blob: 812cf749abd342e75faab22f4042ca80960f1b49 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
typedef BYTE ubyte;
typedef uint16 uhalf;
typedef uint32 uword;
CompileAssert(sizeof(ubyte) == 1);
CompileAssert(sizeof(uhalf) == 2);
CompileAssert(sizeof(uword) == 4);
BYTE* EmitLEB128(BYTE* pc, unsigned value);
BYTE* EmitLEB128(BYTE* pc, int value);
ubyte GetDwarfRegNum(ubyte regNum);
template <class T>
class LEB128Wrapper
{
private:
T value;
public:
LEB128Wrapper(T value): value(value)
{}
BYTE* Write(BYTE* pc) const
{
return EmitLEB128(pc, value);
}
};
typedef LEB128Wrapper<unsigned> ULEB128;
typedef LEB128Wrapper<int> LEB128;
//
// EhFrame emits .eh_frame unwind data for our JIT code. We emit only one CIE
// followed by one FDE for each JIT function.
//
class EhFrame
{
// Simple buffer writer. Must operate on a buffer of sufficient size.
class Writer
{
private:
BYTE* buffer; // original buffer head
BYTE* cur; // current output position
const size_t size; // original size of buffer, for debug only
public:
Writer(BYTE* buffer, size_t size) : buffer(buffer), cur(buffer), size(size)
{}
// Write a value, and advance cur position
template <class T>
void Write(T value)
{
*reinterpret_cast<T*>(cur) = value;
cur += sizeof(value);
Assert(Count() <= size);
}
// Write a ULEB128 or LEB128 value, and advance cur position
template <class T>
void Write(const LEB128Wrapper<T>& leb128)
{
cur = leb128.Write(cur);
Assert(Count() <= size);
}
// Write a value at an absolute position
template <class T>
void Write(size_t offset, T value)
{
Assert(offset + sizeof(value) <= size);
*reinterpret_cast<T*>(buffer + offset) = value;
}
// Get original buffer head
BYTE* Buffer() const
{
return buffer;
}
// Get count of written bytes (== offset of cur position)
size_t Count() const
{
return cur - buffer;
}
};
// Base class for CIE and FDE
class Entry
{
protected:
Writer* writer;
size_t beginOffset; // where we'll update "length" record
// To limit supported value types
void Emit(ubyte value) { writer->Write(value); }
void Emit(uhalf value) { writer->Write(value); }
void Emit(uword value) { writer->Write(value); }
void Emit(const void* absptr) { writer->Write(absptr); }
void Emit(LEB128 value) { writer->Write(value); }
void Emit(ULEB128 value) { writer->Write(value); }
template <class T1>
void Emit(ubyte op, T1 arg1)
{
Emit(op);
Emit(arg1);
}
template <class T1, class T2>
void Emit(ubyte op, T1 arg1, T2 arg2)
{
Emit(op, arg1);
Emit(arg2);
}
public:
Entry(Writer* writer) : writer(writer), beginOffset(-1)
{}
void Begin();
void End();
#define ENTRY(name, op) \
void cfi_##name() \
{ Emit(static_cast<ubyte>(op)); }
#define ENTRY1(name, op, arg1_type) \
void cfi_##name(arg1_type arg1) \
{ Emit(op, arg1); }
#define ENTRY2(name, op, arg1_type, arg2_type) \
void cfi_##name(arg1_type arg1, arg2_type arg2) \
{ Emit(op, arg1, arg2); }
#define ENTRY_SM1(name, op, arg1_type) \
void cfi_##name(arg1_type arg1) \
{ Assert((arg1) <= 0x3F); Emit(static_cast<ubyte>((op) | arg1)); }
#define ENTRY_SM2(name, op, arg1_type, arg2_type) \
void cfi_##name(arg1_type arg1, arg2_type arg2) \
{ Assert((arg1) <= 0x3F); Emit((op) | arg1, arg2); }
#include "EhFrameCFI.inc"
void cfi_advance(uword advance);
};
// Common Information Entry
class CIE : public Entry
{
public:
CIE(Writer* writer) : Entry(writer)
{}
void Begin();
};
// Frame Description Entry
class FDE: public Entry
{
private:
size_t pcBeginOffset;
public:
FDE(Writer* writer) : Entry(writer)
{}
void Begin();
void UpdateAddressRange(const void* pcBegin, size_t pcRange);
};
private:
Writer writer;
FDE fde;
public:
EhFrame(BYTE* buffer, size_t size);
Writer* GetWriter()
{
return &writer;
}
FDE* GetFDE()
{
return &fde;
}
void End();
BYTE* Buffer() const
{
return writer.Buffer();
}
size_t Count() const
{
return writer.Count();
}
};