summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2017-12-25 17:05:07 +0000
committerwhitequark <whitequark@whitequark.org>2017-12-25 17:05:07 +0000
commit0b964a1ed14cfc93e1c9487f7cf14af8c7bc26ec (patch)
treed0e4f65b7fbbed07d56f160e31b9f8b5d996a2a8
parent5d8a75e3d7badab5f069ced85b35057c9c620991 (diff)
[libunwind] Add proper support for DWARF unwind on bare metal.
Right now, ARM EHABI unwind on bare metal expects to find the symbols __exidx_start and __exidx_end defined, and uses those to locate the EH tables. However, DWARF unwind on bare metal expects to find dl_iterate_phdr, which, although possible to provide, is inconvenient and mildly absurd. This commit provides feature parity with ARM EHABI unwind by looking for symbols __eh_frame_start, __eh_frame_end, __eh_frame_hdr_start and __eh_frame_hdr_end, denoting the start and end of the sections with corresponding names. As far as I know, there is no de jure or de facto ABI providing any such names, so I chose the obvious ones. The .eh_frame_hdr support is optional for maximum flexibility and possible space savings (e.g. if libunwind is only used to provide backtraces when a device crashes, providing the .eh_frame_hdr, which is an index for rapid access to EH tables, would be a waste.) The support for .eh_frame_hdr/DWARF index in the first place is conditional on defined(_LIBUNWIND_SUPPORT_DWARF_INDEX), although right now config.h will always define this macro. The support for DWARF unwind on bare metal has been validated within the ARTIQ environment[1]. [1]: https://m-labs.hk/artiq/ git-svn-id: https://llvm.org/svn/llvm-project/libunwind/trunk@321445 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--src/AddressSpace.hpp46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp
index 2be16af..c9312a4 100644
--- a/src/AddressSpace.hpp
+++ b/src/AddressSpace.hpp
@@ -83,6 +83,38 @@ namespace libunwind {
}
#endif
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+
+// When statically linked on bare-metal, the symbols for the EH table are looked
+// up without going through the dynamic loader.
+
+// The following linker script may be used to produce the necessary sections and symbols.
+// Unless the --eh-frame-hdr linker option is provided, the section is not generated
+// and does not take space in the output file.
+//
+// .eh_frame :
+// {
+// __eh_frame_start = .;
+// KEEP(*(.eh_frame))
+// __eh_frame_end = .;
+// }
+//
+// .eh_frame_hdr :
+// {
+// KEEP(*(.eh_frame_hdr))
+// }
+//
+// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
+// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
+
+extern char __eh_frame_start;
+extern char __eh_frame_end;
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+extern char __eh_frame_hdr_start;
+extern char __eh_frame_hdr_end;
+#endif
+
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
// When statically linked on bare-metal, the symbols for the EH table are looked
@@ -348,6 +380,20 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
return true;
}
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+ // Bare metal is statically linked, so no need to ask the dynamic loader
+ info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
+ info.dwarf_section = (uintptr_t)(&__eh_frame_start);
+ _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x",
+ info.dwarf_section, info.dwarf_section_length);
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+ info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
+ info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
+ _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %X length %x",
+ info.dwarf_index_section, info.dwarf_index_section_length);
+#endif
+ if (info.dwarf_section_length)
+ return true;
#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
// Bare metal is statically linked, so no need to ask the dynamic loader
info.arm_section = (uintptr_t)(&__exidx_start);