diff options
author | Keno Fischer <keno@juliacomputing.com> | 2021-08-29 11:07:54 -0700 |
---|---|---|
committer | Dave Watson <dade.watson@gmail.com> | 2021-11-26 08:50:31 -0800 |
commit | 400b3f819ad44ff4e15487b163cc3613389cb4c8 (patch) | |
tree | 5929714208ce379d64c82cc9a770e9a18417424c /src/x86_64 | |
parent | 971989687f9cf46d9d7f95df593657e455d96493 (diff) | |
download | libunwind-400b3f819ad44ff4e15487b163cc3613389cb4c8.tar.gz |
x86_64: Stop aliasing RSP and CFA
RSP and CFA are different concepts. RSP refers to the physical
register, CFA is a virtual register that serves as the base
address for various other saved registers. It is true that
in many frames these are set to alias, however this is not
a requirement. For example, a function that performs a stack
switch would likely change the rsp in the middle of the function,
but would keep the CFA at the original RSP such that saved registers
may be appropriately recovered.
We are seeing incorrect unwinds in the Julia runtime when running
julia under rr. This is because injects code (with correct CFI)
that performs just such a stack switch [1]. GDB manages to unwind
this correctly, but libunwind incorrectly sets the rsp to the CFA
address, causing a misunwind.
Tested on x86_64, patches for other architectures are ported, but
not tested.
[1] https://github.com/rr-debugger/rr/blob/469c22059a4a1798d33a8a224457faf22b2c178c/src/preload/syscall_hook.S#L454
Diffstat (limited to 'src/x86_64')
-rw-r--r-- | src/x86_64/Gos-freebsd.c | 1 | ||||
-rw-r--r-- | src/x86_64/Gregs.c | 2 | ||||
-rw-r--r-- | src/x86_64/Gstep.c | 2 |
3 files changed, 3 insertions, 2 deletions
diff --git a/src/x86_64/Gos-freebsd.c b/src/x86_64/Gos-freebsd.c index 91a465c6..aa6a4b43 100644 --- a/src/x86_64/Gos-freebsd.c +++ b/src/x86_64/Gos-freebsd.c @@ -133,6 +133,7 @@ x86_64_handle_signal_frame (unw_cursor_t *cursor) c->dwarf.loc[RCX] = c->dwarf.loc[R10]; /* rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0); */ /* rbp_loc = c->dwarf.loc[RBP]; */ + c->dwarf.loc[RSP] = DWARF_VAL_LOC (c, c->dwarf.cfa + 8); c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", diff --git a/src/x86_64/Gregs.c b/src/x86_64/Gregs.c index baf8a24f..dff5bcbe 100644 --- a/src/x86_64/Gregs.c +++ b/src/x86_64/Gregs.c @@ -79,7 +79,6 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, break; case UNW_X86_64_CFA: - case UNW_X86_64_RSP: if (write) return -UNW_EREADONLYREG; *valp = c->dwarf.cfa; @@ -107,6 +106,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, case UNW_X86_64_RCX: loc = c->dwarf.loc[RCX]; break; case UNW_X86_64_RBX: loc = c->dwarf.loc[RBX]; break; + case UNW_X86_64_RSP: loc = c->dwarf.loc[RSP]; break; case UNW_X86_64_RBP: loc = c->dwarf.loc[RBP]; break; case UNW_X86_64_RSI: loc = c->dwarf.loc[RSI]; break; case UNW_X86_64_RDI: loc = c->dwarf.loc[RDI]; break; diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 3c5c3830..fdad298c 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -223,7 +223,7 @@ unw_step (unw_cursor_t *cursor) Debug (2, "RIP fixup didn't work, falling back\n"); unw_word_t rbp1 = 0; rbp_loc = DWARF_LOC(rbp, 0); - rsp_loc = DWARF_NULL_LOC; + rsp_loc = DWARF_VAL_LOC(c, rbp + 16); rip_loc = DWARF_LOC (rbp + 8, 0); ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1); Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n", |