summaryrefslogtreecommitdiffstats
path: root/libcxxabi/src/Unwind/AddressSpace.hpp
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2015-02-27 22:21:07 +0000
committerDan Albert <danalbert@google.com>2015-02-27 22:21:07 +0000
commit198d366fadaf66fb6b79dea31b51d502b947cccc (patch)
tree17207c11f957aed546d87d44da888f991a8e697f /libcxxabi/src/Unwind/AddressSpace.hpp
parente3959eb54ebf5a2a8997fa79c5d1dd2a1e4eab75 (diff)
downloadbcm5719-llvm-198d366fadaf66fb6b79dea31b51d502b947cccc.tar.gz
bcm5719-llvm-198d366fadaf66fb6b79dea31b51d502b947cccc.zip
Add .eh_frame_hdr search to Linux unwinder.
This improves the performance of unwinding on DWARF based targets. The 32-bit x86 support for scanning the full eh_frame (CFI_Parser::findFDE) apparently does not work (at least not on Linux). Since the eh_frame_hdr code delegates to that, this still doesn't work for x86 Linux, but it has been tested on x86_64 Linux and aarch64 Android. llvm-svn: 230802
Diffstat (limited to 'libcxxabi/src/Unwind/AddressSpace.hpp')
-rw-r--r--libcxxabi/src/Unwind/AddressSpace.hpp80
1 files changed, 74 insertions, 6 deletions
diff --git a/libcxxabi/src/Unwind/AddressSpace.hpp b/libcxxabi/src/Unwind/AddressSpace.hpp
index 960c8f85bb4..f9e64ae5df4 100644
--- a/libcxxabi/src/Unwind/AddressSpace.hpp
+++ b/libcxxabi/src/Unwind/AddressSpace.hpp
@@ -56,6 +56,9 @@ extern EHTEntry __exidx_start;
extern EHTEntry __exidx_end;
#endif // !defined(_LIBUNWIND_IS_BAREMETAL)
+#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#include <link.h>
+#include "EHHeaderParser.hpp"
#endif // LIBCXXABI_ARM_EHABI
namespace libunwind {
@@ -132,7 +135,8 @@ public:
static uint64_t getULEB128(pint_t &addr, pint_t end);
static int64_t getSLEB128(pint_t &addr, pint_t end);
- pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
+ pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+ pint_t datarelBase = 0);
bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
unw_word_t *offset);
bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
@@ -195,9 +199,9 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
return result;
}
-inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
- pint_t end,
- uint8_t encoding) {
+inline LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+ pint_t datarelBase) {
pint_t startAddr = addr;
const uint8_t *p = (uint8_t *)addr;
pint_t result;
@@ -263,7 +267,12 @@ inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
_LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
break;
case DW_EH_PE_datarel:
- _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
+ // default value of 0, and we abort in the event that someone calls this
+ // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
+ if (datarelBase == 0)
+ _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
+ result += datarelBase;
break;
case DW_EH_PE_funcrel:
_LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
@@ -353,6 +362,64 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
info.arm_section, info.arm_section_length);
if (info.arm_section && info.arm_section_length)
return true;
+#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ struct dl_iterate_cb_data {
+ LocalAddressSpace *addressSpace;
+ UnwindInfoSections *sects;
+ uintptr_t targetAddr;
+ };
+
+ dl_iterate_cb_data cb_data = {this, &info, targetAddr};
+ int found = dl_iterate_phdr(
+ [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
+ auto cbdata = static_cast<dl_iterate_cb_data *>(data);
+ size_t object_length;
+ bool found_obj = false;
+ bool found_hdr = false;
+
+ assert(cbdata);
+ assert(cbdata->sects);
+
+ if (cbdata->targetAddr < pinfo->dlpi_addr) {
+ return false;
+ }
+
+ for (ElfW(Half) i = 0; i < pinfo->dlpi_phnum; i++) {
+ const ElfW(Phdr) *phdr = &pinfo->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
+ uintptr_t end = begin + phdr->p_memsz;
+ if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
+ cbdata->sects->dso_base = begin;
+ object_length = phdr->p_memsz;
+ found_obj = true;
+ }
+ } else if (phdr->p_type == PT_GNU_EH_FRAME) {
+ EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+ uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
+ cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
+ cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
+ EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+ *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
+ hdrInfo);
+ cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+ found_hdr = true;
+ }
+ }
+
+ if (found_obj && found_hdr) {
+ cbdata->sects->dwarf_section_length = object_length;
+ return true;
+ } else {
+ return false;
+ }
+ },
+ &cb_data);
+ return static_cast<bool>(found);
+#else
+#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
+#endif
#endif
return false;
@@ -408,7 +475,8 @@ public:
pint_t getP(pint_t addr);
uint64_t getULEB128(pint_t &addr, pint_t end);
int64_t getSLEB128(pint_t &addr, pint_t end);
- pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
+ pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+ pint_t datarelBase = 0);
bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
unw_word_t *offset);
bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
OpenPOWER on IntegriCloud