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 }