summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyungwoo Lee <kyulee@microsoft.com>2016-01-23 06:13:58 -0800
committerKyungwoo Lee <kyulee@microsoft.com>2016-01-28 13:03:04 -0800
commitb5f2fda695bf450c2bb37bdc618bfbc604406bde (patch)
tree8a1070d53999932e07e6b69f29b5083c02258c5f
parent67a86c9e114593ce1d24ef7b8a943b86438c0e46 (diff)
downloadcoreclr-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.txt3
-rw-r--r--src/inc/cfi.h33
-rw-r--r--src/inc/clrnt.h1
-rw-r--r--src/inc/corjit.h2
-rw-r--r--src/jit/compiler.h19
-rw-r--r--src/jit/unwindamd64.cpp363
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