forked from OSchip/llvm-project
[libunwind] Combine dl_iterate_phdr codepaths for DWARF and EHABI
dl_iterate_phdr is used to search for unwind info provided by either PT_GNU_EH_FRAME or PT_ARM_EXIDX. Most of the code between the two is the same, so combine them, and factor out what's different into checkForUnwindInfoSegment. Details: - The FrameHeaderCache can now be enabled for ARM EHABI. - findUnwindSectionsByPhdr now finds the last PT_ARM_EXIDX rather than the first. There should only be one segment. - The dso_base and text_segment_length fields of UnwindInfoSections are now needed for dl_iterate_phdr when using EHABI, to hold the low and high PC values for a cache entry. Reviewed By: compnerd, danielkiss, #libunwind, saugustine Differential Revision: https://reviews.llvm.org/D87880
This commit is contained in:
parent
38de1c33a8
commit
b16d6653c0
|
@ -114,13 +114,13 @@ namespace libunwind {
|
|||
|
||||
/// Used by findUnwindSections() to return info about needed sections.
|
||||
struct UnwindInfoSections {
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
|
||||
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||
// No dso_base for SEH or ARM EHABI.
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
|
||||
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
|
||||
defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||
// No dso_base for SEH.
|
||||
uintptr_t dso_base;
|
||||
#endif
|
||||
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \
|
||||
defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||
uintptr_t text_segment_length;
|
||||
#endif
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
|
@ -394,11 +394,6 @@ struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
|
|||
uintptr_t targetAddr;
|
||||
};
|
||||
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||
#if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
|
||||
#include "FrameHeaderCache.hpp"
|
||||
|
||||
|
@ -421,6 +416,38 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
|
||||
dl_iterate_cb_data *cbdata) {
|
||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||
if (phdr->p_type == PT_GNU_EH_FRAME) {
|
||||
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
|
||||
uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
|
||||
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
|
||||
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
|
||||
if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
||||
hdrInfo)) {
|
||||
// .eh_frame_hdr records the start of .eh_frame, but not its size.
|
||||
// Rely on a zero terminator to find the end of the section.
|
||||
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
|
||||
cbdata->sects->dwarf_section_length = UINTPTR_MAX;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI)
|
||||
if (phdr->p_type == PT_ARM_EXIDX) {
|
||||
uintptr_t exidx_start = image_base + phdr->p_vaddr;
|
||||
cbdata->sects->arm_section = exidx_start;
|
||||
cbdata->sects->arm_section_length = phdr->p_memsz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
|
||||
#endif
|
||||
}
|
||||
|
||||
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
||||
size_t pinfo_size, void *data) {
|
||||
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||
|
@ -435,35 +462,22 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
|||
#endif
|
||||
|
||||
Elf_Addr image_base = calculateImageBase(pinfo);
|
||||
bool found_obj = false;
|
||||
bool found_hdr = false;
|
||||
bool found_text = false;
|
||||
bool found_unwind = false;
|
||||
|
||||
// Third phdr is usually the executable phdr.
|
||||
if (pinfo->dlpi_phnum > 2)
|
||||
found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
|
||||
found_text = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
|
||||
|
||||
// PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
|
||||
// that there is one or more phdrs.
|
||||
// PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
|
||||
// backward. We already know that there is one or more phdrs.
|
||||
for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
|
||||
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
|
||||
if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
|
||||
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
|
||||
uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
|
||||
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
|
||||
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
|
||||
found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
|
||||
*cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
|
||||
hdrInfo);
|
||||
if (found_hdr) {
|
||||
// .eh_frame_hdr records the start of .eh_frame, but not its size.
|
||||
// Rely on a zero terminator to find the end of the section.
|
||||
cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
|
||||
cbdata->sects->dwarf_section_length = UINTPTR_MAX;
|
||||
}
|
||||
} else if (!found_obj) {
|
||||
found_obj = checkAddrInSegment(phdr, image_base, cbdata);
|
||||
}
|
||||
if (found_obj && found_hdr) {
|
||||
if (!found_unwind && checkForUnwindInfoSegment(phdr, image_base, cbdata))
|
||||
found_unwind = true;
|
||||
else if (!found_text && checkAddrInSegment(phdr, image_base, cbdata))
|
||||
found_text = true;
|
||||
if (found_text && found_unwind) {
|
||||
#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
|
||||
TheFrameHeaderCache.add(cbdata->sects);
|
||||
#endif
|
||||
|
@ -473,40 +487,6 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(_LIBUNWIND_ARM_EHABI)
|
||||
|
||||
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t,
|
||||
void *data) {
|
||||
auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||
bool found_obj = false;
|
||||
bool found_hdr = false;
|
||||
|
||||
assert(cbdata);
|
||||
assert(cbdata->sects);
|
||||
|
||||
if (cbdata->targetAddr < pinfo->dlpi_addr)
|
||||
return 0;
|
||||
|
||||
Elf_Addr image_base = calculateImageBase(pinfo);
|
||||
|
||||
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
|
||||
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
uintptr_t begin = image_base + phdr->p_vaddr;
|
||||
uintptr_t end = begin + phdr->p_memsz;
|
||||
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
|
||||
found_obj = true;
|
||||
} else if (phdr->p_type == PT_ARM_EXIDX) {
|
||||
uintptr_t exidx_start = image_base + phdr->p_vaddr;
|
||||
cbdata->sects->arm_section = exidx_start;
|
||||
cbdata->sects->arm_section_length = phdr->p_memsz;
|
||||
found_hdr = true;
|
||||
}
|
||||
}
|
||||
return found_obj && found_hdr;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
// Only run this test under supported configurations.
|
||||
|
||||
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \
|
||||
defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) && \
|
||||
defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
|
||||
|
||||
#include <link.h>
|
||||
|
|
Loading…
Reference in New Issue