blob: 555021442523244dcf28288c251dd2d54e0abc67 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// 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<ubyte>(advance));
}
else if (advance <= 0xFF) // 1-byte
{
cfi_advance_loc1(static_cast<ubyte>(advance));
}
else if (advance <= 0xFFFF) // 2-byte
{
cfi_advance_loc2(static_cast<uword>(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 <begin, range> 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<const void*>(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);
}