//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #include "Backend.h" #include "EhFrame.h" // AMD64 ABI -- DWARF register number mapping static const ubyte DWARF_RegNum[] = { // Exactly same order as RegList.h! -1, // NOREG, 0, // RAX, 2, // RCX, 1, // RDX, 3, // RBX, 7, // RSP, 6, // RBP, 4, // RSI, 5, // RDI, 8, // R8, 9, // R9, 10, // R10, 11, // R11, 12, // R12, 13, // R13, 14, // R14, 15, // R15, 17, // XMM0, 18, // XMM1, 19, // XMM2, 20, // XMM3, 21, // XMM4, 22, // XMM5, 23, // XMM6, 24, // XMM7, 25, // XMM8, 26, // XMM9, 27, // XMM10, 28, // XMM11, 29, // XMM12, 30, // XMM13, 31, // XMM14, 32, // XMM15, }; static const ubyte DWARF_RegRA = 16; ubyte GetDwarfRegNum(ubyte regNum) { return DWARF_RegNum[regNum]; } // Encode into ULEB128 (Unsigned Little Endian Base 128) BYTE* EmitLEB128(BYTE* pc, unsigned value) { do { BYTE b = value & 0x7F; // low order 7 bits value >>= 7; if (value) // more bytes to come { b |= 0x80; } *pc++ = b; } while (value != 0); return pc; } // Encode into signed LEB128 (Signed Little Endian Base 128) BYTE* EmitLEB128(BYTE* pc, int value) { static const int size = sizeof(value) * 8; static const bool isLogicShift = (-1 >> 1) != -1; const bool signExtend = isLogicShift && value < 0; bool more = true; while (more) { BYTE b = value & 0x7F; // low order 7 bits value >>= 7; if (signExtend) { value |= - (1 << (size - 7)); // sign extend } const bool signBit = (b & 0x40) != 0; if ((value == 0 && !signBit) || (value == -1 && signBit)) { more = false; } else { b |= 0x80; } *pc++ = b; } return pc; } void EhFrame::Entry::Begin() { Assert(beginOffset == -1); beginOffset = writer->Count(); // Write Length place holder const uword length = 0; writer->Write(length); } void EhFrame::Entry::End() { Assert(beginOffset != -1); // Must have called Begin() // padding size_t padding = (MachPtr - writer->Count() % MachPtr) % MachPtr; for (size_t i = 0; i < padding; i++) { cfi_nop(); } // update length record uword length = writer->Count() - beginOffset - sizeof(length); // exclude length itself writer->Write(beginOffset, length); } void EhFrame::Entry::cfi_advance(uword advance) { if (advance <= 0x3F) // 6-bits { cfi_advance_loc(static_cast(advance)); } else if (advance <= 0xFF) // 1-byte { cfi_advance_loc1(static_cast(advance)); } else if (advance <= 0xFFFF) // 2-byte { cfi_advance_loc2(static_cast(advance)); } else // 4-byte { cfi_advance_loc4(advance); } } void EhFrame::CIE::Begin() { Assert(writer->Count() == 0); Entry::Begin(); const uword cie_id = 0; Emit(cie_id); const ubyte version = 1; Emit(version); const ubyte augmentationString = 0; // none Emit(augmentationString); const ULEB128 codeAlignmentFactor = 1; Emit(codeAlignmentFactor); const LEB128 dataAlignmentFactor = - MachPtr; Emit(dataAlignmentFactor); const ubyte returnAddressRegister = DWARF_RegRA; Emit(returnAddressRegister); } void EhFrame::FDE::Begin() { Entry::Begin(); const uword cie_id = writer->Count(); Emit(cie_id); // Write pc placeholder pcBeginOffset = writer->Count(); const void* pc = nullptr; Emit(pc); Emit(pc); } void EhFrame::FDE::UpdateAddressRange(const void* pcBegin, size_t pcRange) { writer->Write(pcBeginOffset, pcBegin); writer->Write(pcBeginOffset + sizeof(pcBegin), reinterpret_cast(pcRange)); } EhFrame::EhFrame(BYTE* buffer, size_t size) : writer(buffer, size), fde(&writer) { CIE cie(&writer); cie.Begin(); // CIE initial instructions // DW_CFA_def_cfa: r7 (rsp) ofs 8 cie.cfi_def_cfa(DWARF_RegNum[LowererMDArch::GetRegStackPointer()], MachPtr); // DW_CFA_offset: r16 (rip) at cfa-8 (data alignment -8) cie.cfi_offset(DWARF_RegRA, 1); cie.End(); fde.Begin(); } void EhFrame::End() { fde.End(); // Write length 0 to mark terminate entry const uword terminate_entry_length = 0; writer.Write(terminate_entry_length); }