1 // Copyright Yazan Dabain 2014. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dwarf.debugabbrev; 7 8 // this implementation follows the DWARF v4 documentation 9 10 import std.exception; 11 import std.range; 12 import std.conv : to; 13 import dwarf.meta; 14 import dwarf.elf; 15 16 alias ULEB128 = ulong; 17 alias LEB128 = long; 18 19 struct Tag { 20 ULEB128 code; 21 TagEncoding name; 22 bool hasChildren; 23 Attribute[] attributes; 24 } 25 26 struct Attribute { 27 AttributeName name; 28 AttributeForm form; 29 } 30 31 struct DebugAbbrev { 32 private Tag[ULEB128] m_tags; // key is tag code 33 34 this(ubyte[] contents) { 35 while (true) { 36 // read tag 37 Tag tag; 38 tag.code = contents.readULEB128(); 39 if (tag.code == 0) break; // read all tags 40 tag.name = cast(TagEncoding) contents.readULEB128(); 41 tag.hasChildren = contents.read!bool(); 42 43 while (true) { 44 // read attributes 45 Attribute attr; 46 attr.name = cast(AttributeName) contents.readULEB128(); 47 attr.form = cast(AttributeForm) contents.readULEB128(); 48 49 if (attr.name == 0 && attr.form == 0) break; 50 tag.attributes ~= attr; 51 } 52 53 m_tags[tag.code] = tag; 54 } 55 } 56 57 @property const(Tag[ULEB128]) tags() const { return m_tags; } 58 } 59 60 private T read(T)(ref ubyte[] buffer) { 61 T result = *(cast(T*) buffer[0 .. T.sizeof].ptr); 62 buffer.popFrontExactly(T.sizeof); 63 return result; 64 } 65 66 private ulong readULEB128(ref ubyte[] buffer) { 67 import std.array; 68 ulong val = 0; 69 ubyte b; 70 uint shift = 0; 71 72 while (true) { 73 b = buffer.read!ubyte(); 74 75 val |= (b & 0x7f) << shift; 76 if ((b & 0x80) == 0) break; 77 shift += 7; 78 } 79 80 return val; 81 } 82 83 unittest { 84 ubyte[] data = [0xe5, 0x8e, 0x26, 0xDE, 0xAD, 0xBE, 0xEF]; 85 assert(readULEB128(data) == 624_485); 86 assert(data[] == [0xDE, 0xAD, 0xBE, 0xEF]); 87 } 88 89 private long readSLEB128(ref ubyte[] buffer) { 90 import std.array; 91 long val = 0; 92 uint shift = 0; 93 ubyte b; 94 int size = 8 << 3; 95 96 while (true) { 97 b = buffer.read!ubyte(); 98 val |= (b & 0x7f) << shift; 99 shift += 7; 100 if ((b & 0x80) == 0) 101 break; 102 } 103 104 if (shift < size && (b & 0x40) != 0) val |= -(1 << shift); 105 return val; 106 } 107 108 enum TagEncoding : ULEB128 { 109 arrayType = 0x01, 110 classType = 0x02, 111 entryPoint = 0x03, 112 enumerationType = 0x04, 113 formalParameter = 0x05, 114 importedDeclaration = 0x08, 115 label = 0x0a, 116 lexicalBlock = 0x0b, 117 member = 0x0d, 118 pointerType = 0x0f, 119 referenceType = 0x10, 120 compileUnit = 0x11, 121 stringType = 0x12, 122 structureType = 0x13, 123 subroutineType = 0x15, 124 typedef_ = 0x16, 125 unionType = 0x17, 126 unspecifiedParameters = 0x18, 127 variant = 0x19, 128 commonBlock = 0x1a, 129 commonInclusion = 0x1b, 130 inheritance = 0x1c, 131 inlinedSubroutine = 0x1d, 132 module_ = 0x1e, 133 ptrToMemberType = 0x1f, 134 setType = 0x20, 135 subrangeType = 0x21, 136 withStmt = 0x22, 137 accessDeclaration = 0x23, 138 baseType = 0x24, 139 catchBlock = 0x25, 140 constType = 0x26, 141 constant = 0x27, 142 enumerator = 0x28, 143 fileType = 0x29, 144 friend = 0x2a, 145 namelist = 0x2b, 146 namelistItem = 0x2c, 147 packedType = 0x2d, 148 subprogram = 0x2e, 149 templateTypeParameter = 0x2f, 150 templateValueParameter = 0x30, 151 thrownType = 0x31, 152 tryBlock = 0x32, 153 variantPart = 0x33, 154 variable = 0x34, 155 volatileType = 0x35, 156 157 // added in dwarf 3 { 158 dwarfProcedure = 0x36, 159 restrictType = 0x37, 160 interfaceType = 0x38, 161 namespace = 0x39, 162 importedModule = 0x3a, 163 unspecifiedType = 0x3b, 164 partialUnit = 0x3c, 165 importedUnit = 0x3d, 166 condition = 0x3f, 167 sharedType = 0x40, 168 // } end in dwarf 3 169 170 loUser = 0x4080, 171 hiUser = 0xffff, 172 } 173 174 enum AttributeName : ULEB128 { 175 sibling = 0x01, 176 location = 0x02, 177 name = 0x03, 178 ordering = 0x09, 179 byteSize = 0x0b, 180 bitOffset = 0x0c, 181 bitSize = 0x0d, 182 stmtList = 0x10, 183 lowPC = 0x11, 184 highPC = 0x12, 185 language = 0x13, 186 discr = 0x15, 187 discrValue = 0x16, 188 visibility = 0x17, 189 import_ = 0x18, 190 stringLength = 0x19, 191 commonReference = 0x1a, 192 compDir = 0x1b, 193 constValue = 0x1c, 194 containingType = 0x1d, 195 defaultValue = 0x1e, 196 inline = 0x20, 197 isOptional = 0x21, 198 lowerBound = 0x22, 199 producer = 0x25, 200 prototyped = 0x27, 201 returnAddr = 0x2a, 202 startScope = 0x2c, 203 bitStride = 0x2e, 204 upperBound = 0x2f, 205 abstractOrigin = 0x31, 206 accessibility = 0x32, 207 addressClass = 0x33, 208 artificial = 0x34, 209 baseTypes = 0x35, 210 callingConvention = 0x36, 211 count = 0x37, 212 dataMemberLocation = 0x38, 213 declColumn = 0x39, 214 declFile = 0x3a, 215 declLine = 0x3b, 216 declaration = 0x3c, 217 discrList = 0x3d, 218 encoding = 0x3e, 219 external = 0x3f, 220 frameBase = 0x40, 221 friend = 0x41, 222 identifierCase = 0x42, 223 macroInfo = 0x43, 224 namelistItem = 0x44, 225 priority = 0x45, 226 segment = 0x46, 227 specification = 0x47, 228 staticLink = 0x48, 229 type = 0x49, 230 useLocation = 0x4a, 231 variableParameter = 0x4b, 232 virtuality = 0x4c, 233 vtableElemLocation = 0x4d, 234 235 // added in dwarf 3 { 236 allocated = 0x4e, 237 associated = 0x4f, 238 dataLocation = 0x50, 239 byteStride = 0x51, 240 entryPc = 0x52, 241 useUTF8 = 0x53, 242 extension = 0x54, 243 ranges = 0x55, 244 trampoline = 0x56, 245 callColumn = 0x57, 246 callFile = 0x58, 247 callLine = 0x59, 248 description = 0x5a, 249 binaryScale = 0x5b, 250 decimalScale = 0x5c, 251 small = 0x5d, 252 decimalSign = 0x5e, 253 digitCount = 0x5f, 254 pictureString = 0x60, 255 mutable = 0x61, 256 threadsScaled = 0x62, 257 explicit = 0x63, 258 objectPointer = 0x64, 259 endianity = 0x65, 260 elemental = 0x66, 261 pure_ = 0x67, 262 recursive = 0x68, 263 // } end in dwarf 3 264 signature = 0x69, 265 mainSubprogram = 0x6a, 266 dataBitOffset = 0x6b, 267 constExpr = 0x6c, 268 enumClass = 0x6d, 269 linkageName = 0x6e, 270 271 loUser = 0x2000, 272 hiUser = 0x3fff, 273 } 274 275 enum AttributeForm : ULEB128 { 276 addr = 0x01, // size is defined in compile_unit 277 block2 = 0x03, // 2 byte length with payload 278 block4 = 0x04, // 4 byte length with payload 279 data2 = 0x05, // 2 bytes 280 data4 = 0x06, // 4 bytes 281 data8 = 0x07, // 8 bytes 282 string_ = 0x08, // null terminated string 283 block = 0x09, // a uleb128 length with payload 284 block1 = 0x0a, // 1 byte length with payload 285 data1 = 0x0b, // 1 byte 286 flag = 0x0c, // 1 byte 287 sdata = 0x0d, // sleb128 288 strp = 0x0e, // 4 byte reference to debug_str 289 udata = 0x0f, // uleb128 290 refAddr = 0x10, // 4 bytes in 32-bit dwarf, 8 bytes in 64 bit dwarf 291 ref1 = 0x11, // 1 byte ref 292 ref2 = 0x12, // 2 byte ref 293 ref4 = 0x13, // 4 byte ref 294 ref8 = 0x14, // 8 byte ref 295 refUdata = 0x15, // uleb128 ref 296 indirect = 0x16, // uleb128 encoding of the form 297 secOffset = 0x17, // 4 bytes in 32-bit dwarf, 8 bytes in 64 bit dwarf 298 exprLoc = 0x18, // uleb128 length with payload 299 flagPresent = 0x19, // no data but flag is always set 300 refSig8 = 0x20 // uleb128 ref 301 }