summaryrefslogtreecommitdiff
path: root/src/x86_64
diff options
context:
space:
mode:
authorKeno Fischer <keno@juliacomputing.com>2021-08-29 11:07:54 -0700
committerDave Watson <dade.watson@gmail.com>2021-11-26 08:50:31 -0800
commit400b3f819ad44ff4e15487b163cc3613389cb4c8 (patch)
tree5929714208ce379d64c82cc9a770e9a18417424c /src/x86_64
parent971989687f9cf46d9d7f95df593657e455d96493 (diff)
downloadlibunwind-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.c1
-rw-r--r--src/x86_64/Gregs.c2
-rw-r--r--src/x86_64/Gstep.c2
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",