[cherry-pick][lldb][swift] Use frame formation as a guide for async unwinding #10687
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This patch changes how the swift language runtime obtains the async context of the currently executing function.
The old strategy consists of querying unwind plans for what they believe the location of the async register is. This proved problematic in cases where the register is not saved directly, e.g. in arm64e, where the register is signed and moved to a scratch register prior to being saved.
The new strategy relies on ABI guarantees: the async context is always saved at the stack slot immediately beneath where FP is saved. As long as a frame has been formed, we can always access the async context by reading memory @ [CFA-24] (FP is saved in [CFA-16]). Before the frame is formed, the async register can be accessed directly.
In other words, the main problem this patch has to solve is detecting the point at which a frame has been fully formed. This is accomplished by scanning the first few Rows of the assembly unwind plan, until a Row is found where FP's location is "AtCFAPlusOffset". The Row immediately after that is used. This is reliable because async prologues follow this pattern in all tested architectures (x86-64, arm64, arm64e):
// 0. adjust sp
// 1. save lr @ CFA-8
// 2. save fp @ CFA-16
// 3. save async_reg @ CFA-24 << "row immediately after"
For frameless functions, we can always use the async register directly.
While this patch adds no tests, all of the existing stepping tests and tests inspecting variables exercise the new behavior.
(cherry picked from commit d1ac271)