diff options
author | Kyungwoo Lee <kyulee@microsoft.com> | 2016-01-23 06:13:58 -0800 |
---|---|---|
committer | Kyungwoo Lee <kyulee@microsoft.com> | 2016-01-28 13:03:04 -0800 |
commit | b5f2fda695bf450c2bb37bdc618bfbc604406bde (patch) | |
tree | 8a1070d53999932e07e6b69f29b5083c02258c5f | |
parent | 67a86c9e114593ce1d24ef7b8a943b86438c0e46 (diff) | |
download | coreclr-b5f2fda695bf450c2bb37bdc618bfbc604406bde.tar.gz coreclr-b5f2fda695bf450c2bb37bdc618bfbc604406bde.tar.bz2 coreclr-b5f2fda695bf450c2bb37bdc618bfbc604406bde.zip |
Support for CFI unwind info
For Unix targeting CoreRT, this will provide platform specific unwind
info which is a dwarf format.
Unlike window’s UNWIND_INFO, we won’t encode the format within RyuJit
since it is not only complex/error-prone but also needs to be adjusted
depending on platforms.
Instead, CFI (call frame information) pseudo instructions are encoded,
which will be passed to CoreRT/ObjectWriter which will translate
them to directly emit CFI directives to LLVM MC stream to establish
frames and layout eh_frame section.
A jit flag is used to dynamically dispatch either Windows’s unwind
blob or this CFI instruction table. No JIT/EE interface change is needed
since the API already expects an opaque blob.
Initially when I looked at what Clang does, the prologue and the
sequence of CFI emissions are a bit different than Windows.
Since we will emit the same sequence of code with the same runtime that
we define, I assume this is unnecessary – I’ve verified the CFI sequence
here can work correctly with libunwind.
Basically we need only 3 operations – push reg is a combination of 1 and
2 below.
1. Allocation – increase stack frame. Normally subtract esp in x64.
2. Store – Copy a (callee save) register to stack (memory)
3. SaveFP – Set frame pointer register
Since Windows operation is based on the relative value (all offsets,
etc are computed from the current point), I also use the similar form of
CFI instructions.
So, mostly one window’s code corresponds to two CFIs – we might optimize
this by aggregating allocation, but I’d like to keep the current
syntax/semantic same as Windows.
This results in a very simple transformation on par with Windows.
-rw-r--r-- | src/inc/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/inc/cfi.h | 33 | ||||
-rw-r--r-- | src/inc/clrnt.h | 1 | ||||
-rw-r--r-- | src/inc/corjit.h | 2 | ||||
-rw-r--r-- | src/jit/compiler.h | 19 | ||||
-rw-r--r-- | src/jit/unwindamd64.cpp | 363 |
6 files changed, 384 insertions, 37 deletions
diff --git a/src/inc/CMakeLists.txt b/src/inc/CMakeLists.txt index 7d53f7ea5e..3277f00787 100644 --- a/src/inc/CMakeLists.txt +++ b/src/inc/CMakeLists.txt @@ -70,7 +70,8 @@ add_library(corguids ${CORGUIDS_SOURCES}) # Binplace the inc files for packaging later. -install (FILES cor.h +install (FILES cfi.h + cor.h corhdr.h corinfo.h corjit.h diff --git a/src/inc/cfi.h b/src/inc/cfi.h new file mode 100644 index 0000000000..d5d77840ec --- /dev/null +++ b/src/inc/cfi.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef CFI_H_ +#define CFI_H_ + +#define DWARF_REG_ILLEGAL -1 +enum CFI_OPCODE +{ + CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one. + CFI_DEF_CFA_REGISTER, // New register is used to compute CFA + CFI_REL_OFFSET // Register is saved at offset from the current CFA +}; + +struct CFI_CODE +{ + unsigned char CodeOffset;// Offset from the start of code the frame covers. + unsigned char CfiOpCode; + short DwarfReg; // Dwarf register number. 0~32 for x64. + int Offset; + CFI_CODE(unsigned char codeOffset, unsigned char cfiOpcode, + short dwarfReg, int offset) + : CodeOffset(codeOffset) + , CfiOpCode(cfiOpcode) + , DwarfReg(dwarfReg) + , Offset(offset) + {} +}; +typedef CFI_CODE* PCFI_CODE; + +#endif // CFI_H + diff --git a/src/inc/clrnt.h b/src/inc/clrnt.h index cd21e2c6ec..5958906898 100644 --- a/src/inc/clrnt.h +++ b/src/inc/clrnt.h @@ -7,6 +7,7 @@ #define CLRNT_H_ #include "staticcontract.h" +#include "cfi.h" // // This file is the result of some changes to the SDK header files. diff --git a/src/inc/corjit.h b/src/inc/corjit.h index 109b54a371..a84887d109 100644 --- a/src/inc/corjit.h +++ b/src/inc/corjit.h @@ -124,7 +124,7 @@ enum CorJitFlag #ifdef MDIL CORJIT_FLG_MDIL = 0x00004000, // Generate MDIL code instead of machine code #else // MDIL - CORJIT_FLG_UNUSED7 = 0x00004000, + CORJIT_FLG_CFI_UNWIND = 0x00004000, // Emit CFI unwind info #endif // MDIL #ifdef MDIL diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 460faca4e1..b915004fea 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -1175,6 +1175,10 @@ struct FuncInfoDsc BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF*sizeof(UNWIND_CODE))]; unsigned unwindCodeSlot; +#ifdef UNIX_AMD64_ABI + jitstd::vector<CFI_CODE>* cfiCodes; +#endif // UNIX_AMD64_ABI + #elif defined(_TARGET_ARMARCH_) UnwindInfo uwi; // Unwind information for this function/funclet's hot section @@ -6899,6 +6903,21 @@ private: void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode); UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func); + void unwindBegPrologWindows(); + void unwindPushWindows(regNumber reg); + void unwindAllocStackWindows(unsigned size); + void unwindSetFrameRegWindows(regNumber reg, unsigned offset); + void unwindSaveRegWindows(regNumber reg, unsigned offset); + +#ifdef UNIX_AMD64_ABI + void unwindBegPrologCFI(); + void unwindPushCFI(regNumber reg); + void unwindAllocStackCFI(unsigned size); + void unwindSetFrameRegCFI(regNumber reg, unsigned offset); + void unwindSaveRegCFI(regNumber reg, unsigned offset); + int mapRegNumToDwarfReg(regNumber reg); + void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0); +#endif // UNIX_AMD64_ABI #elif defined(_TARGET_ARM_) void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16); diff --git a/src/jit/unwindamd64.cpp b/src/jit/unwindamd64.cpp index 3f624eac9b..b5658ab716 100644 --- a/src/jit/unwindamd64.cpp +++ b/src/jit/unwindamd64.cpp @@ -17,6 +17,58 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif #if defined(_TARGET_AMD64_) +#ifdef UNIX_AMD64_ABI +int Compiler::mapRegNumToDwarfReg(regNumber reg) +{ + int dwarfReg = DWARF_REG_ILLEGAL; + + switch (reg) + { + case REG_RAX: dwarfReg = 0; break; + case REG_RCX: dwarfReg = 2; break; + case REG_RDX: dwarfReg = 1; break; + case REG_RBX: dwarfReg = 3; break; + case REG_RSP: dwarfReg = 7; break; + case REG_RBP: dwarfReg = 6; break; + case REG_RSI: dwarfReg = 4; break; + case REG_RDI: dwarfReg = 5; break; + case REG_R8: dwarfReg = 8; break; + case REG_R9: dwarfReg = 9; break; + case REG_R10: dwarfReg = 10; break; + case REG_R11: dwarfReg = 11; break; + case REG_R12: dwarfReg = 12; break; + case REG_R13: dwarfReg = 13; break; + case REG_R14: dwarfReg = 14; break; + case REG_R15: dwarfReg = 15; break; + case REG_XMM0: dwarfReg = 17; break; + case REG_XMM1: dwarfReg = 18; break; + case REG_XMM2: dwarfReg = 19; break; + case REG_XMM3: dwarfReg = 20; break; + case REG_XMM4: dwarfReg = 21; break; + case REG_XMM5: dwarfReg = 22; break; + case REG_XMM6: dwarfReg = 23; break; + case REG_XMM7: dwarfReg = 24; break; + case REG_XMM8: dwarfReg = 25; break; + case REG_XMM9: dwarfReg = 26; break; + case REG_XMM10:dwarfReg = 27; break; + case REG_XMM11:dwarfReg = 28; break; + case REG_XMM12:dwarfReg = 29; break; + case REG_XMM13:dwarfReg = 30; break; + case REG_XMM14:dwarfReg = 31; break; + case REG_XMM15:dwarfReg = 32; break; + default: + noway_assert(!"unexpected REG_NUM"); + } + + return dwarfReg; +} + +void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset) +{ + CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset); + func->cfiCodes->push_back(cfiEntry); +} +#endif // UNIX_AMD64_ABI //------------------------------------------------------------------------ // Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the @@ -31,7 +83,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func) { assert(compGeneratingProlog); - UNATIVE_OFFSET offset; if (func->funKind == FUNC_ROOT) { @@ -50,7 +101,21 @@ UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func) // Compiler::unwindBegProlog: Initialize the unwind info data structures. // Called at the beginning of main function or funclet prolog generation. // -void Compiler::unwindBegProlog() +void Compiler::unwindBegProlog() +{ +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + unwindBegPrologCFI(); + } + else +#endif // UNIX_AMD64_ABI + { + unwindBegPrologWindows(); + } +} + +void Compiler::unwindBegPrologWindows() { assert(compGeneratingProlog); @@ -74,6 +139,37 @@ void Compiler::unwindBegProlog() func->unwindHeader.FrameOffset = 0; } +#ifdef UNIX_AMD64_ABI +template <typename T> +inline +static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5) +{ + return jitstd::allocator<T>(alloc).allocate(count); +} +typedef jitstd::vector<CFI_CODE> CFICodeVector; + +void Compiler::unwindBegPrologCFI() +{ + assert(compGeneratingProlog); + + FuncInfoDsc* func = funCurrentFunc(); + + // There is only one prolog for a function/funclet, and it comes first. So now is + // a good time to initialize all the unwind data structures. + + unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc); + + if (fgFirstColdBlock != nullptr) + { + unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc); + } + + jitstd::allocator<void> allocator(getAllocator()); + + func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator); +} +#endif // UNIX_AMD64_ABI + //------------------------------------------------------------------------ // Compiler::unwindEndProlog: Called at the end of main function or funclet // prolog generation to indicate there is no more unwind information for this prolog. @@ -109,6 +205,20 @@ void Compiler::unwindEndEpilog() // void Compiler::unwindPush(regNumber reg) { +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + unwindPushCFI(reg); + } + else +#endif + { + unwindPushWindows(reg); + } +} + +void Compiler::unwindPushWindows(regNumber reg) +{ assert(compGeneratingProlog); FuncInfoDsc* func = funCurrentFunc(); @@ -120,6 +230,7 @@ void Compiler::unwindPush(regNumber reg) unsigned int cbProlog = unwindGetCurrentOffset(func); noway_assert((BYTE)cbProlog == cbProlog); code->CodeOffset = (BYTE)cbProlog; + if ((RBM_CALLEE_SAVED & genRegMask(reg)) #if ETW_EBP_FRAMED // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP) @@ -141,6 +252,32 @@ void Compiler::unwindPush(regNumber reg) } } +#ifdef UNIX_AMD64_ABI +void Compiler::unwindPushCFI(regNumber reg) +{ + assert(compGeneratingProlog); + + FuncInfoDsc* func = funCurrentFunc(); + + unsigned int cbProlog = unwindGetCurrentOffset(func); + noway_assert((BYTE)cbProlog == cbProlog); + + createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, 8); + if ((RBM_CALLEE_SAVED & genRegMask(reg)) +#if ETW_EBP_FRAMED + // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP) + // is excluded from the callee-save register list. + // Make sure the register gets PUSH unwind info in this case, + // since it is pushed as a frame register. + || (reg == REG_FPBASE) +#endif // ETW_EBP_FRAMED + ) + { + createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg)); + } +} +#endif // UNIX_AMD64_ABI + //------------------------------------------------------------------------ // Compiler::unwindAllocStack: Record a stack frame allocation (sub sp, X). // @@ -149,6 +286,20 @@ void Compiler::unwindPush(regNumber reg) // void Compiler::unwindAllocStack(unsigned size) { +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + unwindAllocStackCFI(size); + } + else +#endif // UNIX_AMD64_ABI + { + unwindAllocStackWindows(size); + } +} + +void Compiler::unwindAllocStackWindows(unsigned size) +{ assert(compGeneratingProlog); FuncInfoDsc* func = funCurrentFunc(); @@ -187,6 +338,19 @@ void Compiler::unwindAllocStack(unsigned size) code->CodeOffset = (BYTE)cbProlog; } +#ifdef UNIX_AMD64_ABI +void Compiler::unwindAllocStackCFI(unsigned size) +{ + assert(compGeneratingProlog); + + FuncInfoDsc* func = funCurrentFunc(); + + unsigned int cbProlog = unwindGetCurrentOffset(func); + noway_assert((BYTE)cbProlog == cbProlog); + createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size); +} +#endif // UNIX_AMD64_ABI + //------------------------------------------------------------------------ // Compiler::unwindSetFrameReg: Record a frame register. // @@ -196,6 +360,20 @@ void Compiler::unwindAllocStack(unsigned size) // void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset) { +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + unwindSetFrameRegCFI(reg, offset); + } + else +#endif // UNIX_AMD64_ABI + { + unwindSetFrameRegWindows(reg, offset); + } +} + +void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset) +{ assert(compGeneratingProlog); FuncInfoDsc* func = funCurrentFunc(); @@ -215,6 +393,23 @@ void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset) func->unwindHeader.FrameOffset = offset / 16; } +#ifdef UNIX_AMD64_ABI +void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset) +{ + assert(compGeneratingProlog); + FuncInfoDsc* func = funCurrentFunc(); + + unsigned int cbProlog = unwindGetCurrentOffset(func); + noway_assert((BYTE)cbProlog == cbProlog); + + createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg)); + if (offset != 0) + { + createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, offset); + } +} +#endif // UNIX_AMD64_ABI + //------------------------------------------------------------------------ // Compiler::unwindSaveReg: Record a register save. // @@ -224,6 +419,20 @@ void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset) // void Compiler::unwindSaveReg(regNumber reg, unsigned offset) { +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + unwindSaveRegCFI(reg, offset); + } + else +#endif // UNIX_AMD64_ABI + { + unwindSaveRegWindows(reg, offset); + } +} + +void Compiler::unwindSaveRegWindows(regNumber reg, unsigned offset) +{ assert(compGeneratingProlog); FuncInfoDsc* func = funCurrentFunc(); @@ -266,6 +475,22 @@ void Compiler::unwindSaveReg(regNumber reg, unsigned offset) } } +#ifdef UNIX_AMD64_ABI +void Compiler::unwindSaveRegCFI(regNumber reg, unsigned offset) +{ + assert(compGeneratingProlog); + + if (RBM_CALLEE_SAVED & genRegMask(reg)) + { + FuncInfoDsc* func = funCurrentFunc(); + + unsigned int cbProlog = unwindGetCurrentOffset(func); + noway_assert((BYTE)cbProlog == cbProlog); + createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg), offset); + } +} +#endif // UNIX_AMD64_ABI + #ifdef DEBUG //------------------------------------------------------------------------ @@ -409,6 +634,50 @@ void DumpUnwindInfo(bool isHotCode, UNATIVE_OFFSET startOffset, UNATIVE_OFFSET e } } +#ifdef UNIX_AMD64_ABI +//------------------------------------------------------------------------ +// DumpCfiInfo: Dump the Cfi data. +// +// Arguments: +// isHotCode - true if this cfi data is for the hot section, false otherwise. +// startOffset - byte offset of the code start that this cfi data represents. +// endOffset - byte offset of the code end that this cfi data represents. +// pcFiCode - pointer to the cfi data blob. +// +void DumpCfiInfo(bool isHotCode, UNATIVE_OFFSET startOffset, UNATIVE_OFFSET endOffset, DWORD cfiCodeBytes, const CFI_CODE * const pCfiCode) +{ + printf("Cfi Info%s:\n", isHotCode ? "" : " COLD"); + printf(" >> Start offset : 0x%06x \n", dspOffset(startOffset)); + printf(" >> End offset : 0x%06x \n", dspOffset(endOffset)); + + for (int i = 0; i < cfiCodeBytes / sizeof(CFI_CODE); i++) + { + const CFI_CODE * const pCode = &(pCfiCode[i]); + + UCHAR codeOffset = pCode->CodeOffset; + SHORT dwarfReg = pCode->DwarfReg; + INT offset = pCode->Offset; + + switch (pCode->CfiOpCode) + { + case CFI_REL_OFFSET: + printf(" CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg, offset); + break; + case CFI_DEF_CFA_REGISTER: + assert(offset == 0); + printf(" CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg); + break; + case CFI_ADJUST_CFA_OFFSET: + assert(dwarfReg == DWARF_REG_ILLEGAL); + printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset); + break; + default: + printf(" Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode); + break; + } + } +} +#endif // UNIX_AMD64_ABI #endif // DEBUG @@ -439,9 +708,6 @@ void Compiler::unwindReserve() // void Compiler::unwindReserveFunc(FuncInfoDsc* func) { - assert(func->unwindHeader.Version == 1); // Can't call this before unwindBegProlog - assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog - unwindReserveFuncHelper(func, true); if (fgFirstColdBlock != nullptr) @@ -460,34 +726,41 @@ void Compiler::unwindReserveFunc(FuncInfoDsc* func) // void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode) { - DWORD unwindCodeBytes; - + DWORD unwindCodeBytes = 0; if (isHotCode) { - // Set the size of the prolog to be the last encoded action - if (func->unwindCodeSlot < sizeof(func->unwindCodes)) +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) { - UNWIND_CODE * code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot]; - func->unwindHeader.SizeOfProlog = code->CodeOffset; + unwindCodeBytes = func->cfiCodes->size() * sizeof(CFI_CODE); } else +#endif // UNIX_AMD64_ABI { - func->unwindHeader.SizeOfProlog = 0; - } - func->unwindHeader.CountOfUnwindCodes = (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE)); + assert(func->unwindHeader.Version == 1); // Can't call this before unwindBegProlog + assert(func->unwindHeader.CountOfUnwindCodes == 0); // Only call this once per prolog - // Prepend the unwindHeader onto the unwind codes - assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode)); + // Set the size of the prolog to be the last encoded action + if (func->unwindCodeSlot < sizeof(func->unwindCodes)) + { + UNWIND_CODE * code = (UNWIND_CODE*)&func->unwindCodes[func->unwindCodeSlot]; + func->unwindHeader.SizeOfProlog = code->CodeOffset; + } + else + { + func->unwindHeader.SizeOfProlog = 0; + } + func->unwindHeader.CountOfUnwindCodes = (BYTE)((sizeof(func->unwindCodes) - func->unwindCodeSlot) / sizeof(UNWIND_CODE)); - func->unwindCodeSlot -= offsetof(UNWIND_INFO, UnwindCode); - UNWIND_INFO * pHeader = (UNWIND_INFO*)&func->unwindCodes[func->unwindCodeSlot]; - memcpy(pHeader, &func->unwindHeader, offsetof(UNWIND_INFO, UnwindCode)); + // Prepend the unwindHeader onto the unwind codes + assert(func->unwindCodeSlot >= offsetof(UNWIND_INFO, UnwindCode)); - unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot; - } - else - { - unwindCodeBytes = 0; + func->unwindCodeSlot -= offsetof(UNWIND_INFO, UnwindCode); + UNWIND_INFO * pHeader = (UNWIND_INFO*)&func->unwindCodes[func->unwindCodeSlot]; + memcpy(pHeader, &func->unwindHeader, offsetof(UNWIND_INFO, UnwindCode)); + + unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot; + } } BOOL isFunclet = (func->funKind != FUNC_ROOT); @@ -531,8 +804,8 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo { UNATIVE_OFFSET startOffset; UNATIVE_OFFSET endOffset; - DWORD unwindCodeBytes; - BYTE* pUnwindBlock; + DWORD unwindCodeBytes = 0; + BYTE* pUnwindBlock = nullptr; if (isHotCode) { @@ -554,15 +827,29 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo endOffset = func->endLoc->CodeOffset(genEmitter); } - unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot; +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + int size = func->cfiCodes->size(); + if (size > 0) + { + unwindCodeBytes = size * sizeof(CFI_CODE); + pUnwindBlock = (BYTE*)&(*func->cfiCodes)[0]; + } + } + else +#endif // UNIX_AMD64_ABI + { + unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot; #ifdef DEBUG - UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) (&func->unwindCodes[func->unwindCodeSlot]); - DWORD unwindCodeBytesSpecified = offsetof(UNWIND_INFO, UnwindCode) + pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE); // This is what the unwind codes themselves say; it better match what we tell the VM. - assert(unwindCodeBytes == unwindCodeBytesSpecified); + UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *)(&func->unwindCodes[func->unwindCodeSlot]); + DWORD unwindCodeBytesSpecified = offsetof(UNWIND_INFO, UnwindCode) + pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE); // This is what the unwind codes themselves say; it better match what we tell the VM. + assert(unwindCodeBytes == unwindCodeBytesSpecified); #endif // DEBUG - pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot]; + pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot]; + } } else { @@ -586,15 +873,21 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo { endOffset = func->coldEndLoc->CodeOffset(genEmitter); } - - unwindCodeBytes = 0; // The VM handles creating chained unwind info, and requires this to be zero. - pUnwindBlock = nullptr; } #ifdef DEBUG if (opts.dspUnwind) { - DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO * const)pUnwindBlock); +#ifdef UNIX_AMD64_ABI + if ((opts.eeFlags & CORJIT_FLG_CFI_UNWIND) != 0) + { + DumpCfiInfo(isHotCode, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE * const)pUnwindBlock); + } + else +#endif // UNIX_AMD64_ABI + { + DumpUnwindInfo(isHotCode, startOffset, endOffset, (const UNWIND_INFO * const)pUnwindBlock); + } } #endif // DEBUG |