Skip to content

Commit

Permalink
Fix misunwind during Profile test under rr (JuliaLang#39553)
Browse files Browse the repository at this point in the history
Libunwind improperly aliases RSP and CFA, which are separate concepts.
Fix that.
  • Loading branch information
Keno authored and antoine-levitt committed May 9, 2021
1 parent fa99b76 commit cac1f0d
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 25 deletions.
1 change: 1 addition & 0 deletions deps/Versions.make
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ SUITESPARSE_JLL_NAME := SuiteSparse
# unwind
UNWIND_VER := 1.3.2
UNWIND_JLL_NAME := LibUnwind
UNWIND_JLL_VER := 1.3.2+3

# zlib
ZLIB_VER := 1.2.11
Expand Down
48 changes: 24 additions & 24 deletions deps/checksums/unwind
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
LibOSXUnwind.v0.0.6+1.x86_64-apple-darwin.tar.gz/md5/fd98df2005d13aa16341c5aecba1af70
LibOSXUnwind.v0.0.6+1.x86_64-apple-darwin.tar.gz/sha512/2d2263c3e5f095ad9eba7fea7cb882a19fece8a10486489d0a15b8e81ea0f8626804c4822b8c92a26a608d568c0ff1a4e976ea6d746be47ac1a70891455162a6
LibUnwind.v1.3.2+0.aarch64-linux-gnu.tar.gz/md5/36281b8ba75cab684c843585dc949b72
LibUnwind.v1.3.2+0.aarch64-linux-gnu.tar.gz/sha512/7f5224fe3bfd9dd579fa2efb40b65ca785da3f7ddee1bd41e072f7f5be1ce8fa24c2eab71a1233406ce532ba9f900d1f0e288f84631684b3cbc8a0f3a8347e41
LibUnwind.v1.3.2+0.aarch64-linux-musl.tar.gz/md5/ba21435b80f4f50fbb13cf4653e3fac3
LibUnwind.v1.3.2+0.aarch64-linux-musl.tar.gz/sha512/25cfe1f1cbfe2b9ee748348e2b0df0fba3607dedbcf88f864e88a15544bfe0781de502157353915b62387abdb467c40e51b08e847f0d2cc096a3d2d13f061559
LibUnwind.v1.3.2+0.armv6l-linux-gnueabihf.tar.gz/md5/81fc18e166b8de9de171ca202ee43816
LibUnwind.v1.3.2+0.armv6l-linux-gnueabihf.tar.gz/sha512/e41f0224d79dc5725b327ad7f24eb09aef0fc687842d43eecc8ac60c4dcdc1d2877d45c88015d0e32014f8bef38712f540c27093d135dd0bc7e7eafb6bd64b18
LibUnwind.v1.3.2+0.armv6l-linux-musleabihf.tar.gz/md5/69da77d1e7124dee0c60d4fc15cf0040
LibUnwind.v1.3.2+0.armv6l-linux-musleabihf.tar.gz/sha512/a1c6d70971a7375c26ce761039f06a940db140b06028534557f3b608363af0da9d7ef570d5f3b388f84d9649d378293bb6b59d44cf34ebf24f0a260a6824f142
LibUnwind.v1.3.2+0.armv7l-linux-gnueabihf.tar.gz/md5/b7a6b251f30cd6d1fc890a8be4a19476
LibUnwind.v1.3.2+0.armv7l-linux-gnueabihf.tar.gz/sha512/d143588edb96b31de4d1347ddc867e5982ccee8a39a35f705114f6fa12aca054f14a05a24ca0850be26c62a92a4c52837e898765b3fa8fa6e5259e45eebbe281
LibUnwind.v1.3.2+0.armv7l-linux-musleabihf.tar.gz/md5/bdfa9757e7631387cb64f3897e1847fc
LibUnwind.v1.3.2+0.armv7l-linux-musleabihf.tar.gz/sha512/54f8529bb836cddff61e0112294ae3165eb6498b0c881b59047a40e180785f63c01e4ad82bcffb045b783e015c255c7b0e2f8ec43411ff647f860ef25551f540
LibUnwind.v1.3.2+0.i686-linux-gnu.tar.gz/md5/17b1c29c3387dc3b685e75ce402caad6
LibUnwind.v1.3.2+0.i686-linux-gnu.tar.gz/sha512/e8551b4771acf7eb31fc5db3423905b17c545aa0895b5e5369c56186841631f188186e585f0384cfca62269e1b2fffe9d9b24274d51e1ccad9bc89c3dbf6072b
LibUnwind.v1.3.2+0.i686-linux-musl.tar.gz/md5/df7e34217c1dc931c88e573179218cf6
LibUnwind.v1.3.2+0.i686-linux-musl.tar.gz/sha512/995318e65520eae55647b2d1065f5ac5bb15cdf7b4980000b17338c59e1657e408ba711c622b450df96712a5c1c75c85c03d7952a1fd7f0b65712fa9ac6ffbab
LibUnwind.v1.3.2+0.powerpc64le-linux-gnu.tar.gz/md5/775e9c77ff9de48d40b2a2f18e5f081e
LibUnwind.v1.3.2+0.powerpc64le-linux-gnu.tar.gz/sha512/3f4d12ba171227c11ad0e774e003742c1cd69d7e0e8ae571accea561ff930ae6aec119fc8b539caf52960886cde3978912e03d663aa7fb6416978e304767dde8
LibUnwind.v1.3.2+0.x86_64-linux-gnu.tar.gz/md5/d63ca2bc34d4bc87498d28b47e530f54
LibUnwind.v1.3.2+0.x86_64-linux-gnu.tar.gz/sha512/2e95d1648414fa9bccf6012a9f6690cf3c209dbb138bf59da76be538793c5caca319eed3b063f18725212844e21bd67157da2aec49ec9424e38664c23dde9f45
LibUnwind.v1.3.2+0.x86_64-linux-musl.tar.gz/md5/56a9c951e75e38bf5787c928862924cf
LibUnwind.v1.3.2+0.x86_64-linux-musl.tar.gz/sha512/8ea0c4d0e412a3792c6d33fe6dab6ae9f4c4103341842e42a9ae7efcb31c29d977970caa383373c6694d6cd8736ce75c727fa2af8f59bc3eff8d8f93ac0b9c89
LibUnwind.v1.3.2+0.x86_64-unknown-freebsd.tar.gz/md5/10507e55604be0137c4531b5e35fbafc
LibUnwind.v1.3.2+0.x86_64-unknown-freebsd.tar.gz/sha512/a795c02b48a3b44d6b7df0b07ed31f44c3c1e189b0732a5a41ce6f2eac952da4cc376eefab17c283a20a84aae4c3dc6618e58ca86003390b4ab396d085fa83c4
LibUnwind.v1.3.2+3.aarch64-linux-gnu.tar.gz/md5/fba1f405a3a7c8bc4f68c17d771100b0
LibUnwind.v1.3.2+3.aarch64-linux-gnu.tar.gz/sha512/a37d3f9da9a133bb270cc1046c7018579731897fed0ef6ab1fbeb0dde38e7be294a4e2abf41096c7edde617e266f1acc95777b34e22b6a8ced0e27b2228b0ec5
LibUnwind.v1.3.2+3.aarch64-linux-musl.tar.gz/md5/587de98245251124c0d29b0b478374ec
LibUnwind.v1.3.2+3.aarch64-linux-musl.tar.gz/sha512/9f10eee8e4f5117dfc4689378c93ba16e205aaa89eec5681e0b1e34e7c2d334717b327cae8d5024db6a1f6a2633454cb77b577112a0a03a3282e566705c1a81e
LibUnwind.v1.3.2+3.armv6l-linux-gnueabihf.tar.gz/md5/953bfa931cb8e44d39ae22d7ccab1f22
LibUnwind.v1.3.2+3.armv6l-linux-gnueabihf.tar.gz/sha512/54ee57c35895cbaed2160d451ca33ac9e8adf157b7f825853f7e92f8304f799f2671f5361dae7d2e7d111a3ab1f749cddb96a2c04b7b8fc7844b1e021dbc443f
LibUnwind.v1.3.2+3.armv6l-linux-musleabihf.tar.gz/md5/5d16fd194ec5a7e46e1e1679072cec0f
LibUnwind.v1.3.2+3.armv6l-linux-musleabihf.tar.gz/sha512/1ae68a77eadaf73de9de266bb3e2f61457faae6b2f971988363d2d1bebf855bdbc55ad848266335a9b3c040308e0bd3e3b66d5b66fe8807e0fb774c22bac928d
LibUnwind.v1.3.2+3.armv7l-linux-gnueabihf.tar.gz/md5/569da138256de02784ba81b01e08a3db
LibUnwind.v1.3.2+3.armv7l-linux-gnueabihf.tar.gz/sha512/264636b57ca49feb005752636671fe1c24264b15d1caca0c0808e89966a7683e7821a56e41b89cde9e32b688cf94647ae61de74f0428b7b1f92be2bed6674114
LibUnwind.v1.3.2+3.armv7l-linux-musleabihf.tar.gz/md5/c9d2f634a742d71e471dd7ff691bf39d
LibUnwind.v1.3.2+3.armv7l-linux-musleabihf.tar.gz/sha512/01c2085d49390ace5c128507a86d23b99d746cce080cc7b6415e1c75e63082d01b047b2cf98f3f76768fb49423c5524f53d253858d82864f09e8182a86be57ad
LibUnwind.v1.3.2+3.i686-linux-gnu.tar.gz/md5/92e075574e65c735f6202cc49ec51593
LibUnwind.v1.3.2+3.i686-linux-gnu.tar.gz/sha512/03f9a71b1b1b0752a835201248cdb2d17f076a82b0928e20f45fc2b8db0914128028c0d589ff94a97847265c216420240b2369af83c4a343d3ca37c58fdcf35a
LibUnwind.v1.3.2+3.i686-linux-musl.tar.gz/md5/fa506359a72ffdf2c3713b5724ad4413
LibUnwind.v1.3.2+3.i686-linux-musl.tar.gz/sha512/0558e871e838e6ce265c73fd7335bd0a486722ce9a710957b2e67731c494c5781a3a37176ba758f74fee37d48ee43acf02aac5092e24230523dd537610b58720
LibUnwind.v1.3.2+3.powerpc64le-linux-gnu.tar.gz/md5/3f76849a52550e169d6f47ef95ca3d75
LibUnwind.v1.3.2+3.powerpc64le-linux-gnu.tar.gz/sha512/2f3a119ccf1fffa8460e2350b66bf2303d11d636e649e144750e362d2e08f61d076adda71b5441b4337eaee6fb1e95049aac87de89be1415ca80f1b69c77f310
LibUnwind.v1.3.2+3.x86_64-linux-gnu.tar.gz/md5/624779c4bc930ae2ba5f6a5d25c73aeb
LibUnwind.v1.3.2+3.x86_64-linux-gnu.tar.gz/sha512/2eb467537e5f2acee7d5b2a5939c712ca96195584c37606d1ff1bcc0683514decefcae042f566633905472c177115c1467c1503bf331d8d7293b3026628bc138
LibUnwind.v1.3.2+3.x86_64-linux-musl.tar.gz/md5/7ddcbe93c8bdb1edde0ffab23db3ced7
LibUnwind.v1.3.2+3.x86_64-linux-musl.tar.gz/sha512/06901d074c15c34002957122897b6b9c449f9c64745363f6fe2886c862197cc6848ca17c3d777eac315fd1d8d90fe236a223167b0aa9fd3b625fd80e3db97655
LibUnwind.v1.3.2+3.x86_64-unknown-freebsd.tar.gz/md5/ca388d44a8ca365b66999e4b4d1853a2
LibUnwind.v1.3.2+3.x86_64-unknown-freebsd.tar.gz/sha512/dfbe0a6b5835b51ebea181bb996ffc8fcd8b08acf71243e171c59edb655fd65b6ba59291c10af923f75b7cbb2f52b46adf65ebdca3eee172d279ae357a35205c
177 changes: 177 additions & 0 deletions deps/patches/libunwind-rsp-cfa.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
commit 66f68ab50d35bb17a7ae3ac47f17e1ba5913760c
Author: Keno Fischer <keno@juliacomputing.com>
Date: Sat Feb 6 18:13:16 2021 -0500

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

diff --git a/include/dwarf.h b/include/dwarf.h
index fab93c61..b845e2eb 100644
--- a/include/dwarf.h
+++ b/include/dwarf.h
@@ -227,6 +227,7 @@ typedef enum
DWARF_WHERE_REG, /* register saved in another register */
DWARF_WHERE_EXPR, /* register saved */
DWARF_WHERE_VAL_EXPR, /* register has computed value */
+ DWARF_WHERE_CFA, /* register is set to the computed cfa value */
}
dwarf_where_t;

@@ -309,7 +310,7 @@ typedef struct dwarf_cursor
void *as_arg; /* argument to address-space callbacks */
unw_addr_space_t as; /* reference to per-address-space info */

- unw_word_t cfa; /* canonical frame address; aka frame-/stack-pointer */
+ unw_word_t cfa; /* canonical frame address; aka frame-pointer */
unw_word_t ip; /* instruction pointer */
unw_word_t args_size; /* size of arguments */
unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS];
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 7d255aee..986c4a89 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -500,6 +500,8 @@ setup_fde (struct dwarf_cursor *c, dwarf_state_record_t *sr)
memset (sr, 0, sizeof (*sr));
for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
set_reg (sr, i, DWARF_WHERE_SAME, 0);
+ // SP defaults to CFA (but is overridable)
+ set_reg (sr, UNW_TDEP_SP, DWARF_WHERE_CFA, 0);

struct dwarf_cie_info *dci = c->pi.unwind_info;
sr->rs_current.ret_addr_column = dci->ret_addr_column;
@@ -826,6 +828,10 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
case DWARF_WHERE_SAME:
break;

+ case DWARF_WHERE_CFA:
+ new_loc[i] = DWARF_VAL_LOC (c, cfa);
+ break;
+
case DWARF_WHERE_CFAREL:
new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]);
break;
diff --git a/src/x86/Gos-freebsd.c b/src/x86/Gos-freebsd.c
index 7dd01404..1b251d02 100644
--- a/src/x86/Gos-freebsd.c
+++ b/src/x86/Gos-freebsd.c
@@ -138,6 +138,7 @@ x86_handle_signal_frame (unw_cursor_t *cursor)
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
} else if (c->sigcontext_format == X86_SCF_FREEBSD_SYSCALL) {
c->dwarf.loc[EIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.loc[ESP] = DWARF_VAL_LOC (c, c->dwarf.cfa + 4);
c->dwarf.loc[EAX] = DWARF_NULL_LOC;
c->dwarf.cfa += 4;
c->dwarf.use_prev_instr = 1;
diff --git a/src/x86/Gregs.c b/src/x86/Gregs.c
index 4a959261..9446d6c6 100644
--- a/src/x86/Gregs.c
+++ b/src/x86/Gregs.c
@@ -53,7 +53,6 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
break;

case UNW_X86_CFA:
- case UNW_X86_ESP:
if (write)
return -UNW_EREADONLYREG;
*valp = c->dwarf.cfa;
@@ -81,6 +80,7 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
case UNW_X86_ECX: loc = c->dwarf.loc[ECX]; break;
case UNW_X86_EBX: loc = c->dwarf.loc[EBX]; break;

+ case UNW_X86_ESP: loc = c->dwarf.loc[ESP]; break;
case UNW_X86_EBP: loc = c->dwarf.loc[EBP]; break;
case UNW_X86_ESI: loc = c->dwarf.loc[ESI]; break;
case UNW_X86_EDI: loc = c->dwarf.loc[EDI]; break;
diff --git a/src/x86/Gstep.c b/src/x86/Gstep.c
index 129b739a..061dcbaa 100644
--- a/src/x86/Gstep.c
+++ b/src/x86/Gstep.c
@@ -47,7 +47,7 @@ unw_step (unw_cursor_t *cursor)
{
/* DWARF failed, let's see if we can follow the frame-chain
or skip over the signal trampoline. */
- struct dwarf_loc ebp_loc, eip_loc;
+ struct dwarf_loc ebp_loc, eip_loc, esp_loc;

/* We could get here because of missing/bad unwind information.
Validate all addresses before dereferencing. */
@@ -77,6 +77,7 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.cfa);

ebp_loc = DWARF_LOC (c->dwarf.cfa, 0);
+ esp_loc = DWARF_VAL_LOC (c, c->dwarf.cfa + 8);
eip_loc = DWARF_LOC (c->dwarf.cfa + 4, 0);
c->dwarf.cfa += 8;

@@ -87,6 +88,7 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.loc[i] = DWARF_NULL_LOC;

c->dwarf.loc[EBP] = ebp_loc;
+ c->dwarf.loc[ESP] = esp_loc;
c->dwarf.loc[EIP] = eip_loc;
c->dwarf.use_prev_instr = 1;
}
diff --git a/src/x86_64/Gos-freebsd.c b/src/x86_64/Gos-freebsd.c
index 883025c8..8bb101ea 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 10498170..5425e3db 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -160,7 +160,7 @@ unw_step (unw_cursor_t *cursor)
{
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",
6 changes: 5 additions & 1 deletion deps/unwind.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ $(SRCCACHE)/libunwind-$(UNWIND_VER)/libunwind-static-arm.patch-applied: $(SRCCAC
cd $(SRCCACHE)/libunwind-$(UNWIND_VER) && patch -p1 -f < $(SRCDIR)/patches/libunwind-static-arm.patch
echo 1 > $@

$(BUILDDIR)/libunwind-$(UNWIND_VER)/build-configured: $(SRCCACHE)/libunwind-$(UNWIND_VER)/source-extracted $(SRCCACHE)/libunwind-$(UNWIND_VER)/libunwind-static-arm.patch-applied
$(SRCCACHE)/libunwind-$(UNWIND_VER)/libunwind-rsp-cfa.patch-applied: $(SRCCACHE)/libunwind-$(UNWIND_VER)/libunwind-static-arm.patch-applied
cd $(SRCCACHE)/libunwind-$(UNWIND_VER) && patch -p1 -f -u < $(SRCDIR)/patches/libunwind-rsp-cfa.patch
echo 1 > $@

$(BUILDDIR)/libunwind-$(UNWIND_VER)/build-configured: $(SRCCACHE)/libunwind-$(UNWIND_VER)/source-extracted $(SRCCACHE)/libunwind-$(UNWIND_VER)/libunwind-rsp-cfa.patch-applied
mkdir -p $(dir $@)
cd $(dir $@) && \
$(dir $<)/configure $(CONFIGURE_COMMON) CPPFLAGS="$(CPPFLAGS) $(LIBUNWIND_CPPFLAGS)" CFLAGS="$(CFLAGS) $(LIBUNWIND_CFLAGS)" --enable-shared --disable-minidebuginfo --disable-tests
Expand Down

0 comments on commit cac1f0d

Please sign in to comment.