1 module d.rt.dwarf; 2 3 import d.rt.unwind; 4 5 alias uintptr_t = size_t; 6 7 enum Format { 8 Absptr = 0x00, 9 Uleb128 = 0x01, 10 Udata2 = 0x02, // unsigned 2-byte 11 Udata4 = 0x03, 12 Udata8 = 0x04, 13 Sleb128 = 0x09, 14 Sdata2 = 0x0a, 15 Sdata4 = 0x0b, 16 Sdata8 = 0x0c, 17 } 18 19 enum Base { 20 Absptr = 0x00, 21 Pcrel = 0x10, // relative to program counter 22 Textrel = 0x20, // relative to .text 23 Datarel = 0x30, // relative to .got or .eh_frame_hdr 24 Funcrel = 0x40, // relative to beginning of function 25 Aligned = 0x50, // is an aligned void* 26 } 27 28 struct Encoding { 29 private ubyte encoding; 30 31 enum Omit = 0xff; 32 enum Indirect = 0x80; 33 34 this(ubyte encoding) { 35 this.encoding = encoding; 36 } 37 38 Format getFormat() { 39 return cast(Format) (encoding & 0x0f); 40 } 41 42 Base getBase() { 43 return cast(Base) (encoding & 0x70); 44 } 45 46 bool isIndirect() { 47 return !!(encoding & Indirect); 48 } 49 50 bool isOmit() { 51 return encoding == Omit; 52 } 53 54 uint getSize() { 55 if (isOmit()) { 56 return 0; 57 } 58 59 switch (encoding & 0x07) { 60 case Format.Absptr: 61 // XXX: remove cast when VRP is in. 62 return cast(uint) size_t.sizeof; 63 64 case Format.Udata2: 65 return 2; 66 67 case Format.Udata4: 68 return 4; 69 70 case Format.Udata8: 71 return 8; 72 73 default: 74 assert(0); 75 } 76 } 77 } 78 79 uintptr_t read_uleb128(ref const(ubyte)* p) { 80 uintptr_t result = 0; 81 uint shift = 0; 82 ubyte b; 83 84 do { 85 b = *p++; 86 result |= (cast(uintptr_t) (b & 0x7f) << shift); 87 shift += 7; 88 } while (b & 0x80); 89 90 return result; 91 } 92 93 ptrdiff_t read_sleb128(ref const(ubyte)* p) { 94 uint shift = 0; 95 ubyte b; 96 ptrdiff_t result = 0; 97 98 do { 99 b = *p++; 100 result |= (cast(long) (b & 0x7f) << shift); 101 shift += 7; 102 } while (b & 0x80); 103 104 // Sign-extend if the value is negative. 105 if (shift < 8 * result.sizeof && (b & 0x40) != 0) { 106 result |= -(1L << shift); 107 } 108 109 return result; 110 } 111 112 ubyte read_ubyte(ref const(ubyte)* p) { 113 return *p++; 114 } 115 116 uintptr_t read_encoded(ref const(ubyte)* p, _Unwind_Context* ctx, 117 Encoding encoding) { 118 if (encoding.isOmit()) { 119 import core.stdc.stdlib, core.stdc.stdio; 120 printf("Encoding specifies omit flag, should not read.\n".ptr); 121 exit(-1); 122 } 123 124 auto pcrel = cast(uintptr_t) p; 125 uintptr_t result; 126 127 switch (encoding.getFormat()) { 128 case Format.Uleb128: 129 result = read_uleb128(p); 130 break; 131 132 case Format.Sleb128: 133 result = read_sleb128(p); 134 break; 135 136 case Format.Absptr: 137 result = *(cast(uintptr_t*) p); 138 p += uintptr_t.sizeof; 139 break; 140 141 case Format.Udata2: 142 result = *(cast(ushort*) p); 143 p += ushort.sizeof; 144 break; 145 146 case Format.Udata4: 147 result = *(cast(uint*) p); 148 p += uint.sizeof; 149 break; 150 151 case Format.Udata8: 152 result = cast(uintptr_t) *(cast(ulong*) p); 153 p += ulong.sizeof; 154 break; 155 156 case Format.Sdata2: 157 result = cast(uintptr_t) *(cast(short*) p); 158 p += short.sizeof; 159 break; 160 161 case Format.Sdata4: 162 result = cast(uintptr_t) *(cast(int*) p); 163 p += int.sizeof; 164 break; 165 166 case Format.Sdata8: 167 result = cast(uintptr_t) *(cast(long*) p); 168 p += long.sizeof; 169 break; 170 171 default: 172 import core.stdc.stdlib, core.stdc.stdio; 173 printf("FORMAT NOT SUPPORTED %d\n".ptr, encoding.getFormat()); 174 exit(-1); 175 } 176 177 switch (encoding.getBase()) { 178 case Base.Absptr: 179 case Base.Aligned: 180 break; 181 182 case Base.Pcrel: 183 result += pcrel; 184 break; 185 186 case Base.Textrel: 187 auto txt = _Unwind_GetTextRelBase(ctx); 188 result += cast(uintptr_t) txt; 189 break; 190 191 case Base.Datarel: 192 auto data = _Unwind_GetDataRelBase(ctx); 193 result += cast(uintptr_t) data; 194 break; 195 196 case Base.Funcrel: 197 auto region = _Unwind_GetRegionStart(ctx); 198 result += cast(uintptr_t) region; 199 break; 200 201 default: 202 import core.stdc.stdlib, core.stdc.stdio; 203 printf("BASE NOT SUPPORTED %d\n".ptr, encoding.getBase()); 204 exit(-1); 205 } 206 207 if (encoding.isIndirect()) { 208 result = *(cast(uintptr_t*) result); 209 } 210 211 return result; 212 } 213 214 struct LsdHeaderInfo { 215 _Unwind_Ptr start; 216 _Unwind_Ptr lpStart; 217 218 Encoding callSiteEncoding; 219 Encoding typeEncoding; 220 221 const(ubyte)* typeTable; 222 const(ubyte)* actionTable; 223 } 224 225 auto parseLsdHeader(ref const(ubyte)* p, _Unwind_Context* ctx) { 226 LsdHeaderInfo infos; 227 228 // infos.start = ctx ? _Unwind_GetRegionStart(ctx) : null; 229 if (ctx !is null) { 230 infos.start = _Unwind_GetRegionStart(ctx); 231 } 232 233 auto encoding = Encoding(*p++); 234 /+ 235 info.lpStart = encoding.isOmit() 236 ? infos.start 237 : read_encoded_value(p, ctx, encoding); 238 +/ 239 if (encoding.isOmit()) { 240 infos.lpStart = infos.start; 241 } else { 242 auto encoded = read_encoded(p, ctx, encoding); 243 infos.lpStart = cast(void*) encoded; 244 } 245 246 infos.typeEncoding = Encoding(*p++); 247 if (!infos.typeEncoding.isOmit()) { 248 auto tmp = read_uleb128(p); 249 infos.typeTable = p + tmp; 250 } 251 252 infos.callSiteEncoding = Encoding(*p++); 253 auto tmp = read_uleb128(p); 254 infos.actionTable = p + tmp; 255 256 return infos; 257 }