Skip to content

Commit

Permalink
Fix source build (CLR_CMAKE_USE_SYSTEM_LIBUNWIND=TRUE) (#39391)
Browse files Browse the repository at this point in the history
Fixes issue ##2014

Adds back ELF unwind info parsing code that has been around since 3.0 so it is fairly well tested. It is conditional on CLR_CMAKE_USE_SYSTEM_LIBUNWIND, otherwise, PAL_VirtualUnwindOutOfProc uses the new libunwind8 _OOP_find_proc_info function.
  • Loading branch information
mikem8361 authored Jul 16, 2020
1 parent 0554117 commit bf2e135
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/coreclr/src/pal/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ include_directories(include)

# Compile options

if(CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
add_definitions(-DFEATURE_USE_SYSTEM_LIBUNWIND)
endif(CLR_CMAKE_USE_SYSTEM_LIBUNWIND)

if(CLR_CMAKE_TARGET_OSX)
add_definitions(-DTARGET_OSX)
add_definitions(-DXSTATE_SUPPORTED)
Expand Down
123 changes: 118 additions & 5 deletions src/coreclr/src/pal/src/exception/remote-unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size

#endif // HOST_UNIX

#if defined(HAVE_UNW_GET_ACCESSORS)
#ifdef HAVE_UNW_GET_ACCESSORS

#ifdef HOST_UNIX
#include <link.h>
Expand Down Expand Up @@ -135,6 +135,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size
#define Nhdr ElfW(Nhdr)
#define Dyn ElfW(Dyn)

#ifndef FEATURE_USE_SYSTEM_LIBUNWIND
extern "C" int
_OOP_find_proc_info(
unw_word_t start_ip,
Expand All @@ -148,10 +149,11 @@ _OOP_find_proc_info(
unw_proc_info_t *pi,
int need_unwind_info,
void *arg);
#endif // FEATURE_USE_SYSTEM_LIBUNWIND

#endif // HAVE_UNW_GET_ACCESSORS

#if defined(HAVE_UNW_GET_ACCESSORS) || defined(__APPLE__)
#if defined(__APPLE__) || defined(HAVE_UNW_GET_ACCESSORS)

typedef struct _libunwindInfo
{
Expand All @@ -160,9 +162,11 @@ typedef struct _libunwindInfo
UnwindReadMemoryCallback ReadMemory;
} libunwindInfo;

#ifdef __APPLE__
#if defined(__APPLE__) || defined(FEATURE_USE_SYSTEM_LIBUNWIND)

#define EXTRACT_BITS(value, mask) ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))

#define EXTRACT_BITS(value, mask) ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
#define DW_EH_VERSION 1

// DWARF Pointer-Encoding (PEs).
//
Expand Down Expand Up @@ -204,6 +208,32 @@ typedef struct _libunwindInfo

#define DWARF_CIE_VERSION 3 // GCC emits version 1???

// DWARF frame header
typedef struct __attribute__((packed)) _eh_frame_hdr
{
unsigned char version;
unsigned char eh_frame_ptr_enc;
unsigned char fde_count_enc;
unsigned char table_enc;
// The rest of the header is variable-length and consists of the
// following members:
//
// encoded_t eh_frame_ptr;
// encoded_t fde_count;
// struct
// {
// encoded_t start_ip; // first address covered by this FDE
// encoded_t fde_offset; // offset of the FDE
// } binary_search_table[fde_count];
} eh_frame_hdr;

// "DW_EH_PE_datarel|DW_EH_PE_sdata4" encoded fde table entry
typedef struct table_entry
{
int32_t start_ip;
int32_t fde_offset;
} table_entry_t;

// DWARF unwind info
typedef struct dwarf_cie_info
{
Expand Down Expand Up @@ -510,6 +540,7 @@ BinarySearchEntries(

static_assert_no_msg(sizeof(T) >= sizeof(uint32_t));

#ifdef __APPLE__
static_assert_no_msg(offsetof(unwind_info_section_header_index_entry, functionOffset) == 0);
static_assert_no_msg(sizeof(unwind_info_section_header_index_entry::functionOffset) == sizeof(uint32_t));

Expand All @@ -518,6 +549,7 @@ BinarySearchEntries(

static_assert_no_msg(offsetof(unwind_info_section_header_lsda_index_entry, functionOffset) == 0);
static_assert_no_msg(sizeof(unwind_info_section_header_lsda_index_entry::functionOffset) == sizeof(uint32_t));
#endif // __APPLE__

// Do a binary search on table
for (low = 0, high = tableCount; low < high;)
Expand All @@ -529,9 +561,11 @@ BinarySearchEntries(
if (!ReadValue32(info, &addr, (uint32_t*)&functionOffset)) {
return false;
}
#ifdef __APPLE__
if (compressed) {
functionOffset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(functionOffset);
}
#endif // __APPLE__
if (ip < functionOffset) {
high = mid;
}
Expand Down Expand Up @@ -914,6 +948,8 @@ ExtractProcInfoFromFde(
return true;
}

#ifdef __APPLE__

static bool
SearchCompactEncodingSection(
const libunwindInfo* info,
Expand Down Expand Up @@ -1142,6 +1178,7 @@ SearchDwarfSection(
return false;
}


static bool
GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, const libunwindInfo* info, bool* step, int need_unwind_info)
{
Expand Down Expand Up @@ -1352,6 +1389,8 @@ StepWithCompactEncoding(const libunwindInfo* info, compact_unwind_encoding_t com

#endif // __APPLE__

#endif // defined(__APPLE__) || defined(FEATURE_USE_SYSTEM_LIBUNWIND)

static void GetContextPointer(unw_cursor_t *cursor, unw_context_t *unwContext, int reg, SIZE_T **contextPointer)
{
#if defined(HAVE_UNW_GET_SAVE_LOC)
Expand Down Expand Up @@ -1689,7 +1728,81 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int nee
}
}

#ifdef FEATURE_USE_SYSTEM_LIBUNWIND
if (ehFrameHdrAddr == 0) {
ASSERT("ELF: No PT_GNU_EH_FRAME program header\n");
return -UNW_EINVAL;
}
eh_frame_hdr ehFrameHdr;
if (!info->ReadMemory((PVOID)ehFrameHdrAddr, &ehFrameHdr, sizeof(eh_frame_hdr))) {
ERROR("ELF: reading ehFrameHdrAddr %p\n", ehFrameHdrAddr);
return -UNW_EINVAL;
}
TRACE("ehFrameHdrAddr %p version %d eh_frame_ptr_enc %d fde_count_enc %d table_enc %d\n",
ehFrameHdrAddr, ehFrameHdr.version, ehFrameHdr.eh_frame_ptr_enc, ehFrameHdr.fde_count_enc, ehFrameHdr.table_enc);

if (ehFrameHdr.version != DW_EH_VERSION) {
ASSERT("ehFrameHdr version %x not supported\n", ehFrameHdr.version);
return -UNW_EBADVERSION;
}
unw_word_t addr = ehFrameHdrAddr + sizeof(eh_frame_hdr);
unw_word_t ehFrameStart;
unw_word_t fdeCount;

// Decode the eh_frame_hdr info
if (!ReadEncodedPointer(info, &addr, ehFrameHdr.eh_frame_ptr_enc, UINTPTR_MAX, &ehFrameStart)) {
ERROR("decoding eh_frame_ptr\n");
return -UNW_EINVAL;
}
if (!ReadEncodedPointer(info, &addr, ehFrameHdr.fde_count_enc, UINTPTR_MAX, &fdeCount)) {
ERROR("decoding fde_count_enc\n");
return -UNW_EINVAL;
}
TRACE("ehFrameStart %p fdeCount %p ip offset %08x\n", ehFrameStart, fdeCount, (int32_t)(ip - ehFrameHdrAddr));

// If there are no frame table entries
if (fdeCount == 0) {
TRACE("No frame table entries\n");
return -UNW_ENOINFO;
}

// We assume this encoding
if (ehFrameHdr.table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
ASSERT("Table encoding not supported %x\n", ehFrameHdr.table_enc);
return -UNW_EINVAL;
}

// Find the fde using a binary search on the frame table
table_entry_t entry;
table_entry_t entryNext;
bool found;
if (!BinarySearchEntries(info, ip - ehFrameHdrAddr, addr, fdeCount, &entry, &entryNext, false, &found)) {
ERROR("LookupTableEntry\n");
return -UNW_EINVAL;
}
unw_word_t fdeAddr = entry.fde_offset + ehFrameHdrAddr;
TRACE("start_ip %08x fde_offset %08x fdeAddr %p found %d\n", entry.start_ip, entry.fde_offset, fdeAddr, found);

// Unwind info not found
if (!found) {
return -UNW_ENOINFO;
}

// Now get the unwind info
if (!ExtractProcInfoFromFde(info, &fdeAddr, pip, need_unwind_info)) {
ERROR("ExtractProcInfoFromFde\n");
return -UNW_EINVAL;
}

if (ip < pip->start_ip || ip >= pip->end_ip) {
TRACE("ip %p not in range start_ip %p end_ip %p\n", ip, pip->start_ip, pip->end_ip);
return -UNW_ENOINFO;
}
return UNW_ESUCCESS;
#else
return _OOP_find_proc_info(start_ip, end_ip, ehFrameHdrAddr, ehFrameHdrLen, exidxFrameHdrAddr, exidxFrameHdrLen, as, ip, pip, need_unwind_info, arg);
#endif // FEATURE_USE_SYSTEM_LIBUNWIND

#endif // __APPLE__
}

Expand Down Expand Up @@ -1796,4 +1909,4 @@ PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *cont
return FALSE;
}

#endif // defined(HAVE_UNW_GET_ACCESSORS) || defined(__APPLE__)
#endif // defined(__APPLE__) || defined(HAVE_UNW_GET_ACCESSORS)

0 comments on commit bf2e135

Please sign in to comment.