1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
#pragma once
#include "Utils/Bitwise.h"
#include "Registers.h"
namespace code {
namespace dwarf {
/**
* Definitions of some useful DWARF constants.
*/
#define DW_CFA_advance_loc 0x40 // + delta
#define DW_CFA_offset 0x80 // + register
#define DW_CFA_restore 0xC0 // + register
#define DW_CFA_nop 0x00
#define DW_CFA_set_loc 0x01
#define DW_CFA_advance_loc1 0x02
#define DW_CFA_advance_loc2 0x03
#define DW_CFA_advance_loc4 0x04
#define DW_CFA_offset_extended 0x05
#define DW_CFA_restore_extended 0x06
#define DW_CFA_undefined 0x07
#define DW_CFA_same_value 0x08
#define DW_CFA_register 0x09
#define DW_CFA_remember_state 0x0a
#define DW_CFA_restore_state 0x0b
#define DW_CFA_def_cfa 0x0c
#define DW_CFA_def_cfa_register 0x0d
#define DW_CFA_def_cfa_offset 0x0e
#define DW_CFA_def_cfa_expression 0x0f
#define DW_CFA_expression 0x10
#define DW_CFA_offset_extended_sf 0x11
#define DW_CFA_def_cfa_sf 0x12
#define DW_CFA_def_cfa_offset_sf 0x13
#define DW_CFA_val_offset 0x14
#define DW_CFA_val_offset_sf 0x15
#define DW_CFA_val_expression 0x16
#define DW_EH_PE_absptr 0x00
// Extensions specific to AARCH64 (ARM64)
#define DW_CFA_AARCH64_negate_ra_state 0x2D
#define DW_CFA_AARCH64_negate_ra_state_with_pc 0x2C
/**
* Output to a buffer in DWARF compatible format.
*/
struct DStream {
byte *to;
nat pos;
nat len;
// Initialize.
DStream(byte *to, nat len) : to(to), pos(0), len(len) {}
DStream(byte *to, nat len, nat pos) : to(to), pos(pos), len(len) {}
// Did we run out of space?
bool overflow() const {
return pos > len;
}
// Write a byte.
void putByte(byte b) {
if (pos < len)
to[pos] = b;
pos++;
}
// Write a pointer.
void putPtr(const void *value) {
if (pos + sizeof(value) <= len) {
const void **d = (const void **)&to[pos];
*d = value;
}
pos += sizeof(value);
}
// Write an unsigned number (encoded as LEB128).
void putUNum(nat value) {
while (value >= 0x80) {
putByte((value & 0x7F) | 0x80);
value >>= 7;
}
putByte(value & 0x7F);
}
// Write a signed number (encoded as LEB128).
void putSNum(int value) {
nat src = value;
nat bits = value;
if (value < 0) {
bits = ~bits; // make 'positive'
bits <<= 1; // make sure to get at least one sign bit in the output.
}
while (bits >= 0x80) {
putByte((src & 0x7F) | 0x80);
src >>= 7;
bits >>= 7;
}
putByte(src & 0x7F);
}
// Write OP-codes.
void putOp(byte op) {
putByte(op);
}
void putSOp(byte op, int p1) {
putByte(op);
putSNum(p1);
}
void putUOp(byte op, nat p1) {
putByte(op);
putUNum(p1);
}
void putSOp(byte op, int p1, int p2) {
putByte(op);
putSNum(p1);
putSNum(p2);
}
void putUOp(byte op, nat p1, nat p2) {
putByte(op);
putUNum(p1);
putUNum(p2);
}
// Encode the 'advance_loc' op-code.
void putAdvance(nat bytes) {
if (bytes <= 0x3F) {
putByte(DW_CFA_advance_loc + bytes);
} else if (bytes <= 0xFF) {
putByte(DW_CFA_advance_loc1);
putByte(bytes);
} else if (bytes <= 0xFFFF) {
putByte(DW_CFA_advance_loc2);
putByte(bytes & 0xFF);
putByte(bytes >> 8);
} else {
putByte(DW_CFA_advance_loc4);
putByte(bytes & 0xFF);
putByte((bytes & 0xFF00) >> 8);
putByte((bytes & 0xFF0000) >> 16);
putByte(bytes >> 24);
}
}
};
class FDEStream : public DStream {
public:
FDEStream(FDE *to, Nat &pos) : DStream(to->data, FDE_DATA), dest(pos) {
this->pos = dest;
}
~FDEStream() {
dest = pos;
dbg_assert(!overflow(), L"Increase FDE_DATA to at least " + ::toS(roundUp(pos, nat(sizeof(void *)))) + L"!");
}
Nat &dest;
};
class FDEIStream {
public:
FDEIStream(FDE *from) : data(from->data), len(FDE_DATA), pos(from->firstFree()) {}
Byte getByte() {
if (pos < len)
return data[pos++];
else
return 0x0;
}
Nat getUNum() {
Nat out = 0;
Nat shift = 0;
while (true) {
Byte b = getByte();
if (b & 0x80) {
out |= (b & 0x7F) << shift;
shift += 7;
} else {
out |= b << shift;
shift += 7;
break;
}
}
return out;
}
Int getSNum() {
Nat out = 0;
Nat shift = 0;
while (true) {
Byte b = getByte();
if (b & 0x80) {
out |= (b & 0x7F) << shift;
shift += 7;
} else {
out |= b << shift;
shift += 7;
break;
}
}
// Check if negative:
if (out >> (shift - 1)) {
// Yes, that means we need to add sign bits:
out |= Nat(0xFFFFFFFF) << shift;
}
return Int(out);
}
Bool atEnd() const {
return pos >= len;
}
private:
Byte *data;
Nat len;
Nat pos;
};
}
}
|