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