You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Consider the following async call sequence:
AsyncFunc0_Y called by AsyncFunc1_Q called by AsyncFunc2_Q.
That is, when AsyncFunc0_Y returns, it will return to AsyncFunc1_Q.
Imagine this backtrace:
Frame 0: AsyncFunc1_Q
Frame 1: AsyncFunc2_Q
That is, AsyncFunc0_Y already finished and we are stopped at AsyncFunc1_Q.
One job of the unwinder for a frame is to produce the registers of the
**parent** frame.
For the top frame (AsyncFunc1_Q), we need to produce the x22 register of
AsyncFunc2_Q. This is the value of x22 at the start of AsyncFunc1_Q (we pretend
this register was setup as part of some imaginary function call AsyncFunc2_Q ->
AsyncFunc1_Q).
We use the following async ABI guarantee:
A) Register x22 is saved at (fp - 8) during the prologue of funclets.
As such, the following dwarf expression is used:
*(fp - 8)
Prior to this patch, that dereference was missing.
The other job of the unwinder for a frame is to produce the CFA of that same
frame.
For the top frame (AsyncFunc1_Q) we use the following ABI guarantees:
B) Its register x22 initially points to the async context of AsyncFunc0 ("Q"
funclets are "indirect")
C) Dereferencing the first field of an async context produces the async context
of the continuation funclet.
Combining A), B), and C), the CFA of the top frame (i.e. the async context of
AsyncFunc1) can be obtained with the expression:
**(fp - 8)
Before this patch, the unwinder was missing one dereference.
0 commit comments