Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAditya Mandaleeka <adityam@microsoft.com>2017-11-16 03:27:54 +0300
committerAditya Mandaleeka <adityam@microsoft.com>2017-12-08 02:45:58 +0300
commit1bd9c3c2472e656d7e2c90b2c8273e99469faf05 (patch)
tree77a83c7a0914a08a2064975e221620cb5334559e /src/Native
parent9f70bcc80bad914b45040c95cd7ebb8838a336e7 (diff)
Find unwind info ourselves rather than initializing unwind cursors each time.
Diffstat (limited to 'src/Native')
-rw-r--r--src/Native/Runtime/CMakeLists.txt4
-rw-r--r--src/Native/Runtime/regdisplay.h200
-rw-r--r--src/Native/Runtime/unix/UnixContext.cpp36
-rw-r--r--src/Native/Runtime/unix/UnwindHelpers.cpp187
-rw-r--r--src/Native/Runtime/unix/UnwindHelpers.h14
-rw-r--r--src/Native/libunwind/src/UnwindCursor.hpp9
6 files changed, 416 insertions, 34 deletions
diff --git a/src/Native/Runtime/CMakeLists.txt b/src/Native/Runtime/CMakeLists.txt
index 12fa1532d..1cd4cd949 100644
--- a/src/Native/Runtime/CMakeLists.txt
+++ b/src/Native/Runtime/CMakeLists.txt
@@ -106,6 +106,9 @@ else()
include_directories($ENV{EMSCRIPTEN/system/lib/libcxxabi/include})
endif()
+ include_directories(../libunwind/include)
+ include_directories(../libunwind)
+
# Disable building _Unwind_XXX style APIs of libunwind, since we don't use them.
add_definitions(-D_LIBUNWIND_DISABLE_ZERO_COST_APIS=1)
@@ -119,6 +122,7 @@ else()
list(APPEND FULL_RUNTIME_SOURCES
unix/HardwareExceptions.cpp
unix/UnixContext.cpp
+ unix/UnwindHelpers.cpp
unix/UnixNativeCodeManager.cpp
../libunwind/src/Unwind-EHABI.cpp
../libunwind/src/libunwind.cpp
diff --git a/src/Native/Runtime/regdisplay.h b/src/Native/Runtime/regdisplay.h
index aa234717e..eb96f400f 100644
--- a/src/Native/Runtime/regdisplay.h
+++ b/src/Native/Runtime/regdisplay.h
@@ -4,6 +4,39 @@
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+// These definitions are from our copy of libunwind. Including them directly here
+// so that the REGDISPLAY code doesn't need to reference libunwind.
+namespace LibunwindConstants
+{
+ // copied from Registers.hpp
+ // Architecture independent register numbers
+ enum {
+ UNW_REG_IP = -1, // instruction pointer
+ UNW_REG_SP = -2, // stack pointer
+ };
+
+ // copied from libunwind.h
+ // 64-bit x86_64 registers
+ enum {
+ UNW_X86_64_RAX = 0,
+ UNW_X86_64_RDX = 1,
+ UNW_X86_64_RCX = 2,
+ UNW_X86_64_RBX = 3,
+ UNW_X86_64_RSI = 4,
+ UNW_X86_64_RDI = 5,
+ UNW_X86_64_RBP = 6,
+ UNW_X86_64_RSP = 7,
+ UNW_X86_64_R8 = 8,
+ UNW_X86_64_R9 = 9,
+ UNW_X86_64_R10 = 10,
+ UNW_X86_64_R11 = 11,
+ UNW_X86_64_R12 = 12,
+ UNW_X86_64_R13 = 13,
+ UNW_X86_64_R14 = 14,
+ UNW_X86_64_R15 = 15
+ };
+}
+
struct REGDISPLAY
{
PTR_UIntNative pRax;
@@ -45,6 +78,173 @@ struct REGDISPLAY
inline void SetIP(PCODE IP) { this->IP = IP; }
inline void SetAddrOfIP(PTR_PCODE pIP) { this->pIP = pIP; }
inline void SetSP(UIntNative SP) { this->SP = SP; }
+
+ // Everything below was added to enable libunwind to work with REGDISPLAYs.
+
+#if defined(_TARGET_AMD64_)
+
+ inline uint64_t getRegister(int regNum) const
+ {
+ switch (regNum)
+ {
+ case LibunwindConstants::UNW_REG_IP:
+ return IP;
+ case LibunwindConstants::UNW_REG_SP:
+ return SP;
+ case LibunwindConstants::UNW_X86_64_RAX:
+ return *pRax;
+ case LibunwindConstants::UNW_X86_64_RDX:
+ return *pRdx;
+ case LibunwindConstants::UNW_X86_64_RCX:
+ return *pRcx;
+ case LibunwindConstants::UNW_X86_64_RBX:
+ return *pRbx;
+ case LibunwindConstants::UNW_X86_64_RSI:
+ return *pRsi;
+ case LibunwindConstants::UNW_X86_64_RDI:
+ return *pRdi;
+ case LibunwindConstants::UNW_X86_64_RBP:
+ return *pRbp;
+ case LibunwindConstants::UNW_X86_64_RSP:
+ return SP;
+ case LibunwindConstants::UNW_X86_64_R8:
+ return *pR8;
+ case LibunwindConstants::UNW_X86_64_R9:
+ return *pR9;
+ case LibunwindConstants::UNW_X86_64_R10:
+ return *pR10;
+ case LibunwindConstants::UNW_X86_64_R11:
+ return *pR11;
+ case LibunwindConstants::UNW_X86_64_R12:
+ return *pR12;
+ case LibunwindConstants::UNW_X86_64_R13:
+ return *pR13;
+ case LibunwindConstants::UNW_X86_64_R14:
+ return *pR14;
+ case LibunwindConstants::UNW_X86_64_R15:
+ return *pR15;
+ }
+
+ // Unsupported register requested
+ abort();
+ }
+
+ inline void setRegister(int regNum, uint64_t value, uint64_t location)
+ {
+ switch (regNum)
+ {
+ case LibunwindConstants::UNW_REG_IP:
+ IP = value;
+ pIP = (PTR_PCODE)location;
+ return;
+ case LibunwindConstants::UNW_REG_SP:
+ SP = value;
+ return;
+ case LibunwindConstants::UNW_X86_64_RAX:
+ pRax = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RDX:
+ pRdx = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RCX:
+ pRcx = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RBX:
+ pRbx = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RSI:
+ pRsi = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RDI:
+ pRdi = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RBP:
+ pRbp = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_RSP:
+ SP = value;
+ return;
+ case LibunwindConstants::UNW_X86_64_R8:
+ pR8 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R9:
+ pR9 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R10:
+ pR10 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R11:
+ pR11 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R12:
+ pR12 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R13:
+ pR13 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R14:
+ pR14 = (PTR_UIntNative)location;
+ return;
+ case LibunwindConstants::UNW_X86_64_R15:
+ pR15 = (PTR_UIntNative)location;
+ return;
+ }
+
+ // Unsupported x86_64 register
+ abort();
+ }
+
+ // N/A for x86_64
+ inline bool validFloatRegister(int) { return false; }
+ inline bool validVectorRegister(int) { return false; }
+
+ inline static int lastDwarfRegNum() { return 16; }
+
+ inline bool validRegister(int regNum) const
+ {
+ if (regNum == LibunwindConstants::UNW_REG_IP)
+ return true;
+ if (regNum == LibunwindConstants::UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum > 15)
+ return false;
+ return true;
+ }
+
+ // N/A for x86_64
+ inline double getFloatRegister(int) const { abort(); }
+ inline void setFloatRegister(int, double) { abort(); }
+ inline double getVectorRegister(int) const { abort(); }
+ inline void setVectorRegister(int, ...) { abort(); }
+
+ uint64_t getSP() const { return SP; }
+ void setSP(uint64_t value, uint64_t location) { SP = value; }
+
+ uint64_t getIP() const { return IP; }
+
+ void setIP(uint64_t value, uint64_t location)
+ {
+ IP = value;
+ pIP = (PTR_PCODE)location;
+ }
+
+ uint64_t getRBP() const { return *pRbp; }
+ void setRBP(uint64_t value, uint64_t location) { pRbp = (PTR_UIntNative)location; }
+ uint64_t getRBX() const { return *pRbx; }
+ void setRBX(uint64_t value, uint64_t location) { pRbx = (PTR_UIntNative)location; }
+ uint64_t getR12() const { return *pR12; }
+ void setR12(uint64_t value, uint64_t location) { pR12 = (PTR_UIntNative)location; }
+ uint64_t getR13() const { return *pR13; }
+ void setR13(uint64_t value, uint64_t location) { pR13 = (PTR_UIntNative)location; }
+ uint64_t getR14() const { return *pR14; }
+ void setR14(uint64_t value, uint64_t location) { pR14 = (PTR_UIntNative)location; }
+ uint64_t getR15() const { return *pR15; }
+ void setR15(uint64_t value, uint64_t location) { pR15 = (PTR_UIntNative)location; }
+
+#endif // _TARGET_AMD64_
+
};
#elif defined(_TARGET_ARM_)
diff --git a/src/Native/Runtime/unix/UnixContext.cpp b/src/Native/Runtime/unix/UnixContext.cpp
index 549271e30..cf88a5994 100644
--- a/src/Native/Runtime/unix/UnixContext.cpp
+++ b/src/Native/Runtime/unix/UnixContext.cpp
@@ -18,6 +18,7 @@
#endif // HAVE_UCONTEXT_T
#include "UnixContext.h"
+#include "UnwindHelpers.h"
// WebAssembly has a slightly different version of LibUnwind that doesn't define unw_get_save_loc
#if defined(_WASM_)
@@ -599,38 +600,5 @@ bool FindProcInfo(UIntNative controlPC, UIntNative* startAddress, UIntNative* ls
// Virtually unwind stack to the caller of the context specified by the REGDISPLAY
bool VirtualUnwind(REGDISPLAY* pRegisterSet)
{
- unw_context_t unwContext;
- unw_cursor_t cursor;
-
- if (!InitializeUnwindContextAndCursor(pRegisterSet, &cursor, &unwContext))
- {
- return false;
- }
-
- // FreeBSD, NetBSD and OSX appear to do two different things when unwinding
- // 1: If it reaches where it cannot unwind anymore, say a
- // managed frame. It wil return 0, but also update the $pc
- // 2: If it unwinds all the way to _start it will return
- // 0 from the step, but $pc will stay the same.
- // The behaviour of libunwind from nongnu.org is to null the PC
- // So we bank the original PC here, so we can compare it after
- // the step
- uintptr_t curPc = pRegisterSet->GetIP();
-
- int st = unw_step(&cursor);
- if (st < 0)
- {
- return false;
- }
-
- // Update the REGDISPLAY to reflect the unwind
- UnwindCursorToRegDisplay(&cursor, &unwContext, pRegisterSet);
-
- if (st == 0 && pRegisterSet->GetIP() == curPc)
- {
- // TODO: is this correct for CoreRT? Should we return false instead?
- pRegisterSet->SetIP(0);
- }
-
- return true;
+ return UnwindHelpers::StepFrame(pRegisterSet);
}
diff --git a/src/Native/Runtime/unix/UnwindHelpers.cpp b/src/Native/Runtime/unix/UnwindHelpers.cpp
new file mode 100644
index 000000000..34008b18d
--- /dev/null
+++ b/src/Native/Runtime/unix/UnwindHelpers.cpp
@@ -0,0 +1,187 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "daccess.h"
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+#ifdef __APPLE__
+#include <mach-o/getsect.h>
+#endif
+
+#include <regdisplay.h>
+#include "UnwindHelpers.h"
+
+// libunwind headers
+#include <libunwind.h>
+#include <src/config.h>
+#include <src/Registers.hpp>
+#include <src/AddressSpace.hpp>
+#include <src/UnwindCursor.hpp>
+
+using libunwind::Registers_x86_64;
+using libunwind::LocalAddressSpace;
+using libunwind::EHHeaderParser;
+using libunwind::DwarfInstructions;
+using libunwind::UnwindInfoSections;
+
+LocalAddressSpace _addressSpace;
+
+#ifdef __APPLE__
+
+struct dyld_unwind_sections
+{
+ const struct mach_header* mh;
+ const void* dwarf_section;
+ uintptr_t dwarf_section_length;
+ const void* compact_unwind_section;
+ uintptr_t compact_unwind_section_length;
+};
+
+#else // __APPLE__
+
+// Passed to the callback function called by dl_iterate_phdr
+struct dl_iterate_cb_data
+{
+ UnwindInfoSections *sects;
+ uintptr_t targetAddr;
+};
+
+// Callback called by dl_iterate_phdr. Locates unwind info sections for the target
+// address.
+static int LocateSectionsCallback(struct dl_phdr_info *info, size_t size, void *data)
+{
+ // info is a pointer to a structure containing information about the shared object
+ dl_iterate_cb_data* cbdata = static_cast<dl_iterate_cb_data*>(data);
+ uintptr_t addrOfInterest = (uintptr_t)cbdata->targetAddr;
+
+ size_t object_length;
+ bool found_obj = false;
+ bool found_hdr = false;
+
+ // If the base address of the SO is past the address we care about, move on.
+ if (info->dlpi_addr > addrOfInterest)
+ {
+ return 0;
+ }
+
+ // Iterate through the program headers for this SO
+ for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++)
+ {
+ const ElfW(Phdr) *phdr = &info->dlpi_phdr[i];
+
+ if (phdr->p_type == PT_LOAD)
+ {
+ // This is a loadable entry. Loader loads all segments of this type.
+
+ uintptr_t begin = info->dlpi_addr + phdr->p_vaddr;
+ uintptr_t end = begin + phdr->p_memsz;
+
+ if (addrOfInterest >= begin && addrOfInterest < end)
+ {
+ cbdata->sects->dso_base = begin;
+ object_length = phdr->p_memsz;
+ found_obj = true;
+ }
+ }
+ else if (phdr->p_type == PT_GNU_EH_FRAME)
+ {
+ // This element specifies the location and size of the exception handling
+ // information as defined by the .eh_frame_hdr section.
+
+ EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+
+ uintptr_t eh_frame_hdr_start = info->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> ehp;
+ ehp.decodeEHHdr(_addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo);
+
+ cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+ found_hdr = true;
+ }
+ }
+
+ return 0;
+}
+
+#endif // __APPLE__
+
+bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs)
+{
+#if defined(_TARGET_AMD64_)
+ libunwind::UnwindCursor<LocalAddressSpace, Registers_x86_64> uc(_addressSpace);
+#elif defined(_TARGET_ARM_)
+ libunwind::UnwindCursor<LocalAddressSpace, Registers_arm> uc(_addressSpace);
+#else
+ #error "Unwinding is not implemented for this architecture yet."
+#endif
+
+ bool retVal = uc.getInfoFromDwarfSection(pc, uwInfoSections, 0 /* fdeSectionOffsetHint */);
+ if (!retVal)
+ {
+ return false;
+ }
+
+ unw_proc_info_t procInfo;
+ uc.getInfo(&procInfo);
+
+ DwarfInstructions<LocalAddressSpace, REGDISPLAY> dwarfInst;
+
+ int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, procInfo.unwind_info, *regs);
+ if (stepRet != UNW_STEP_SUCCESS)
+ {
+ return false;
+ }
+
+ regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR));
+
+ return true;
+}
+
+UnwindInfoSections LocateUnwindSections(uintptr_t pc)
+{
+ UnwindInfoSections uwInfoSections;
+
+#ifdef __APPLE__
+ // On macOS, we can use a dyld function from libSystem in order
+ // to find the unwind sections.
+
+ libunwind::dyld_unwind_sections dyldInfo;
+
+ if (libunwind::_dyld_find_unwind_sections((void *)pc, &dyldInfo))
+ {
+ uwInfoSections.dso_base = (uintptr_t)dyldInfo.mh;
+
+ uwInfoSections.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
+ uwInfoSections.dwarf_section_length = dyldInfo.dwarf_section_length;
+
+ uwInfoSections.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
+ uwInfoSections.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+ }
+#else // __APPLE__
+
+ dl_iterate_cb_data cb_data = {&uwInfoSections, pc };
+ dl_iterate_phdr(LocateSectionsCallback, &cb_data);
+
+#endif
+
+ return uwInfoSections;
+}
+
+bool UnwindHelpers::StepFrame(REGDISPLAY *regs)
+{
+ uintptr_t pc = regs->GetIP();
+
+ UnwindInfoSections uwInfoSections = LocateUnwindSections(pc);
+ if (uwInfoSections.dwarf_section == NULL)
+ {
+ return false;
+ }
+
+ return DoTheStep(pc, uwInfoSections, regs);
+}
diff --git a/src/Native/Runtime/unix/UnwindHelpers.h b/src/Native/Runtime/unix/UnwindHelpers.h
new file mode 100644
index 000000000..cf9e91ea4
--- /dev/null
+++ b/src/Native/Runtime/unix/UnwindHelpers.h
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+
+// This class is used to encapsulate the internals of our unwinding implementation
+// and any custom versions of libunwind structures that we use for performance
+// reasons.
+class UnwindHelpers
+{
+public:
+ static bool StepFrame(REGDISPLAY *regs);
+};
diff --git a/src/Native/libunwind/src/UnwindCursor.hpp b/src/Native/libunwind/src/UnwindCursor.hpp
index 7a1149eaf..f68eee18e 100644
--- a/src/Native/libunwind/src/UnwindCursor.hpp
+++ b/src/Native/libunwind/src/UnwindCursor.hpp
@@ -427,6 +427,7 @@ template <typename A, typename R>
class UnwindCursor : public AbstractUnwindCursor{
typedef typename A::pint_t pint_t;
public:
+ UnwindCursor(A &as);
UnwindCursor(unw_context_t *context, A &as);
UnwindCursor(A &as, void *threadArg);
virtual ~UnwindCursor() {}
@@ -469,6 +470,7 @@ private:
#endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+public:
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint=0);
int stepWithDwarfFDE() {
@@ -608,6 +610,13 @@ private:
bool _isSignalFrame;
};
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(A &as)
+ : _addressSpace(as)
+ , _unwindInfoMissing(false)
+ , _isSignalFrame(false) {
+ memset(&_info, 0, sizeof(_info));
+}
template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)