Skip to content

Commit

Permalink
Resurrect libunwind patches
Browse files Browse the repository at this point in the history
Fixes #44499
  • Loading branch information
fxcoudert committed May 4, 2022
1 parent 862018b commit 3a6a2d1
Show file tree
Hide file tree
Showing 2 changed files with 362 additions and 0 deletions.
179 changes: 179 additions & 0 deletions deps/patches/llvm-libunwind-force-dwarf.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
An updated version of this libosxunwind commit:

Author: Keno Fischer <kfischer@college.harvard.edu>
Date: Tue Aug 27 15:01:22 2013 -0400

Add option to step with DWARF

---
diff -pur a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
--- a/libunwind/include/libunwind.h 2021-06-28 18:23:38.000000000 +0200
+++ b/libunwind/include/libunwind.h 2022-05-04 18:44:24.000000000 +0200
@@ -108,6 +108,7 @@ extern "C" {

extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL;
extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_init_local_dwarf(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
Only in b/libunwind/include: libunwind.h.orig
diff -pur a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
--- a/libunwind/src/UnwindCursor.hpp 2021-06-28 18:23:38.000000000 +0200
+++ b/libunwind/src/UnwindCursor.hpp 2022-05-04 18:45:11.000000000 +0200
@@ -437,6 +437,9 @@ public:
virtual bool isSignalFrame() {
_LIBUNWIND_ABORT("isSignalFrame not implemented");
}
+ virtual void setForceDWARF(bool) {
+ _LIBUNWIND_ABORT("setForceDWARF not implemented");
+ }
virtual bool getFunctionName(char *, size_t, unw_word_t *) {
_LIBUNWIND_ABORT("getFunctionName not implemented");
}
@@ -894,6 +897,7 @@ public:
virtual void getInfo(unw_proc_info_t *);
virtual void jumpto();
virtual bool isSignalFrame();
+ virtual void setForceDWARF(bool force);
virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
virtual const char *getRegisterName(int num);
@@ -963,7 +967,7 @@ private:
const UnwindInfoSections &sects);
int stepWithCompactEncoding() {
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
- if ( compactSaysUseDwarf() )
+ if ( _forceDwarf || compactSaysUseDwarf() )
return stepWithDwarfFDE();
#endif
R dummy;
@@ -1198,6 +1202,7 @@ private:
unw_proc_info_t _info;
bool _unwindInfoMissing;
bool _isSignalFrame;
+ bool _forceDwarf;
#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
bool _isSigReturn = false;
#endif
@@ -1207,7 +1212,7 @@ private:
template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
: _addressSpace(as), _registers(context), _unwindInfoMissing(false),
- _isSignalFrame(false) {
+ _isSignalFrame(false), _forceDwarf(false) {
static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
"UnwindCursor<> does not fit in unw_cursor_t");
static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
@@ -1217,7 +1222,8 @@ UnwindCursor<A, R>::UnwindCursor(unw_con

template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
- : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+ : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false),
+ _forceDwarf(false) {
memset(&_info, 0, sizeof(_info));
// FIXME
// fill in _registers from thread arg
@@ -1273,6 +1279,10 @@ template <typename A, typename R> bool U
return _isSignalFrame;
}

+template <typename A, typename R> void UnwindCursor<A, R>::setForceDWARF(bool force) {
+ _forceDwarf = force;
+}
+
#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

#if defined(_LIBUNWIND_ARM_EHABI)
@@ -1941,7 +1951,13 @@ void UnwindCursor<A, R>::setInfoBasedOnI
// record that we have no unwind info.
if (_info.format == 0)
_unwindInfoMissing = true;
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+ if (!(_forceDwarf || compactSaysUseDwarf(&dwarfOffset)))
+ return;
+ #else
return;
+ #endif
+
}
}
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
diff -pur a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
--- a/libunwind/src/libunwind.cpp 2021-06-28 18:23:38.000000000 +0200
+++ b/libunwind/src/libunwind.cpp 2022-05-04 18:44:24.000000000 +0200
@@ -71,6 +71,7 @@ _LIBUNWIND_HIDDEN int __unw_init_local(u
new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))
UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
context, LocalAddressSpace::sThisAddressSpace);
+ static_assert(sizeof(unw_cursor_t) >= sizeof(UnwindCursor<LocalAddressSpace,REGISTER_KIND>), "libunwind header outdated");
#undef REGISTER_KIND
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
co->setInfoBasedOnIPRegister();
@@ -79,6 +80,54 @@ _LIBUNWIND_HIDDEN int __unw_init_local(u
}
_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local)

+_LIBUNWIND_HIDDEN int __unw_init_local_dwarf(unw_cursor_t *cursor,
+ unw_context_t *context) {
+ _LIBUNWIND_TRACE_API("__unw_init_local_dwarf(cursor=%p, context=%p)",
+ static_cast<void *>(cursor),
+ static_cast<void *>(context));
+#if defined(__i386__)
+# define REGISTER_KIND Registers_x86
+#elif defined(__x86_64__)
+# define REGISTER_KIND Registers_x86_64
+#elif defined(__powerpc64__)
+# define REGISTER_KIND Registers_ppc64
+#elif defined(__ppc__)
+# define REGISTER_KIND Registers_ppc
+#elif defined(__aarch64__)
+# define REGISTER_KIND Registers_arm64
+#elif defined(__arm__)
+# define REGISTER_KIND Registers_arm
+#elif defined(__or1k__)
+# define REGISTER_KIND Registers_or1k
+#elif defined(__hexagon__)
+# define REGISTER_KIND Registers_hexagon
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+# define REGISTER_KIND Registers_mips_o32
+#elif defined(__mips64)
+# define REGISTER_KIND Registers_mips_newabi
+#elif defined(__mips__)
+# warning The MIPS architecture is not supported with this ABI and environment!
+#elif defined(__sparc__)
+# define REGISTER_KIND Registers_sparc
+#elif defined(__riscv) && __riscv_xlen == 64
+# define REGISTER_KIND Registers_riscv
+#else
+# error Architecture not supported
+#endif
+ // Use "placement new" to allocate UnwindCursor in the cursor buffer.
+ new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))
+ UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
+ context, LocalAddressSpace::sThisAddressSpace);
+ static_assert(sizeof(unw_cursor_t) >= sizeof(UnwindCursor<LocalAddressSpace,REGISTER_KIND>), "libunwind header outdated");
+#undef REGISTER_KIND
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->setForceDWARF(true);
+ co->setInfoBasedOnIPRegister();
+
+ return UNW_ESUCCESS;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_init_local_dwarf, unw_init_local_dwarf)
+
/// Get value of specified register at cursor position in stack frame.
_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_word_t *value) {
diff -pur a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h
--- a/libunwind/src/libunwind_ext.h 2021-06-28 18:23:38.000000000 +0200
+++ b/libunwind/src/libunwind_ext.h 2022-05-04 18:44:24.000000000 +0200
@@ -25,6 +25,7 @@ extern "C" {

extern int __unw_getcontext(unw_context_t *);
extern int __unw_init_local(unw_cursor_t *, unw_context_t *);
+extern int __unw_init_local_dwarf(unw_cursor_t *, unw_context_t *);
extern int __unw_step(unw_cursor_t *);
extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *);
extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
183 changes: 183 additions & 0 deletions deps/patches/llvm-libunwind-prologue-epilogue.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
An updated version of this libosxunwind commit:

commit ca57a5b60de4cd1daa42ed2e5d1d4aa3e96a09d1
Author: Keno Fischer <kfischer@college.harvard.edu>
Date: Mon Aug 26 15:28:08 2013 -0400

Add support for unwinding during prologue/epilogue

---
diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp
index 1c3175dff50a..78a658ccbc27 100644
--- a/libunwind/src/CompactUnwinder.hpp
+++ b/libunwind/src/CompactUnwinder.hpp
@@ -310,6 +310,50 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
uint32_t savedRegistersLocations =
EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);

+ // If we have not stored EBP yet
+ if (functionStart == registers.getIP()) {
+ uint64_t rsp = registers.getSP();
+ // old esp is ebp less return address
+ registers.setSP(rsp+8);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rsp));
+
+ return UNW_STEP_SUCCESS;
+ } else if (functionStart + 1 == registers.getIP()) {
+ uint64_t rsp = registers.getSP();
+ // old esp is ebp less return address
+ registers.setSP(rsp + 16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rsp + 8));
+
+ return UNW_STEP_SUCCESS;
+ }
+
+ // If we're about to return, we've already popped the base pointer
+ uint8_t b = addressSpace.get8(registers.getIP());
+
+ // This is a hack to detect VZEROUPPER but in between popq rbp and ret
+ // It's not pretty but it works
+ if (b == 0xC5) {
+ if ((b = addressSpace.get8(registers.getIP() + 1)) == 0xF8 &&
+ (b = addressSpace.get8(registers.getIP() + 2)) == 0x77)
+ b = addressSpace.get8(registers.getIP() + 3);
+ else
+ goto skip_ret;
+ }
+
+ if (b == 0xC3 || b == 0xCB || b == 0xC2 || b == 0xCA) {
+ uint64_t rbp = registers.getSP();
+ // old esp is ebp less return address
+ registers.setSP(rbp + 16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rbp + 8));
+
+ return UNW_STEP_SUCCESS;
+ }
+
+ skip_ret:
+
uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
for (int i = 0; i < 5; ++i) {
switch (savedRegistersLocations & 0x7) {
@@ -430,6 +474,118 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
}
}
}
+
+ // Note that the order of these registers is so that
+ // registersSaved[0] is the one that will be pushed onto the stack last.
+ // Thus, if we want to walk this from the top, we need to go in reverse.
+ assert(regCount <= 6);
+
+ // check whether we are still in the prologue
+ uint64_t curAddr = functionStart;
+ if (regCount > 0) {
+ for (int8_t i = (int8_t)(regCount) - 1; i >= 0; --i) {
+ if (registers.getIP() == curAddr) {
+ // None of the registers have been modified yet, so we don't need to reload them
+ framelessUnwind(addressSpace, registers.getSP() + 8 * (regCount - (uint64_t)(i + 1)), registers);
+ return UNW_STEP_SUCCESS;
+ } else {
+ assert(curAddr < registers.getIP());
+ }
+
+
+ // pushq %rbp and pushq %rbx is 1 byte. Everything else 2
+ if ((UNWIND_X86_64_REG_RBP == registersSaved[i]) ||
+ (UNWIND_X86_64_REG_RBX == registersSaved[i]))
+ curAddr += 1;
+ else
+ curAddr += 2;
+ }
+ }
+ if (registers.getIP() == curAddr) {
+ // None of the registers have been modified yet, so we don't need to reload them
+ framelessUnwind(addressSpace, registers.getSP() + 8*regCount, registers);
+ return UNW_STEP_SUCCESS;
+ } else {
+ assert(curAddr < registers.getIP());
+ }
+
+
+ // And now for the epilogue
+ {
+ uint8_t i = 0;
+ uint64_t p = registers.getIP();
+ uint8_t b = 0;
+
+ while (true) {
+ b = addressSpace.get8(p++);
+ // This is a hack to detect VZEROUPPER but in between the popq's and ret
+ // It's not pretty but it works
+ if (b == 0xC5) {
+ if ((b = addressSpace.get8(p++)) == 0xF8 && (b = addressSpace.get8(p++)) == 0x77)
+ b = addressSpace.get8(p++);
+ else
+ break;
+ }
+ // popq %rbx popq %rbp
+ if (b == 0x5B || b == 0x5D) {
+ i++;
+ } else if (b == 0x41) {
+ b = addressSpace.get8(p++);
+ if (b == 0x5C || b == 0x5D || b == 0x5E || b == 0x5F)
+ i++;
+ else
+ break;
+ } else if (b == 0xC3 || b == 0xCB || b == 0xC2 || b == 0xCA) {
+ // i pop's haven't happened yet
+ uint64_t savedRegisters = registers.getSP() + 8 * i;
+ if (regCount > 0) {
+ for (int8_t j = (int8_t)(regCount) - 1; j >= (int8_t)(regCount) - i; --j) {
+ uint64_t addr = savedRegisters - 8 * (regCount - (uint64_t)(j));
+ switch (registersSaved[j]) {
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(addr));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(addr));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(addr));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(addr));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(addr));
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ registers.setRBP(addressSpace.get64(addr));
+ break;
+ default:
+ _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+ "function starting at 0x%llX",
+ encoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ }
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /*
+ 0x10fe2733a: 5b popq %rbx
+ 0x10fe2733b: 41 5c popq %r12
+ 0x10fe2733d: 41 5d popq %r13
+ 0x10fe2733f: 41 5e popq %r14
+ 0x10fe27341: 41 5f popq %r15
+ 0x10fe27343: 5d popq %rbp
+ */
+
+
uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
for (uint32_t i = 0; i < regCount; ++i) {
switch (registersSaved[i]) {

0 comments on commit 3a6a2d1

Please sign in to comment.