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 }