Skip to content

Conversation

@felipepiovezan
Copy link

@felipepiovezan felipepiovezan commented Jul 29, 2024

This series of patches aims to solve the problem where LLDB is unable to print variables in backtraces involving swift async functions. The only frame where this works today is the first async frame, which is a real frame and is physically on the stack. We fail to do so for all virtual frames.

The underlying problem is simple: when unwinding the PC, we use the first instruction of the continuation funclets. This instruction is part of the prologue, where no variables are in scope.

The solution is similarly simple: we just offset the PC by the size of the prologue of the continuation funclet.

These commits are meant to be reviewed independently, please the commit messages too.

The first commit is a cherry-pick from: llvm#100624

@felipepiovezan
Copy link
Author

felipepiovezan commented Jul 29, 2024

Requires: swiftlang/swift#75553
edit: no longer true, reworked to remove the Q funclet fixes

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lldb functions start with an Upper case letter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the new version

@felipepiovezan felipepiovezan force-pushed the felipe/unwinding_pc_patches_to_release branch from 9964bc1 to 317e4a6 Compare July 30, 2024 15:21

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

///

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. Yes, it's 128-8, but sleb128 is a variable-length encoding, so I'm confused.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also understand this is not new in your patch.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate? -8 is 0x78 in sleb128 encoding, and it takes a single byte to represent it.
The comment is explaining where the magic 0x78 comes from.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a doxygen comment on the declaration.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a generic name for x22 (since this is arch specific?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context_reg or some thing like that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling is "async_reg" to match other comments in this file which refer to it as "asynchronous register"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should comment that this is true on all ABIs, otherwise this screams for being an ABI callback.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the missing detail to this comment that explains why the indirection follows from it being a virtual frame?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reworded this entire paragraph to remove this part of the explanation that requires a lot of background information.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get this from process?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Target &target = process.GetTarget(); ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@felipepiovezan felipepiovezan force-pushed the felipe/unwinding_pc_patches_to_release branch from 317e4a6 to 1aa6a85 Compare July 30, 2024 20:18
Copy link
Author

@felipepiovezan felipepiovezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address review comments

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate? -8 is 0x78 in sleb128 encoding, and it takes a single byte to represent it.
The comment is explaining where the magic 0x78 comes from.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling is "async_reg" to match other comments in this file which refer to it as "asynchronous register"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reworded this entire paragraph to remove this part of the explanation that requires a lot of background information.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

This will enable subsequent commits to introduce calls to other member functions
from that method.
@felipepiovezan felipepiovezan force-pushed the felipe/unwinding_pc_patches_to_release branch from 1aa6a85 to 8e0cfd2 Compare July 31, 2024 17:51
@felipepiovezan felipepiovezan changed the base branch from stable/20230725 to swift/release/6.0 July 31, 2024 17:52
@felipepiovezan
Copy link
Author

Removed the last two commits, which dealt with Q funclets as frame 0 and required compiler changes.
This PR no longer needs any compiler changes, going to propose it for the 6.0 branch

@felipepiovezan felipepiovezan marked this pull request as ready for review July 31, 2024 18:16
@felipepiovezan
Copy link
Author

@swift-ci test


// Compute the CFA of this frame.
addr_t cfa = async_reg_val;
while (num_indirections--) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that this underflows on the last iteration bothers me a bit.
for (; num_indirections != 0; --num_indirections) ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, good catch!


func ASYNC___2___() async -> Int {
var myvar = 222;
let result = await ASYNC___1___() //breakpoint1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// breakpoint1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Variables are never available in the prologue of a function. By unwinding the pc
of the virtual frames as the first instruction of the continuation function,
LLDB is unable to display any variable information.

This patch addresses the issue by computing the continuation pointer from the
context of the function being unwound, and then querying the continuation's
SymbolContext to determine its prologue size.
@felipepiovezan felipepiovezan force-pushed the felipe/unwinding_pc_patches_to_release branch from 8e0cfd2 to 85069c8 Compare July 31, 2024 20:55
Copy link
Author

@felipepiovezan felipepiovezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed review comments


func ASYNC___2___() async -> Int {
var myvar = 222;
let result = await ASYNC___1___() //breakpoint1
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


// Compute the CFA of this frame.
addr_t cfa = async_reg_val;
while (num_indirections--) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, good catch!

@felipepiovezan
Copy link
Author

@swift-ci test

@felipepiovezan
Copy link
Author

@swift-ci test platform windows

@felipepiovezan
Copy link
Author

@swift-ci test windows platform

@felipepiovezan
Copy link
Author

@swift-ci test windows platform

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants