xref: /haiku/src/kits/debugger/dwarf/DwarfFile.cpp (revision 8497e566502bda506c22558a67f007c6c2e46fa9)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2012-2014, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "DwarfFile.h"
9 
10 #include <algorithm>
11 #include <new>
12 
13 #include <AutoDeleter.h>
14 #include <Entry.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <PathFinder.h>
18 
19 #include "AttributeClasses.h"
20 #include "AttributeValue.h"
21 #include "AbbreviationTable.h"
22 #include "CfaContext.h"
23 #include "CompilationUnit.h"
24 #include "DataReader.h"
25 #include "DwarfExpressionEvaluator.h"
26 #include "DwarfTargetInterface.h"
27 #include "ElfFile.h"
28 #include "TagNames.h"
29 #include "TargetAddressRangeList.h"
30 #include "Tracing.h"
31 #include "Variant.h"
32 
33 
34 // #pragma mark - AutoSectionPutter
35 
36 
37 class AutoSectionPutter {
38 public:
AutoSectionPutter(ElfFile * elfFile,ElfSection * elfSection)39 	AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection)
40 		:
41 		fElfFile(elfFile),
42 		fElfSection(elfSection)
43 	{
44 	}
45 
~AutoSectionPutter()46 	~AutoSectionPutter()
47 	{
48 		if (fElfSection != NULL)
49 			fElfFile->PutSection(fElfSection);
50 	}
51 
52 private:
53 	ElfFile*			fElfFile;
54 	ElfSection*			fElfSection;
55 };
56 
57 
58 // #pragma mark - ExpressionEvaluationContext
59 
60 
61 struct DwarfFile::ExpressionEvaluationContext
62 	: DwarfExpressionEvaluationContext {
63 public:
ExpressionEvaluationContextDwarfFile::ExpressionEvaluationContext64 	ExpressionEvaluationContext(DwarfFile* file, CompilationUnit* unit,
65 		uint8 addressSize, bool isBigEndian, DIESubprogram* subprogramEntry,
66 		const DwarfTargetInterface* targetInterface,
67 		target_addr_t instructionPointer, target_addr_t objectPointer,
68 		bool hasObjectPointer, target_addr_t framePointer,
69 		target_addr_t relocationDelta)
70 		:
71 		DwarfExpressionEvaluationContext(targetInterface, addressSize, isBigEndian,
72 			relocationDelta),
73 		fFile(file),
74 		fUnit(unit),
75 		fSubprogramEntry(subprogramEntry),
76 		fInstructionPointer(instructionPointer),
77 		fObjectPointer(objectPointer),
78 		fHasObjectPointer(hasObjectPointer),
79 		fFramePointer(framePointer),
80 		fFrameBasePointer(0),
81 		fFrameBaseEvaluated(false)
82 	{
83 	}
84 
GetObjectAddressDwarfFile::ExpressionEvaluationContext85 	virtual bool GetObjectAddress(target_addr_t& _address)
86 	{
87 		if (!fHasObjectPointer)
88 			return false;
89 
90 		_address = fObjectPointer;
91 		return true;
92 	}
93 
GetFrameAddressDwarfFile::ExpressionEvaluationContext94 	virtual bool GetFrameAddress(target_addr_t& _address)
95 	{
96 		if (fFramePointer == 0)
97 			return false;
98 
99 		_address = fFramePointer;
100 		return true;
101 	}
102 
GetFrameBaseAddressDwarfFile::ExpressionEvaluationContext103 	virtual bool GetFrameBaseAddress(target_addr_t& _address)
104 	{
105 		if (fFrameBaseEvaluated) {
106 			if (fFrameBasePointer == 0)
107 				return false;
108 
109 			_address = fFrameBasePointer;
110 			return true;
111 		}
112 
113 		// set flag already to prevent recursion for a buggy expression
114 		fFrameBaseEvaluated = true;
115 
116 		// get the subprogram's frame base location
117 		if (fSubprogramEntry == NULL)
118 			return false;
119 		const LocationDescription* location = fSubprogramEntry->FrameBase();
120 		if (!location->IsValid())
121 			return false;
122 
123 		// get the expression
124 		const void* expression;
125 		off_t expressionLength;
126 		status_t error = fFile->_GetLocationExpression(fUnit, location,
127 			fInstructionPointer, expression, expressionLength);
128 		if (error != B_OK)
129 			return false;
130 
131 		// evaluate the expression
132 		DwarfExpressionEvaluator evaluator(this);
133 		error = evaluator.Evaluate(expression, expressionLength,
134 			fFrameBasePointer);
135 		if (error != B_OK)
136 			return false;
137 
138 		TRACE_EXPR("  -> frame base: %" B_PRIx64 "\n", fFrameBasePointer);
139 
140 		_address = fFrameBasePointer;
141 		return true;
142 	}
143 
GetTLSAddressDwarfFile::ExpressionEvaluationContext144 	virtual bool GetTLSAddress(target_addr_t localAddress,
145 		target_addr_t& _address)
146 	{
147 		// TODO:...
148 		return false;
149 	}
150 
GetCallTargetDwarfFile::ExpressionEvaluationContext151 	virtual status_t GetCallTarget(uint64 offset, uint8 refType,
152 		const void*& _block, off_t& _size)
153 	{
154 		// resolve the entry
155 		DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType);
156 		if (entry == NULL)
157 			return B_ENTRY_NOT_FOUND;
158 
159 		// get the location description
160 		LocationDescription* location = entry->GetLocationDescription();
161 		if (location == NULL || !location->IsValid()) {
162 			_block = NULL;
163 			_size = 0;
164 			return B_OK;
165 		}
166 
167 		// get the expression
168 		return fFile->_GetLocationExpression(fUnit, location,
169 			fInstructionPointer, _block, _size);
170 	}
171 
172 private:
173 	DwarfFile*			fFile;
174 	CompilationUnit*	fUnit;
175 	DIESubprogram*		fSubprogramEntry;
176 	target_addr_t		fInstructionPointer;
177 	target_addr_t		fObjectPointer;
178 	bool				fHasObjectPointer;
179 	target_addr_t		fFramePointer;
180 	target_addr_t		fFrameBasePointer;
181 	bool				fFrameBaseEvaluated;
182 };
183 
184 
185 // #pragma mark - FDEAugmentation
186 
187 
188 struct DwarfFile::FDEAugmentation {
189 	// Currently we're ignoring all augmentation data.
190 };
191 
192 
193 // #pragma mark - CIEAugmentation
194 
195 
196 enum {
197 	CFI_AUGMENTATION_DATA					= 0x01,
198 	CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA	= 0x02,
199 	CFI_AUGMENTATION_PERSONALITY			= 0x04,
200 	CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT	= 0x08,
201 };
202 
203 
204 // encodings for CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT
205 enum {
206 	CFI_ADDRESS_FORMAT_ABSOLUTE			= 0x00,
207 	CFI_ADDRESS_FORMAT_UNSIGNED_LEB128	= 0x01,
208 	CFI_ADDRESS_FORMAT_UNSIGNED_16		= 0x02,
209 	CFI_ADDRESS_FORMAT_UNSIGNED_32		= 0x03,
210 	CFI_ADDRESS_FORMAT_UNSIGNED_64		= 0x04,
211 	CFI_ADDRESS_FORMAT_SIGNED			= 0x08,
212 	CFI_ADDRESS_FORMAT_SIGNED_LEB128	=
213 		CFI_ADDRESS_FORMAT_UNSIGNED_LEB128 | CFI_ADDRESS_FORMAT_SIGNED,
214 	CFI_ADDRESS_FORMAT_SIGNED_16		=
215 		CFI_ADDRESS_FORMAT_UNSIGNED_16 | CFI_ADDRESS_FORMAT_SIGNED,
216 	CFI_ADDRESS_FORMAT_SIGNED_32		=
217 		CFI_ADDRESS_FORMAT_UNSIGNED_32 | CFI_ADDRESS_FORMAT_SIGNED,
218 	CFI_ADDRESS_FORMAT_SIGNED_64		=
219 		CFI_ADDRESS_FORMAT_UNSIGNED_64 | CFI_ADDRESS_FORMAT_SIGNED
220 };
221 
222 
223 enum {
224 	CFI_ADDRESS_TYPE_PC_RELATIVE		= 0x10,
225 	CFI_ADDRESS_TYPE_TEXT_RELATIVE		= 0x20,
226 	CFI_ADDRESS_TYPE_DATA_RELATIVE		= 0x30,
227 	CFI_ADDRESS_TYPE_FUNCTION_RELATIVE	= 0x40,
228 	CFI_ADDRESS_TYPE_ALIGNED			= 0x50,
229 	CFI_ADDRESS_TYPE_INDIRECT			= 0x80
230 };
231 
232 
233 struct DwarfFile::CIEAugmentation {
CIEAugmentationDwarfFile::CIEAugmentation234 	CIEAugmentation()
235 		:
236 		fString(NULL),
237 		fFlags(0),
238 		fAddressEncoding(CFI_ADDRESS_FORMAT_ABSOLUTE)
239 	{
240 		// we default to absolute address format since that corresponds
241 		// to the DWARF standard for .debug_frame. In gcc's case, however,
242 		// .eh_frame will generally override that via augmentation 'R'
243 	}
244 
InitDwarfFile::CIEAugmentation245 	void Init(DataReader& dataReader)
246 	{
247 		fFlags = 0;
248 		fString = dataReader.ReadString();
249 	}
250 
ReadDwarfFile::CIEAugmentation251 	status_t Read(DataReader& dataReader)
252 	{
253 		if (fString == NULL || *fString == '\0')
254 			return B_OK;
255 
256 		if (*fString == 'z') {
257 			// There are augmentation data.
258 			fFlags |= CFI_AUGMENTATION_DATA;
259 			const char* string = fString + 1;
260 
261 			// read the augmentation data block -- it is preceeded by an
262 			// LEB128 indicating the length of the data block
263 			uint64 length = dataReader.ReadUnsignedLEB128(0);
264 			uint64 remaining = length;
265 			// let's see what data we have to expect
266 
267 			TRACE_CFI("    %" B_PRIu64 " bytes of augmentation data\n", length);
268 			while (*string != '\0') {
269 				switch (*string) {
270 					case 'L':
271 						fFlags |= CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA;
272 						dataReader.Read<char>(0);
273 						--remaining;
274 						break;
275 					case 'P':
276 					{
277 						char tempEncoding = fAddressEncoding;
278 						fAddressEncoding = dataReader.Read<char>(0);
279 						off_t offset = dataReader.Offset();
280 						ReadEncodedAddress(dataReader, NULL, NULL, true);
281 						fAddressEncoding = tempEncoding;
282 						remaining -= dataReader.Offset() - offset + 1;
283  						break;
284 					}
285 					case 'R':
286 						fFlags |= CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT;
287 						fAddressEncoding = dataReader.Read<char>(0);
288 						--remaining;
289 						break;
290 					default:
291 						WARNING("Encountered unsupported augmentation '%c' "
292 							" while parsing CIE augmentation string %s\n",
293 							*string, fString);
294 						return B_UNSUPPORTED;
295 				}
296 				string++;
297 			}
298 
299 			// we should have read through all of the augmentation data
300 			// at this point, if not, something is wrong.
301 			if (remaining != 0 || dataReader.HasOverflow()) {
302 				WARNING("Error while reading CIE Augmentation, expected "
303 					"%" B_PRIu64 " bytes of augmentation data, but read "
304 					"%" B_PRIu64 " bytes.\n", length, length - remaining);
305 				return B_BAD_DATA;
306 			}
307 
308 			return B_OK;
309 		}
310 
311 		// nothing to do
312 		if (strcmp(fString, "eh") == 0)
313 			return B_OK;
314 
315 		// something we can't handle
316 		return B_UNSUPPORTED;
317 	}
318 
ReadFDEDataDwarfFile::CIEAugmentation319 	status_t ReadFDEData(DataReader& dataReader,
320 		FDEAugmentation& fdeAugmentation)
321 	{
322 		if (!HasData())
323 			return B_OK;
324 
325 		// read the augmentation data block -- it is preceeded by an LEB128
326 		// indicating the length of the data block
327 		uint64 length = dataReader.ReadUnsignedLEB128(0);
328 		dataReader.Skip(length);
329 			// TODO: Actually read what is interesting for us!
330 
331 		TRACE_CFI("    %" B_PRIu64 " bytes of augmentation data\n", length);
332 
333 		if (dataReader.HasOverflow())
334 			return B_BAD_DATA;
335 
336 		return B_OK;
337 	}
338 
StringDwarfFile::CIEAugmentation339 	const char* String() const
340 	{
341 		return fString;
342 	}
343 
HasDataDwarfFile::CIEAugmentation344 	bool HasData() const
345 	{
346 		return (fFlags & CFI_AUGMENTATION_DATA) != 0;
347 	}
348 
HasFDEAddressFormatDwarfFile::CIEAugmentation349 	bool HasFDEAddressFormat() const
350 	{
351 		return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0;
352 	}
353 
FDEAddressOffsetDwarfFile::CIEAugmentation354 	target_addr_t FDEAddressOffset(ElfFile* file,
355 		ElfSection* debugFrameSection) const
356 	{
357 		switch (FDEAddressType()) {
358 			case CFI_ADDRESS_FORMAT_ABSOLUTE:
359 				TRACE_CFI("FDE address format: absolute, ");
360 				return 0;
361 			case CFI_ADDRESS_TYPE_PC_RELATIVE:
362 				TRACE_CFI("FDE address format: PC relative, ");
363 				return debugFrameSection->LoadAddress();
364 			case CFI_ADDRESS_TYPE_FUNCTION_RELATIVE:
365 				TRACE_CFI("FDE address format: function relative, ");
366 				return 0;
367 			case CFI_ADDRESS_TYPE_TEXT_RELATIVE:
368 				TRACE_CFI("FDE address format: text relative, ");
369 				return file->TextSegment()->LoadAddress();
370 			case CFI_ADDRESS_TYPE_DATA_RELATIVE:
371 				TRACE_CFI("FDE address format: data relative, ");
372 				return file->DataSegment()->LoadAddress();
373 			case CFI_ADDRESS_TYPE_ALIGNED:
374 			case CFI_ADDRESS_TYPE_INDIRECT:
375 				TRACE_CFI("FDE address format: UNIMPLEMENTED, ");
376 				// TODO: implement
377 				// -- note: type indirect is currently not generated
378 				return 0;
379 		}
380 
381 		return 0;
382 	}
383 
FDEAddressTypeDwarfFile::CIEAugmentation384 	uint8 FDEAddressType() const
385 	{
386 		return fAddressEncoding & 0x70;
387 	}
388 
ReadEncodedAddressDwarfFile::CIEAugmentation389 	target_addr_t ReadEncodedAddress(DataReader &reader,
390 		ElfFile* file, ElfSection* debugFrameSection,
391 		bool valueOnly = false) const
392 	{
393 		target_addr_t address = valueOnly ? 0 : FDEAddressOffset(file,
394 			debugFrameSection);
395 		switch (fAddressEncoding & 0x0f) {
396 			case CFI_ADDRESS_FORMAT_ABSOLUTE:
397 				address += reader.ReadAddress(0);
398 				TRACE_CFI(" target address: %" B_PRId64 "\n", address);
399 				break;
400 			case CFI_ADDRESS_FORMAT_UNSIGNED_LEB128:
401 				address += reader.ReadUnsignedLEB128(0);
402 				TRACE_CFI(" unsigned LEB128: %" B_PRId64 "\n", address);
403 				break;
404 			case CFI_ADDRESS_FORMAT_SIGNED_LEB128:
405 				address += reader.ReadSignedLEB128(0);
406 				TRACE_CFI(" signed LEB128: %" B_PRId64 "\n", address);
407 				break;
408 			case CFI_ADDRESS_FORMAT_UNSIGNED_16:
409 				address += reader.Read<uint16>(0);
410 				TRACE_CFI(" unsigned 16-bit: %" B_PRId64 "\n", address);
411 				break;
412 			case CFI_ADDRESS_FORMAT_SIGNED_16:
413 				address += reader.Read<int16>(0);
414 				TRACE_CFI(" signed 16-bit: %" B_PRId64 "\n", address);
415 				break;
416 			case CFI_ADDRESS_FORMAT_UNSIGNED_32:
417 				address += reader.Read<uint32>(0);
418 				TRACE_CFI(" unsigned 32-bit: %" B_PRId64 "\n", address);
419 				break;
420 			case CFI_ADDRESS_FORMAT_SIGNED_32:
421 				address += reader.Read<int32>(0);
422 				TRACE_CFI(" signed 32-bit: %" B_PRId64 "\n", address);
423 				break;
424 			case CFI_ADDRESS_FORMAT_UNSIGNED_64:
425 				address += reader.Read<uint64>(0);
426 				TRACE_CFI(" unsigned 64-bit: %" B_PRId64 "\n", address);
427 				break;
428 			case CFI_ADDRESS_FORMAT_SIGNED_64:
429 				address += reader.Read<int64>(0);
430 				TRACE_CFI(" signed 64-bit: %" B_PRId64 "\n", address);
431 				break;
432 		}
433 
434 		return address;
435 	}
436 
437 
438 private:
439 	const char*	fString;
440 	uint32		fFlags;
441 	int8		fAddressEncoding;
442 };
443 
444 
445 // #pragma mark - FDELookupInfo
446 
447 
448 struct DwarfFile::FDELookupInfo {
449 public:
FDELookupInfoDwarfFile::FDELookupInfo450 	FDELookupInfo(target_addr_t start, target_addr_t end,
451 		uint64 fdeOffset, uint64 cieOffset, bool ehFrame)
452 	:
453 	start(start),
454 	end(end),
455 	fdeOffset(fdeOffset),
456 	cieOffset(cieOffset),
457 	ehFrame(ehFrame)
458 	{
459 	}
460 
CompareFDEInfosDwarfFile::FDELookupInfo461 	static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b)
462 	{
463 		if (a->start < b->start)
464 			return -1;
465 		else if (a->start > b->start)
466 			return 1;
467 
468 		return 0;
469 	}
470 
ContainsAddressDwarfFile::FDELookupInfo471 	inline bool ContainsAddress(target_addr_t address) const
472 	{
473 		return address >= start && address < end;
474 	}
475 
476 	target_addr_t 		start;
477 	target_addr_t 		end;
478 	uint64				fdeOffset;
479 	uint64				cieOffset;
480 	bool				ehFrame;
481 };
482 
483 
484 // #pragma mark - DwarfFile
485 
486 
DwarfFile()487 DwarfFile::DwarfFile()
488 	:
489 	fName(NULL),
490 	fAlternateName(NULL),
491 	fElfFile(NULL),
492 	fAlternateElfFile(NULL),
493 	fDebugInfoSection(NULL),
494 	fDebugAbbrevSection(NULL),
495 	fDebugAddressSection(NULL),
496 	fDebugStringSection(NULL),
497 	fDebugStrOffsetsSection(NULL),
498 	fDebugRangesSection(NULL),
499 	fDebugLineSection(NULL),
500 	fDebugLineStrSection(NULL),
501 	fDebugFrameSection(NULL),
502 	fEHFrameSection(NULL),
503 	fDebugLocationSection(NULL),
504 	fDebugPublicTypesSection(NULL),
505 	fDebugTypesSection(NULL),
506 	fCompilationUnits(20, true),
507 	fTypeUnits(),
508 	fDebugFrameInfos(100, true),
509 	fEHFrameInfos(100, true),
510 	fTypesSectionRequired(false),
511 	fFinished(false),
512 	fItaniumEHFrameFormat(false),
513 	fFinishError(B_OK)
514 {
515 }
516 
517 
~DwarfFile()518 DwarfFile::~DwarfFile()
519 {
520 	while (AbbreviationTable* table = fAbbreviationTables.RemoveHead())
521 		delete table;
522 
523 	if (fElfFile != NULL) {
524 		ElfFile* debugInfoFile = fAlternateElfFile != NULL
525 			? fAlternateElfFile : fElfFile;
526 
527 		debugInfoFile->PutSection(fDebugInfoSection);
528 		debugInfoFile->PutSection(fDebugAbbrevSection);
529 		debugInfoFile->PutSection(fDebugAddressSection);
530 		debugInfoFile->PutSection(fDebugStringSection);
531 		debugInfoFile->PutSection(fDebugStrOffsetsSection);
532 		debugInfoFile->PutSection(fDebugRangesSection);
533 		debugInfoFile->PutSection(fDebugLineSection);
534 		debugInfoFile->PutSection(fDebugLineStrSection);
535 		debugInfoFile->PutSection(fDebugFrameSection);
536 		fElfFile->PutSection(fEHFrameSection);
537 		debugInfoFile->PutSection(fDebugLocationSection);
538 		debugInfoFile->PutSection(fDebugPublicTypesSection);
539 		delete fElfFile;
540 		delete fAlternateElfFile;
541 	}
542 
543 	TypeUnitTableEntry* entry = fTypeUnits.Clear(true);
544 	while (entry != NULL) {
545 		TypeUnitTableEntry* nextEntry = entry->next;
546 		delete entry;
547 		entry = nextEntry;
548 	}
549 
550 	free(fName);
551 	free(fAlternateName);
552 }
553 
554 
555 status_t
StartLoading(const char * fileName,BString & _requiredExternalFile)556 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
557 {
558 	fName = strdup(fileName);
559 	if (fName == NULL)
560 		return B_NO_MEMORY;
561 
562 	status_t error = fTypeUnits.Init();
563 	if (error != B_OK)
564 		return error;
565 
566 	// load the ELF file
567 	fElfFile = new(std::nothrow) ElfFile;
568 	if (fElfFile == NULL)
569 		return B_NO_MEMORY;
570 
571 	error = fElfFile->Init(fileName);
572 	if (error != B_OK)
573 		return error;
574 
575 	return _LocateDebugInfo(_requiredExternalFile);
576 }
577 
578 
579 status_t
Load(uint8 addressSize,bool isBigEndian,const BString & externalInfoFilePath)580 DwarfFile::Load(uint8 addressSize, bool isBigEndian, const BString& externalInfoFilePath)
581 {
582 	status_t error = B_OK;
583 	if (fDebugInfoSection == NULL) {
584 		BString path;
585 		error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty()
586 				? NULL : externalInfoFilePath.String());
587 		if (error != B_OK)
588 			return error;
589 	}
590 
591 	ElfFile* debugInfoFile = fAlternateElfFile != NULL
592 		? fAlternateElfFile : fElfFile;
593 
594 	// non mandatory sections
595 	fDebugAddressSection = debugInfoFile->GetSection(".debug_addr");
596 	fDebugStringSection = debugInfoFile->GetSection(".debug_str");
597 	fDebugStrOffsetsSection = debugInfoFile->GetSection(".debug_str_offsets");
598 	fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
599 	fDebugLineSection = debugInfoFile->GetSection(".debug_line");
600 	fDebugLineStrSection = debugInfoFile->GetSection(".debug_line_str");
601 	fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
602 
603 	if (fDebugFrameSection != NULL) {
604 		error = _ParseFrameSection(fDebugFrameSection,
605 			addressSize, isBigEndian,
606 			false, fDebugFrameInfos);
607 		if (error != B_OK)
608 			return error;
609 	}
610 
611 	// .eh_frame doesn't appear to get copied into separate debug
612 	// info files properly, therefore always use it off the main
613 	// executable image
614 	if (fEHFrameSection == NULL)
615 		fEHFrameSection = fElfFile->GetSection(".eh_frame");
616 
617 	if (fEHFrameSection != NULL) {
618 		error = _ParseFrameSection(fEHFrameSection,
619 			addressSize, isBigEndian,
620 			true, fEHFrameInfos);
621 		if (error != B_OK)
622 			return error;
623 	}
624 
625 	fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
626 	fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
627 
628 	if (fDebugInfoSection == NULL) {
629 		fFinished = true;
630 		return B_OK;
631 	}
632 
633 	error = _ParseDebugInfoSection(addressSize, isBigEndian);
634 	if (error != B_OK)
635 		return error;
636 
637 	if (fTypesSectionRequired) {
638 		fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
639 		if (fDebugTypesSection == NULL) {
640 			WARNING(".debug_types section required but missing.\n");
641 			return B_BAD_DATA;
642 		}
643 		error = _ParseTypesSection(addressSize, isBigEndian);
644 		if (error != B_OK)
645 			return error;
646 	}
647 
648 	return B_OK;
649 }
650 
651 
652 status_t
FinishLoading(uint8 addressSize,bool isBigEndian)653 DwarfFile::FinishLoading(uint8 addressSize, bool isBigEndian)
654 {
655 	if (fFinished)
656 		return B_OK;
657 	if (fFinishError != B_OK)
658 		return fFinishError;
659 
660 	status_t error;
661 	for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator();
662 		TypeUnitTableEntry* entry = it.Next();) {
663 		error = _FinishUnit(entry->unit);
664 		if (error != B_OK)
665 			return fFinishError = error;
666 	}
667 
668 	for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
669 			i++) {
670 		error = _FinishUnit(unit);
671 		if (error != B_OK)
672 			return fFinishError = error;
673 	}
674 
675 	_ParsePublicTypesInfo(addressSize, isBigEndian);
676 
677 	fFinished = true;
678 	return B_OK;
679 }
680 
681 
682 int32
CountCompilationUnits() const683 DwarfFile::CountCompilationUnits() const
684 {
685 	return fCompilationUnits.CountItems();
686 }
687 
688 
689 CompilationUnit*
CompilationUnitAt(int32 index) const690 DwarfFile::CompilationUnitAt(int32 index) const
691 {
692 	return fCompilationUnits.ItemAt(index);
693 }
694 
695 
696 CompilationUnit*
CompilationUnitForDIE(const DebugInfoEntry * entry) const697 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const
698 {
699 	// find the root of the tree the entry lives in
700 	while (entry != NULL && entry->Parent() != NULL)
701 		entry = entry->Parent();
702 
703 	// that should be the compilation unit entry
704 	const DIECompileUnitBase* unitEntry
705 		= dynamic_cast<const DIECompileUnitBase*>(entry);
706 	if (unitEntry == NULL)
707 		return NULL;
708 
709 	// find the compilation unit
710 	for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
711 			i++) {
712 		if (unit->UnitEntry() == unitEntry)
713 			return unit;
714 	}
715 
716 	return NULL;
717 }
718 
719 
720 TargetAddressRangeList*
ResolveRangeList(CompilationUnit * unit,uint64 offset) const721 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
722 {
723 	if (unit == NULL || fDebugRangesSection == NULL)
724 		return NULL;
725 
726 	if (offset >= (uint64)fDebugRangesSection->Size())
727 		return NULL;
728 
729 	TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList;
730 	if (ranges == NULL) {
731 		ERROR("Out of memory.\n");
732 		return NULL;
733 	}
734 	BReference<TargetAddressRangeList> rangesReference(ranges, true);
735 
736 	target_addr_t baseAddress = unit->AddressRangeBase();
737 	target_addr_t maxAddress = unit->MaxAddress();
738 
739 	DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset,
740 		fDebugRangesSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
741 	while (true) {
742 		target_addr_t start = dataReader.ReadAddress(0);
743 		target_addr_t end = dataReader.ReadAddress(0);
744 		if (dataReader.HasOverflow())
745 			return NULL;
746 
747 		if (start == 0 && end == 0)
748 			break;
749 		if (start == maxAddress) {
750 			baseAddress = end;
751 			continue;
752 		}
753 		if (start == end)
754 			continue;
755 
756 		if (!ranges->AddRange(baseAddress + start, end - start)) {
757 			ERROR("Out of memory.\n");
758 			return NULL;
759 		}
760 	}
761 
762 	return rangesReference.Detach();
763 }
764 
765 
766 status_t
UnwindCallFrame(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,target_addr_t location,const DwarfTargetInterface * inputInterface,DwarfTargetInterface * outputInterface,target_addr_t & _framePointer)767 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
768 	DIESubprogram* subprogramEntry, target_addr_t location,
769 	const DwarfTargetInterface* inputInterface,
770 	DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
771 {
772 	FDELookupInfo* info = _GetContainingFDEInfo(location);
773 	if (info == NULL)
774 		return B_ENTRY_NOT_FOUND;
775 
776 	return _UnwindCallFrame(unit, addressSize, isBigEndian,
777 		subprogramEntry, location, info,
778 		inputInterface, outputInterface, _framePointer);
779 }
780 
781 
782 status_t
EvaluateExpression(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const void * expression,off_t expressionLength,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,target_addr_t valueToPush,bool pushValue,target_addr_t & _result)783 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
784 	DIESubprogram* subprogramEntry, const void* expression,
785 	off_t expressionLength, const DwarfTargetInterface* targetInterface,
786 	target_addr_t instructionPointer, target_addr_t framePointer,
787 	target_addr_t valueToPush, bool pushValue, target_addr_t& _result)
788 {
789 	ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian,
790 		subprogramEntry, targetInterface, instructionPointer, 0, false,
791 		framePointer, 0);
792 	DwarfExpressionEvaluator evaluator(&context);
793 
794 	if (pushValue && evaluator.Push(valueToPush) != B_OK)
795 		return B_NO_MEMORY;
796 
797 	return evaluator.Evaluate(expression, expressionLength, _result);
798 }
799 
800 
801 status_t
ResolveLocation(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const LocationDescription * location,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t objectPointer,bool hasObjectPointer,target_addr_t framePointer,target_addr_t relocationDelta,ValueLocation & _result)802 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
803 	DIESubprogram* subprogramEntry, const LocationDescription* location,
804 	const DwarfTargetInterface* targetInterface,
805 	target_addr_t instructionPointer, target_addr_t objectPointer,
806 	bool hasObjectPointer, target_addr_t framePointer,
807 	target_addr_t relocationDelta, ValueLocation& _result)
808 {
809 	// get the expression
810 	const void* expression;
811 	off_t expressionLength;
812 	status_t error = _GetLocationExpression(unit, location, instructionPointer,
813 		expression, expressionLength);
814 	if (error != B_OK)
815 		return error;
816 
817 	// evaluate it
818 	ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian,
819 		subprogramEntry, targetInterface, instructionPointer, objectPointer,
820 		hasObjectPointer, framePointer, relocationDelta);
821 	DwarfExpressionEvaluator evaluator(&context);
822 	return evaluator.EvaluateLocation(expression, expressionLength,
823 		_result);
824 }
825 
826 
827 status_t
EvaluateConstantValue(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const ConstantAttributeValue * value,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,BVariant & _result)828 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
829 	DIESubprogram* subprogramEntry, const ConstantAttributeValue* value,
830 	const DwarfTargetInterface* targetInterface,
831 	target_addr_t instructionPointer, target_addr_t framePointer,
832 	BVariant& _result)
833 {
834 	if (!value->IsValid())
835 		return B_BAD_VALUE;
836 
837 	switch (value->attributeClass) {
838 		case ATTRIBUTE_CLASS_CONSTANT:
839 			_result.SetTo(value->constant);
840 			return B_OK;
841 		case ATTRIBUTE_CLASS_STRING:
842 			_result.SetTo(value->string);
843 			return B_OK;
844 		case ATTRIBUTE_CLASS_BLOCK:
845 		{
846 			target_addr_t result;
847 			status_t error = EvaluateExpression(unit, addressSize, isBigEndian,
848 				subprogramEntry, value->block.data, value->block.length,
849 				targetInterface, instructionPointer, framePointer, 0, false,
850 				result);
851 			if (error != B_OK)
852 				return error;
853 
854 			_result.SetTo(result);
855 			return B_OK;
856 		}
857 		default:
858 			return B_BAD_VALUE;
859 	}
860 }
861 
862 
863 status_t
EvaluateDynamicValue(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const DynamicAttributeValue * value,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,BVariant & _result,DIEType ** _type)864 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
865 	DIESubprogram* subprogramEntry, const DynamicAttributeValue* value,
866 	const DwarfTargetInterface* targetInterface,
867 	target_addr_t instructionPointer, target_addr_t framePointer,
868 	BVariant& _result, DIEType** _type)
869 {
870 	if (!value->IsValid())
871 		return B_BAD_VALUE;
872 
873 	DIEType* dummyType;
874 	if (_type == NULL)
875 		_type = &dummyType;
876 
877 	switch (value->attributeClass) {
878 		case ATTRIBUTE_CLASS_CONSTANT:
879 			_result.SetTo(value->constant);
880 			*_type = NULL;
881 			return B_OK;
882 
883 		case ATTRIBUTE_CLASS_REFERENCE:
884 		{
885 			// TODO: The specs are a bit fuzzy on this one: "the value is a
886 			// reference to another entity whose value is the value of the
887 			// attribute". Supposedly that also means e.g. if the referenced
888 			// entity is a variable, we should read the value of that variable.
889 			// ATM we only check for the types that can have a DW_AT_const_value
890 			// attribute and evaluate it, if present.
891 			DebugInfoEntry* entry = value->reference;
892 			if (entry == NULL)
893 				return B_BAD_VALUE;
894 
895 			const ConstantAttributeValue* constantValue = NULL;
896 			DIEType* type = NULL;
897 
898 			switch (entry->Tag()) {
899 				case DW_TAG_constant:
900 				{
901 					DIEConstant* constantEntry
902 						= dynamic_cast<DIEConstant*>(entry);
903 					constantValue = constantEntry->ConstValue();
904 					type = constantEntry->GetType();
905 					break;
906 				}
907 				case DW_TAG_enumerator:
908 					constantValue = dynamic_cast<DIEEnumerator*>(entry)
909 						->ConstValue();
910 					if (DIEEnumerationType* enumerationType
911 							= dynamic_cast<DIEEnumerationType*>(
912 								entry->Parent())) {
913 						type = enumerationType->GetType();
914 					}
915 					break;
916 				case DW_TAG_formal_parameter:
917 				{
918 					DIEFormalParameter* parameterEntry
919 						= dynamic_cast<DIEFormalParameter*>(entry);
920 					constantValue = parameterEntry->ConstValue();
921 					type = parameterEntry->GetType();
922 					break;
923 				}
924 				case DW_TAG_template_value_parameter:
925 				{
926 					DIETemplateValueParameter* parameterEntry
927 						= dynamic_cast<DIETemplateValueParameter*>(entry);
928 					constantValue = parameterEntry->ConstValue();
929 					type = parameterEntry->GetType();
930 					break;
931 				}
932 				case DW_TAG_variable:
933 				{
934 					DIEVariable* variableEntry
935 						= dynamic_cast<DIEVariable*>(entry);
936 					constantValue = variableEntry->ConstValue();
937 					type = variableEntry->GetType();
938 					break;
939 				}
940 				default:
941 					return B_BAD_VALUE;
942 			}
943 
944 			if (constantValue == NULL || !constantValue->IsValid())
945 				return B_BAD_VALUE;
946 
947 			status_t error = EvaluateConstantValue(unit, addressSize, isBigEndian,
948 				subprogramEntry, constantValue, targetInterface,
949 				instructionPointer, framePointer, _result);
950 			if (error != B_OK)
951 				return error;
952 
953 			*_type = type;
954 			return B_OK;
955 		}
956 
957 		case ATTRIBUTE_CLASS_BLOCK:
958 		{
959 			target_addr_t result;
960 			status_t error = EvaluateExpression(unit, addressSize, isBigEndian,
961 				subprogramEntry, value->block.data, value->block.length,
962 				targetInterface, instructionPointer, framePointer, 0, false,
963 				result);
964 			if (error != B_OK)
965 				return error;
966 
967 			_result.SetTo(result);
968 			*_type = NULL;
969 			return B_OK;
970 		}
971 
972 		default:
973 			return B_BAD_VALUE;
974 	}
975 }
976 
977 
978 status_t
_ParseDebugInfoSection(uint8 _addressSize,bool isBigEndian)979 DwarfFile::_ParseDebugInfoSection(uint8 _addressSize, bool isBigEndian)
980 {
981 	// iterate through the debug info section
982 	DataReader dataReader(fDebugInfoSection->Data(),
983 		fDebugInfoSection->Size(), _addressSize, isBigEndian);
984 
985 	while (dataReader.HasData()) {
986 		off_t unitHeaderOffset = dataReader.Offset();
987 		bool dwarf64;
988 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
989 
990 		off_t unitLengthOffset = dataReader.Offset();
991 			// the unitLength starts here
992 
993 		if (unitLengthOffset + unitLength
994 				> (uint64)fDebugInfoSection->Size()) {
995 			WARNING("\"%s\": Invalid compilation unit length.\n", fName);
996 			break;
997 		}
998 
999 		int version = dataReader.Read<uint16>(0);
1000 		if (version >= 5) {
1001 			uint8 unitType = dataReader.Read<uint8>(0);
1002 			if (unitType != DW_UT_compile) {
1003 				WARNING("\"%s\": Unsupported unit type %d\n",
1004 					fName, unitType);
1005 				return B_UNSUPPORTED;
1006 			}
1007 		}
1008 
1009 		off_t abbrevOffset;
1010 		uint8 addressSize;
1011 
1012 		if (version >= 5) {
1013 			addressSize = dataReader.Read<uint8>(0);
1014 			abbrevOffset = dwarf64
1015 				? dataReader.Read<uint64>(0)
1016 				: dataReader.Read<uint32>(0);
1017 		} else {
1018 			abbrevOffset = dwarf64
1019 				? dataReader.Read<uint64>(0)
1020 				: dataReader.Read<uint32>(0);
1021 			addressSize = dataReader.Read<uint8>(0);
1022 		}
1023 
1024 		if (dataReader.HasOverflow()) {
1025 			WARNING("\"%s\": Unexpected end of data in compilation unit "
1026 				"header.\n", fName);
1027 			break;
1028 		}
1029 
1030 		TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
1031 			", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
1032 			dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
1033 
1034 		if (version < 2 || version > 4) {
1035 			WARNING("\"%s\": Unsupported compilation unit version: %d\n",
1036 				fName, version);
1037 			break;
1038 		}
1039 
1040 		if (addressSize != 4 && addressSize != 8) {
1041 			WARNING("\"%s\": Unsupported address size: %d\n", fName,
1042 				addressSize);
1043 			break;
1044 		}
1045 		dataReader.SetAddressSize(addressSize);
1046 
1047 		off_t unitContentOffset = dataReader.Offset();
1048 
1049 		// create a compilation unit object
1050 		CompilationUnit* unit = new(std::nothrow) CompilationUnit(
1051 			unitHeaderOffset, unitContentOffset,
1052 			unitLength + (unitLengthOffset - unitHeaderOffset),
1053 			abbrevOffset, addressSize, isBigEndian, dwarf64);
1054 		if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
1055 			delete unit;
1056 			return B_NO_MEMORY;
1057 		}
1058 
1059 		// parse the debug info for the unit
1060 		status_t error = _ParseCompilationUnit(unit);
1061 		if (error != B_OK)
1062 			return error;
1063 
1064 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1065 	}
1066 
1067 	return B_OK;
1068 }
1069 
1070 
1071 status_t
_ParseTypesSection(uint8 _addressSize,bool isBigEndian)1072 DwarfFile::_ParseTypesSection(uint8 _addressSize, bool isBigEndian)
1073 {
1074 	DataReader dataReader(fDebugTypesSection->Data(),
1075 		fDebugTypesSection->Size(), _addressSize, isBigEndian);
1076 	while (dataReader.HasData()) {
1077 		off_t unitHeaderOffset = dataReader.Offset();
1078 		bool dwarf64;
1079 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1080 
1081 		off_t unitLengthOffset = dataReader.Offset();
1082 			// the unitLength starts here
1083 
1084 		if (unitLengthOffset + unitLength
1085 				> (uint64)fDebugTypesSection->Size()) {
1086 			WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n",
1087 				unitHeaderOffset);
1088 			break;
1089 		}
1090 
1091 		int version = dataReader.Read<uint16>(0);
1092 		off_t abbrevOffset = dwarf64
1093 			? dataReader.Read<uint64>(0)
1094 			: dataReader.Read<uint32>(0);
1095 		uint8 addressSize = dataReader.Read<uint8>(0);
1096 
1097 		if (dataReader.HasOverflow()) {
1098 			WARNING("Unexpected end of data in type unit header at %#"
1099 				B_PRIx64 ".\n", unitHeaderOffset);
1100 			break;
1101 		}
1102 
1103 		dataReader.SetAddressSize(addressSize);
1104 
1105 		uint64 signature = dataReader.Read<uint64>(0);
1106 
1107 		off_t typeOffset = dwarf64
1108 			? dataReader.Read<uint64>(0)
1109 			: dataReader.Read<uint32>(0);
1110 
1111 		off_t unitContentOffset = dataReader.Offset();
1112 
1113 		TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64
1114 			", abbrevOffset: %" B_PRIdOFF ", address size: %d, "
1115 			"signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n",
1116 			dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize,
1117 			signature, typeOffset);
1118 
1119 		if (version > 4) {
1120 			WARNING("\"%s\": Unsupported type unit version: %d\n",
1121 				fName, version);
1122 			break;
1123 		}
1124 
1125 		if (addressSize != 4 && addressSize != 8) {
1126 			WARNING("\"%s\": Unsupported address size: %d\n", fName,
1127 				addressSize);
1128 			break;
1129 		}
1130 
1131 		// create a type unit object
1132 		TypeUnit* unit = new(std::nothrow) TypeUnit(
1133 			unitHeaderOffset, unitContentOffset,
1134 			unitLength + (unitLengthOffset - unitHeaderOffset),
1135 			abbrevOffset, typeOffset, addressSize, isBigEndian,
1136 			signature, dwarf64);
1137 		if (unit == NULL)
1138 			return B_NO_MEMORY;
1139 
1140 		// parse the debug info for the unit
1141 		status_t error = _ParseTypeUnit(unit);
1142 		if (error != B_OK)
1143 			return error;
1144 
1145 		// TODO: it should theoretically never happen that we get a duplicate,
1146 		// but it wouldn't hurt to check since that situation would potentially
1147 		// be problematic.
1148 		if (fTypeUnits.Lookup(signature) == NULL) {
1149 			TypeUnitTableEntry* entry = new(std::nothrow)
1150 				TypeUnitTableEntry(signature, unit);
1151 			if (entry == NULL)
1152 				return B_NO_MEMORY;
1153 
1154 			fTypeUnits.Insert(entry);
1155 		}
1156 
1157 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1158 	}
1159 
1160 	return B_OK;
1161 }
1162 
1163 
1164 status_t
_ParseFrameSection(ElfSection * section,uint8 addressSize,bool isBigEndian,bool ehFrame,FDEInfoList & infos)1165 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize, bool isBigEndian,
1166 	bool ehFrame, FDEInfoList& infos)
1167 {
1168 	if (ehFrame) {
1169 		fItaniumEHFrameFormat = section->IsWritable();
1170 			// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
1171 			// .eh_frame sections. The ones generated by GCC 2 are writable,
1172 			// the ones generated by GCC 4 aren't.
1173 	}
1174 
1175 	DataReader dataReader((uint8*)section->Data(),
1176 		section->Size(), addressSize, isBigEndian);
1177 
1178 	while (dataReader.BytesRemaining() > 0) {
1179 		// length
1180 		bool dwarf64;
1181 		off_t entryOffset = dataReader.Offset();
1182 		uint64 length = dataReader.ReadInitialLength(dwarf64);
1183 
1184 		TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF
1185 			", length: %" B_PRId64 "\n", entryOffset, length);
1186 
1187 		if (length > (uint64)dataReader.BytesRemaining())
1188 			return B_BAD_DATA;
1189 		off_t lengthOffset = dataReader.Offset();
1190 
1191 		// If the length is 0, it means a terminator of the CIE.
1192 		// Then just skip this .debug_frame/.eh_frame section.
1193 		if (length == 0)
1194 			return B_OK;
1195 
1196 		// CIE ID/CIE pointer
1197 		uint64 cieID = dwarf64
1198 			? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1199 
1200 		// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
1201 		if (ehFrame
1202 			? cieID == 0
1203 			: (dwarf64
1204 				? cieID == 0xffffffffffffffffULL
1205 				: cieID == 0xffffffff)) {
1206 			// this is a CIE -- skip it
1207 		} else {
1208 			// this is a FDE
1209 			uint64 initialLocationOffset = dataReader.Offset();
1210 			// In .eh_frame the CIE offset is a relative back offset.
1211 			if (ehFrame) {
1212 				if (cieID > (uint64)lengthOffset) {
1213 					TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
1214 						"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
1215 					break;
1216 				}
1217 				// convert to a section relative offset
1218 				cieID = lengthOffset - cieID;
1219 			}
1220 
1221 
1222 			CfaContext context;
1223 			CIEAugmentation cieAugmentation;
1224 			// when using .eh_frame format, we need to parse the CIE's
1225 			// augmentation up front in order to know how the FDE's addresses
1226 			//  will be represented
1227 			DataReader cieReader;
1228 			off_t cieRemaining;
1229 			status_t error = _ParseCIEHeader(section, ehFrame, NULL,
1230 				addressSize, isBigEndian, context,
1231 				cieID, cieAugmentation, cieReader, cieRemaining);
1232 			if (error != B_OK)
1233 				return error;
1234 			if (cieReader.HasOverflow())
1235 				return B_BAD_DATA;
1236 			if (cieRemaining < 0)
1237 				return B_BAD_DATA;
1238 
1239 			target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
1240 				dataReader, fElfFile, section);
1241 			target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
1242 				dataReader, fElfFile, section, true);
1243 
1244 			if (dataReader.HasOverflow())
1245 				return B_BAD_DATA;
1246 
1247 			if ((cieAugmentation.FDEAddressType()
1248 					& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
1249 				initialLocation += initialLocationOffset;
1250 			}
1251 
1252 			// for unknown reasons, the debug frame sections generated by gcc
1253 			// sometimes contain duplicates at different offsets within the
1254 			// section. In such a case, simply skip the duplicates.
1255 			FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
1256 				infos);
1257 			if (temp == NULL) {
1258 				FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
1259 					initialLocation, initialLocation + addressRange - 1,
1260 					entryOffset, cieID, ehFrame);
1261 				if (info == NULL)
1262 					return B_NO_MEMORY;
1263 
1264 				ObjectDeleter<FDELookupInfo> infoDeleter(info);
1265 				if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
1266 					return B_NO_MEMORY;
1267 
1268 				infoDeleter.Detach();
1269 			}
1270 		}
1271 
1272 		dataReader.SeekAbsolute(lengthOffset + length);
1273 	}
1274 
1275 	return B_OK;
1276 }
1277 
1278 
1279 status_t
_ParseCompilationUnit(CompilationUnit * unit)1280 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
1281 {
1282 	AbbreviationTable* abbreviationTable;
1283 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1284 		abbreviationTable);
1285 	if (error != B_OK)
1286 		return error;
1287 
1288 	unit->SetAbbreviationTable(abbreviationTable);
1289 
1290 	DataReader dataReader(
1291 		(const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(),
1292 		unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian());
1293 
1294 	DebugInfoEntry* entry;
1295 	bool endOfEntryList;
1296 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1297 		endOfEntryList);
1298 	if (error != B_OK)
1299 		return error;
1300 
1301 	DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry);
1302 	if (unitEntry == NULL) {
1303 		WARNING("No compilation unit entry in .debug_info section.\n");
1304 		return B_BAD_DATA;
1305 	}
1306 
1307 	unit->SetUnitEntry(unitEntry);
1308 
1309 	TRACE_DIE_ONLY(
1310 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1311 			dataReader.BytesRemaining());
1312 		if (dataReader.HasData()) {
1313 			TRACE_DIE("  ");
1314 			while (dataReader.HasData())
1315 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1316 			TRACE_DIE("\n");
1317 		}
1318 	)
1319 	return B_OK;
1320 }
1321 
1322 
1323 status_t
_ParseTypeUnit(TypeUnit * unit)1324 DwarfFile::_ParseTypeUnit(TypeUnit* unit)
1325 {
1326 	AbbreviationTable* abbreviationTable;
1327 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1328 		abbreviationTable);
1329 	if (error != B_OK)
1330 		return error;
1331 
1332 	unit->SetAbbreviationTable(abbreviationTable);
1333 
1334 	DataReader dataReader(
1335 		(const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
1336 		unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian());
1337 
1338 	DebugInfoEntry* entry;
1339 	bool endOfEntryList;
1340 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1341 		endOfEntryList);
1342 	if (error != B_OK)
1343 		return error;
1344 
1345 	DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
1346 	if (unitEntry == NULL) {
1347 		WARNING("No type unit entry in .debug_types section.\n");
1348 		return B_BAD_DATA;
1349 	}
1350 
1351 	unit->SetUnitEntry(unitEntry);
1352 	DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset());
1353 	if (typeEntry == NULL) {
1354 		WARNING("No type found for type unit %p at specified offset %"
1355 			B_PRId64 ".\n", unit, unit->TypeOffset());
1356 		return B_BAD_DATA;
1357 	}
1358 	unit->SetTypeEntry(typeEntry);
1359 
1360 	TRACE_DIE_ONLY(
1361 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1362 			dataReader.BytesRemaining());
1363 		if (dataReader.HasData()) {
1364 			TRACE_DIE("  ");
1365 			while (dataReader.HasData())
1366 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1367 			TRACE_DIE("\n");
1368 		}
1369 	)
1370 	return B_OK;
1371 }
1372 
1373 
1374 status_t
_ParseDebugInfoEntry(DataReader & dataReader,BaseUnit * unit,AbbreviationTable * abbreviationTable,DebugInfoEntry * & _entry,bool & _endOfEntryList,int level)1375 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
1376 	BaseUnit* unit, AbbreviationTable* abbreviationTable,
1377 	DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
1378 {
1379 	off_t entryOffset = dataReader.Offset()
1380 		+ unit->RelativeContentOffset();
1381 
1382 	uint32 code = dataReader.ReadUnsignedLEB128(0);
1383 	if (code == 0) {
1384 		if (dataReader.HasOverflow()) {
1385 			WARNING("Unexpected end of .debug_info section.\n");
1386 			return B_BAD_DATA;
1387 		}
1388 		_entry = NULL;
1389 		_endOfEntryList = true;
1390 		return B_OK;
1391 	}
1392 
1393 	// get the corresponding abbreviation entry
1394 	AbbreviationEntry abbreviationEntry;
1395 	if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
1396 		WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
1397 		return B_BAD_DATA;
1398 	}
1399 
1400 	DebugInfoEntry* entry;
1401 	status_t error = fDebugInfoFactory.CreateDebugInfoEntry(
1402 		abbreviationEntry.Tag(), entry);
1403 	if (error != B_OK) {
1404 		WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %"
1405 			B_PRIu32 "\n", abbreviationEntry.Tag(), code);
1406 		return error;
1407 	}
1408 
1409 	ObjectDeleter<DebugInfoEntry> entryDeleter(entry);
1410 
1411 	TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%"
1412 		B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset,
1413 		abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
1414 		abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
1415 
1416 	error = unit->AddDebugInfoEntry(entry, entryOffset);
1417 
1418 	if (error != B_OK)
1419 		return error;
1420 
1421 	// parse the attributes (supply NULL entry to avoid adding them yet)
1422 	error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
1423 	if (error != B_OK)
1424 		return error;
1425 
1426 	// parse children, if the entry has any
1427 	if (abbreviationEntry.HasChildren()) {
1428 		while (true) {
1429 			DebugInfoEntry* childEntry;
1430 			bool endOfEntryList;
1431 			status_t error = _ParseDebugInfoEntry(dataReader,
1432 				unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
1433 			if (error != B_OK)
1434 				return error;
1435 
1436 			// add the child to our entry
1437 			if (childEntry != NULL) {
1438 				if (entry != NULL) {
1439 					error = entry->AddChild(childEntry);
1440 					if (error == B_OK) {
1441 						childEntry->SetParent(entry);
1442 					} else if (error == ENTRY_NOT_HANDLED) {
1443 						error = B_OK;
1444 						TRACE_DIE("%*s  -> child unhandled\n", level * 2, "");
1445 					}
1446 
1447 					if (error != B_OK) {
1448 						delete childEntry;
1449 						return error;
1450 					}
1451 				} else
1452 					delete childEntry;
1453 			}
1454 
1455 			if (endOfEntryList)
1456 				break;
1457 		}
1458 	}
1459 
1460 	entryDeleter.Detach();
1461 	_entry = entry;
1462 	_endOfEntryList = false;
1463 	return B_OK;
1464 }
1465 
1466 
1467 status_t
_FinishUnit(BaseUnit * unit)1468 DwarfFile::_FinishUnit(BaseUnit* unit)
1469 {
1470 	CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
1471 	bool isTypeUnit = compilationUnit == NULL;
1472 	TRACE_DIE("\nfinishing %s unit %p\n",
1473 		isTypeUnit ? "type" : "compilation", unit);
1474 
1475 
1476 	AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
1477 
1478 	ElfSection* section = isTypeUnit
1479 			? fDebugTypesSection : fDebugInfoSection;
1480 	DataReader dataReader(
1481 		(const uint8*)section->Data() + unit->HeaderOffset(),
1482 		unit->TotalSize(), unit->AddressSize(), unit->IsBigEndian());
1483 
1484 	DebugInfoEntryInitInfo entryInitInfo;
1485 
1486 	int entryCount = unit->CountEntries();
1487 	for (int i = 0; i < entryCount; i++) {
1488 		// get the entry
1489 		DebugInfoEntry* entry;
1490 		off_t offset;
1491 		unit->GetEntryAt(i, entry, offset);
1492 
1493 		TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset);
1494 
1495 		// seek the reader to the entry
1496 		dataReader.SeekAbsolute(offset);
1497 
1498 		// read the entry code
1499 		uint32 code = dataReader.ReadUnsignedLEB128(0);
1500 
1501 		// get the respective abbreviation entry
1502 		AbbreviationEntry abbreviationEntry;
1503 		abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry);
1504 
1505 		// initialization before setting the attributes
1506 		status_t error = entry->InitAfterHierarchy(entryInitInfo);
1507 		if (error != B_OK) {
1508 			WARNING("Init after hierarchy failed!\n");
1509 			return error;
1510 		}
1511 
1512 		// parse the attributes -- this time pass the entry, so that the
1513 		// attribute get set on it
1514 		error = _ParseEntryAttributes(dataReader, unit, entry,
1515 			abbreviationEntry);
1516 		if (error != B_OK)
1517 			return error;
1518 
1519 		// initialization after setting the attributes
1520 		error = entry->InitAfterAttributes(entryInitInfo);
1521 		if (error != B_OK) {
1522 			WARNING("Init after attributes failed!\n");
1523 			return error;
1524 		}
1525 	}
1526 
1527 	// set the compilation unit's source language
1528 	unit->SetSourceLanguage(entryInitInfo.languageInfo);
1529 
1530 	if (isTypeUnit)
1531 		return B_OK;
1532 
1533 	// resolve the compilation unit's address range list
1534 	if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
1535 			compilationUnit->UnitEntry()->AddressRangesOffset())) {
1536 		compilationUnit->SetAddressRanges(ranges);
1537 		ranges->ReleaseReference();
1538 	}
1539 
1540 	// add compilation dir to directory list
1541 	const char* compilationDir = compilationUnit->UnitEntry()
1542 		->CompilationDir();
1543 	if (!compilationUnit->AddDirectory(compilationDir != NULL
1544 				? compilationDir : ".")) {
1545 		return B_NO_MEMORY;
1546 	}
1547 
1548 	// parse line info header
1549 	if (fDebugLineSection != NULL)
1550 		_ParseLineInfo(compilationUnit);
1551 
1552 	return B_OK;
1553 }
1554 
1555 
1556 status_t
_ReadStringIndirect(BaseUnit * unit,uint64 index,const char * & value) const1557 DwarfFile::_ReadStringIndirect(BaseUnit* unit, uint64 index, const char*& value) const
1558 {
1559 	if (fDebugStrOffsetsSection == NULL) {
1560 		WARNING("Invalid DW_FORM_strx*: no debug_str_offsets section!\n");
1561 		return B_BAD_DATA;
1562 	}
1563 
1564 	uint64 strOffsetsBase = unit->IsDwarf64() ? 16 : 8;
1565 	uint64 offsetSize = unit->IsDwarf64() ? 8 : 4;
1566 
1567 	if (strOffsetsBase + index * offsetSize >= fDebugStrOffsetsSection->Size()) {
1568 		WARNING("Invalid DW_FORM_strx* index: %" B_PRIu64 "\n", index);
1569 		return B_BAD_DATA;
1570 	}
1571 
1572 	const char *strOffsets = (const char*)fDebugStrOffsetsSection->Data() + strOffsetsBase;
1573 	uint64 offset = unit->IsDwarf64()
1574 		? ((uint64*)strOffsets)[index]
1575 		: ((uint32*)strOffsets)[index];
1576 
1577 	if (offset >= fDebugStringSection->Size()) {
1578 		WARNING("Invalid DW_FORM_strx* offset: %" B_PRIu64 "\n", offset);
1579 		return B_BAD_DATA;
1580 	}
1581 
1582 	value = (const char*)fDebugStringSection->Data() + offset;
1583 	return B_OK;
1584 }
1585 
1586 
1587 status_t
_ReadAddressIndirect(BaseUnit * unit,uint64 index,uint64 & value) const1588 DwarfFile::_ReadAddressIndirect(BaseUnit* unit, uint64 index, uint64& value) const
1589 {
1590 	if (fDebugAddressSection == NULL) {
1591 		WARNING("Invalid DW_FORM_addrx*: no debug_addr section!\n");
1592 		return B_BAD_DATA;
1593 	}
1594 
1595 	uint64 addrBase = unit->IsDwarf64() ? 16 : 8;
1596 
1597 	if (addrBase + index * unit->AddressSize() >= fDebugAddressSection->Size()) {
1598 		WARNING("Invalid DW_FORM_addrx* index: %" B_PRIu64 "\n", index);
1599 		return B_BAD_DATA;
1600 	}
1601 
1602 	const char *addrPtr = (const char*)fDebugAddressSection->Data()
1603 		+ addrBase + index * unit->AddressSize();
1604 
1605 	if (unit->AddressSize() == 8)
1606 		value = *(uint64*)addrPtr;
1607 	else
1608 		value = *(uint32*)addrPtr;
1609 
1610 	return B_OK;
1611 }
1612 
1613 
1614 status_t
_ParseEntryAttributes(DataReader & dataReader,BaseUnit * unit,DebugInfoEntry * entry,AbbreviationEntry & abbreviationEntry)1615 DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
1616 	BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
1617 {
1618 	uint32 attributeName;
1619 	uint32 attributeForm;
1620 	int32 attributeImplicitConst = 0;
1621 	while (abbreviationEntry.GetNextAttribute(attributeName,
1622 			attributeForm, attributeImplicitConst)) {
1623 		// resolve attribute form indirection
1624 		if (attributeForm == DW_FORM_indirect)
1625 			attributeForm = dataReader.ReadUnsignedLEB128(0);
1626 
1627 		// prepare an AttributeValue
1628 		AttributeValue attributeValue;
1629 		attributeValue.attributeForm = attributeForm;
1630 		bool isSigned = false;
1631 
1632 		// Read the attribute value according to the attribute's form. For
1633 		// the forms that don't map to a single attribute class only or
1634 		// those that need additional processing, we read a temporary value
1635 		// first.
1636 		uint64 value = 0;
1637 		off_t blockLength = 0;
1638 		off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
1639 		uint8 refType = dwarf_reference_type_local;
1640 
1641 		switch (attributeForm) {
1642 			case DW_FORM_addr:
1643 				value = dataReader.ReadAddress(0);
1644 				break;
1645 			case DW_FORM_block2:
1646 				blockLength = dataReader.Read<uint16>(0);
1647 				break;
1648 			case DW_FORM_block4:
1649 				blockLength = dataReader.Read<uint32>(0);
1650 				break;
1651 			case DW_FORM_data2:
1652 				value = dataReader.Read<uint16>(0);
1653 				break;
1654 			case DW_FORM_data4:
1655 				value = dataReader.Read<uint32>(0);
1656 				break;
1657 			case DW_FORM_data8:
1658 				value = dataReader.Read<uint64>(0);
1659 				break;
1660 			case DW_FORM_string:
1661 				attributeValue.SetToString(dataReader.ReadString());
1662 				break;
1663 			case DW_FORM_block:
1664 			case DW_FORM_exprloc:
1665 				blockLength = dataReader.ReadUnsignedLEB128(0);
1666 				break;
1667 			case DW_FORM_block1:
1668 				blockLength = dataReader.Read<uint8>(0);
1669 				break;
1670 			case DW_FORM_data1:
1671 				value = dataReader.Read<uint8>(0);
1672 				break;
1673 			case DW_FORM_flag:
1674 				attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0);
1675 				break;
1676 			case DW_FORM_sdata:
1677 				value = dataReader.ReadSignedLEB128(0);
1678 				isSigned = true;
1679 				break;
1680 			case DW_FORM_strp:
1681 			{
1682 				if (fDebugStringSection != NULL) {
1683 					uint64 offset = unit->IsDwarf64()
1684 						? dataReader.Read<uint64>(0)
1685 						: dataReader.Read<uint32>(0);
1686 					if (offset >= fDebugStringSection->Size()) {
1687 						WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1688 							offset);
1689 						return B_BAD_DATA;
1690 					}
1691 					attributeValue.SetToString(
1692 						(const char*)fDebugStringSection->Data() + offset);
1693 				} else {
1694 					WARNING("Invalid DW_FORM_strp: no string section!\n");
1695 					return B_BAD_DATA;
1696 				}
1697 				break;
1698 			}
1699 			case DW_FORM_udata:
1700 				value = dataReader.ReadUnsignedLEB128(0);
1701 				break;
1702 			case DW_FORM_ref_addr:
1703 				value = unit->IsDwarf64()
1704 					? dataReader.Read<uint64>(0)
1705 					: (uint64)dataReader.Read<uint32>(0);
1706 				refType = dwarf_reference_type_global;
1707 				break;
1708 			case DW_FORM_ref1:
1709 				value = dataReader.Read<uint8>(0);
1710 				break;
1711 			case DW_FORM_ref2:
1712 				value = dataReader.Read<uint16>(0);
1713 				break;
1714 			case DW_FORM_ref4:
1715 				value = dataReader.Read<uint32>(0);
1716 				break;
1717 			case DW_FORM_ref8:
1718 				value = dataReader.Read<uint64>(0);
1719 				break;
1720 			case DW_FORM_ref_udata:
1721 				value = dataReader.ReadUnsignedLEB128(0);
1722 				break;
1723 			case DW_FORM_flag_present:
1724 				attributeValue.SetToFlag(true);
1725 				break;
1726 			case DW_FORM_strx:
1727 			{
1728 				uint64 index = dataReader.ReadUnsignedLEB128(0);
1729 				const char* strValue;
1730 				status_t res = _ReadStringIndirect(unit, index, strValue);
1731 				if (res != B_OK)
1732 					return res;
1733 				attributeValue.SetToString(strValue);
1734 				break;
1735 			}
1736 			case DW_FORM_addrx:
1737 			{
1738 				uint64 index = dataReader.ReadUnsignedLEB128(0);
1739 				status_t res = _ReadAddressIndirect(unit, index, value);
1740 				if (res != B_OK)
1741 					return res;
1742 				break;
1743 			}
1744 			case DW_FORM_line_strp:
1745 			{
1746 				if (fDebugLineStrSection != NULL) {
1747 					uint64 offset = unit->IsDwarf64()
1748 						? dataReader.Read<uint64>(0)
1749 						: dataReader.Read<uint32>(0);
1750 					if (offset >= fDebugLineStrSection->Size()) {
1751 						WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n",
1752 							offset);
1753 						return B_BAD_DATA;
1754 					}
1755 					attributeValue.SetToString(
1756 						(const char*)fDebugLineStrSection->Data() + offset);
1757 				} else {
1758 					WARNING("Invalid DW_FORM_line_strp: no debug_line_str section!\n");
1759 					return B_BAD_DATA;
1760 				}
1761 				break;
1762 			}
1763 			case DW_FORM_ref_sig8:
1764 				fTypesSectionRequired = true;
1765 				value = dataReader.Read<uint64>(0);
1766 				refType = dwarf_reference_type_signature;
1767 				break;
1768 			case DW_FORM_implicit_const:
1769 				value = attributeImplicitConst;
1770 				break;
1771 			case DW_FORM_sec_offset:
1772 				value = unit->IsDwarf64()
1773 					? dataReader.Read<uint64>(0)
1774 					: (uint64)dataReader.Read<uint32>(0);
1775 				break;
1776 			case DW_FORM_strx1:
1777 			case DW_FORM_strx2:
1778 			case DW_FORM_strx3:
1779 			case DW_FORM_strx4:
1780 			{
1781 				size_t numBytes = attributeForm - DW_FORM_strx1 + 1;
1782 				uint64 index = dataReader.ReadUInt(numBytes, 0);
1783 				const char* strValue;
1784 				status_t res = _ReadStringIndirect(unit, index, strValue);
1785 				if (res != B_OK)
1786 					return res;
1787 				attributeValue.SetToString(strValue);
1788 				break;
1789 			}
1790 			case DW_FORM_addrx1:
1791 			case DW_FORM_addrx2:
1792 			case DW_FORM_addrx3:
1793 			case DW_FORM_addrx4:
1794 			{
1795 				size_t numBytes = attributeForm - DW_FORM_addrx1 + 1;
1796 				uint64 index = dataReader.ReadUInt(numBytes, 0);
1797 				status_t res = _ReadAddressIndirect(unit, index, value);
1798 				if (res != B_OK)
1799 					return res;
1800 				break;
1801 			}
1802 			case DW_FORM_indirect:
1803 			default:
1804 				WARNING("Unsupported attribute form: %" B_PRIu32 "\n",
1805 					attributeForm);
1806 				return B_BAD_DATA;
1807 		}
1808 
1809 		// get the attribute class -- skip the attribute, if we can't handle
1810 		// it
1811 		uint8 attributeClass = get_attribute_class(attributeName,
1812 			attributeForm);
1813 
1814 		if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
1815 			TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
1816 				B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
1817 				get_attribute_name_name(attributeName), attributeName,
1818 				get_attribute_form_name(attributeForm), attributeForm);
1819 			continue;
1820 		}
1821 
1822 		// set the attribute value according to the attribute's class
1823 		switch (attributeClass) {
1824 			case ATTRIBUTE_CLASS_ADDRESS:
1825 				attributeValue.SetToAddress(value);
1826 				break;
1827 			case ATTRIBUTE_CLASS_ADDRPTR:
1828 				attributeValue.SetToAddrPtr(value);
1829 				break;
1830 			case ATTRIBUTE_CLASS_BLOCK:
1831 				attributeValue.SetToBlock(dataReader.Data(), blockLength);
1832 				dataReader.Skip(blockLength);
1833 				break;
1834 			case ATTRIBUTE_CLASS_CONSTANT:
1835 				attributeValue.SetToConstant(value, isSigned);
1836 				break;
1837 			case ATTRIBUTE_CLASS_LINEPTR:
1838 				attributeValue.SetToLinePointer(value);
1839 				break;
1840 			case ATTRIBUTE_CLASS_LOCLIST:
1841 				attributeValue.SetToLocationList(value);
1842 				break;
1843 			case ATTRIBUTE_CLASS_LOCLISTPTR:
1844 				attributeValue.SetToLocationListPointer(value);
1845 				break;
1846 			case ATTRIBUTE_CLASS_MACPTR:
1847 				attributeValue.SetToMacroPointer(value);
1848 				break;
1849 			case ATTRIBUTE_CLASS_RANGELIST:
1850 				attributeValue.SetToRangeList(value);
1851 				break;
1852 			case ATTRIBUTE_CLASS_RANGELISTPTR:
1853 				attributeValue.SetToRangeListPointer(value);
1854 				break;
1855 			case ATTRIBUTE_CLASS_REFERENCE:
1856 				if (entry != NULL) {
1857 					attributeValue.SetToReference(_ResolveReference(
1858 						unit, value, refType));
1859 					if (attributeValue.reference == NULL) {
1860 						// gcc 2 apparently somtimes produces DW_AT_sibling
1861 						// attributes pointing to the end of the sibling list.
1862 						// Just ignore those.
1863 						if (attributeName == DW_AT_sibling)
1864 							continue;
1865 
1866 						WARNING("Failed to resolve reference on entry %p: "
1867 							"(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
1868 							"(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
1869 							entry,
1870 							valueOffset,
1871 							get_attribute_name_name(attributeName),
1872 							attributeName,
1873 							get_attribute_form_name(attributeForm),
1874 							attributeForm, value);
1875 						return B_ENTRY_NOT_FOUND;
1876 					}
1877 				}
1878 				break;
1879 			case ATTRIBUTE_CLASS_FLAG:
1880 			case ATTRIBUTE_CLASS_STRING:
1881 				// already set
1882 				break;
1883 			case ATTRIBUTE_CLASS_STROFFSETSPTR:
1884 				attributeValue.SetToStrOffsetsPtr(value);
1885 				break;
1886 		}
1887 
1888 		if (dataReader.HasOverflow()) {
1889 			WARNING("Unexpected end of .debug_info section.\n");
1890 			return B_BAD_DATA;
1891 		}
1892 
1893 		TRACE_DIE_ONLY(
1894 			char buffer[1024];
1895 			TRACE_DIE("  attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
1896 				valueOffset,
1897 				get_attribute_name_name(attributeName),
1898 				get_attribute_form_name(attributeForm), attributeClass,
1899 				attributeValue.ToString(buffer, sizeof(buffer)));
1900 		)
1901 
1902 		// add the attribute
1903 		if (entry != NULL) {
1904 			DebugInfoEntrySetter attributeSetter
1905 				= get_attribute_name_setter(attributeName);
1906 			if (attributeSetter != 0) {
1907 				status_t error = (entry->*attributeSetter)(attributeName,
1908 					attributeValue);
1909 
1910 				if (error == ATTRIBUTE_NOT_HANDLED) {
1911 					error = B_OK;
1912 					TRACE_DIE("    -> unhandled\n");
1913 				}
1914 
1915 				if (error != B_OK) {
1916 					WARNING("Failed to set attribute: name: %s, form: %s: %s\n",
1917 						get_attribute_name_name(attributeName),
1918 						get_attribute_form_name(attributeForm),
1919 						strerror(error));
1920 				}
1921 			} else
1922 				TRACE_DIE("    -> no attribute setter!\n");
1923 		}
1924 	}
1925 
1926 	return B_OK;
1927 }
1928 
1929 
1930 status_t
_ParseLineInfoFormatString(CompilationUnit * unit,DataReader & dataReader,uint64 format,const char * & value)1931 DwarfFile::_ParseLineInfoFormatString(CompilationUnit* unit, DataReader &dataReader,
1932 	uint64 format, const char*& value)
1933 {
1934 	switch (format) {
1935 		case DW_FORM_string:
1936 			value = dataReader.ReadString();
1937 			break;
1938 		case DW_FORM_line_strp:
1939 		{
1940 			if (fDebugLineStrSection == NULL) {
1941 				WARNING("Invalid DW_FORM_line_strp: no line_str section!\n");
1942 				return B_BAD_DATA;
1943 			}
1944 
1945 			target_addr_t offset = unit->IsDwarf64()
1946 				? dataReader.Read<uint64>(0)
1947 				: dataReader.Read<uint32>(0);
1948 			if (offset > fDebugLineStrSection->Size()) {
1949 				WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n",
1950 					offset);
1951 				return B_BAD_DATA;
1952 			}
1953 
1954 			value = (const char*)fDebugLineStrSection->Data() + offset;
1955 			break;
1956 		}
1957 		case DW_FORM_strp:
1958 		{
1959 			if (fDebugStringSection == NULL) {
1960 				WARNING("Invalid DW_FORM_strp: no string section!\n");
1961 				return B_BAD_DATA;
1962 			}
1963 
1964 			target_addr_t offset = unit->IsDwarf64()
1965 				? dataReader.Read<uint64>(0)
1966 				: dataReader.Read<uint32>(0);
1967 			if (offset > fDebugStringSection->Size()) {
1968 				WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1969 					offset);
1970 				return B_BAD_DATA;
1971 			}
1972 
1973 			value = (const char*)fDebugStringSection->Data() + offset;
1974 			break;
1975 		}
1976 		case DW_FORM_strp_sup:
1977 			return B_UNSUPPORTED;
1978 			break;
1979 		default:
1980 			WARNING("DwarfFile::_ParseLineInfoFormatString(\"%s\"): unsupported "
1981 				"field type %" PRIu64 "\n", fName, format);
1982 			return B_BAD_DATA;
1983 	}
1984 
1985 	return B_OK;
1986 }
1987 
1988 
1989 status_t
_ParseLineInfoFormatUint(CompilationUnit * unit,DataReader & dataReader,uint64 format,uint64 & value)1990 DwarfFile::_ParseLineInfoFormatUint(CompilationUnit* unit, DataReader &dataReader,
1991 	uint64 format, uint64 &value)
1992 {
1993 	switch (format)
1994 	{
1995 		case DW_FORM_data1:
1996 			value = dataReader.Read<uint8>(0);
1997 			break;
1998 		case DW_FORM_data2:
1999 			value = dataReader.Read<uint16>(0);
2000 			break;
2001 		case DW_FORM_data4:
2002 			value = dataReader.Read<uint32>(0);
2003 			break;
2004 		case DW_FORM_data8:
2005 			value = dataReader.Read<uint64>(0);
2006 			break;
2007 		case DW_FORM_udata:
2008 			value = dataReader.ReadUnsignedLEB128(0);
2009 			break;
2010 		default:
2011 			WARNING("DwarfFile::_ParseLineInfoFormatUint(\"%s\"): unsupported "
2012 				"field type %" PRIu64 "\n", fName, format);
2013 			return B_BAD_DATA;
2014 	}
2015 
2016 	return B_OK;
2017 }
2018 
2019 
2020 status_t
_ParseLineInfo(CompilationUnit * unit)2021 DwarfFile::_ParseLineInfo(CompilationUnit* unit)
2022 {
2023 	off_t offset = unit->UnitEntry()->StatementListOffset();
2024 
2025 	TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit,
2026 		offset);
2027 
2028 	DataReader dataReader((uint8*)fDebugLineSection->Data() + offset,
2029 		fDebugLineSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
2030 
2031 	// unit length
2032 	bool dwarf64;
2033 	uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
2034 	if (unitLength > (uint64)dataReader.BytesRemaining())
2035 		return B_BAD_DATA;
2036 	off_t unitOffset = dataReader.Offset();
2037 
2038 	// version (uhalf)
2039 	uint16 version = dataReader.Read<uint16>(0);
2040 
2041 	if (version < 2 || version > 5) {
2042 		WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2043 			"version %d\n", fName, version);
2044 		return B_UNSUPPORTED;
2045 	}
2046 
2047 	uint8 addressSize = unit->AddressSize();
2048 	uint8 segmentSelectorSize = 0;
2049 
2050 	if (version >= 5) {
2051 		addressSize = dataReader.Read<uint8>(0);
2052 		if (addressSize != 4 && addressSize != 8) {
2053 			WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2054 				"addressSize %d\n", fName, addressSize);
2055 			return B_BAD_DATA;
2056 		}
2057 
2058 		segmentSelectorSize = dataReader.Read<uint8>(0);
2059 		if (segmentSelectorSize != 0) {
2060 			WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2061 				"segmentSelectorSize %d\n", fName, segmentSelectorSize);
2062 			return B_BAD_DATA;
2063 		}
2064 	}
2065 
2066 	// header_length (4/8)
2067 	uint64 headerLength = dwarf64
2068 		? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
2069 	off_t headerOffset = dataReader.Offset();
2070 
2071 	if ((uint64)dataReader.BytesRemaining() < headerLength)
2072 		return B_BAD_DATA;
2073 
2074 	// minimum instruction length
2075 	uint8 minInstructionLength = dataReader.Read<uint8>(0);
2076 
2077 	uint8 maxOpsPerInstruction;
2078 	if (version >= 4)
2079 		maxOpsPerInstruction = dataReader.Read<uint8>(0);
2080 	else
2081 		maxOpsPerInstruction = 1;
2082 
2083 	if (maxOpsPerInstruction != 1) {
2084 		WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2085 			"maxOpsPerInstruction %u\n", fName, maxOpsPerInstruction);
2086 		return B_UNSUPPORTED;
2087 	}
2088 
2089 	// default is statement
2090 	bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
2091 
2092 	// line_base (sbyte)
2093 	int8 lineBase = (int8)dataReader.Read<uint8>(0);
2094 
2095 	// line_range (ubyte)
2096 	uint8 lineRange = dataReader.Read<uint8>(0);
2097 
2098 	// opcode_base (ubyte)
2099 	uint8 opcodeBase = dataReader.Read<uint8>(0);
2100 
2101 	// standard_opcode_lengths (ubyte[])
2102 	const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
2103 	dataReader.Skip(opcodeBase - 1);
2104 
2105 	if (dataReader.HasOverflow())
2106 		return B_BAD_DATA;
2107 
2108 	TRACE_LINES("  unitLength:           %" B_PRIu64 "\n", unitLength);
2109 	TRACE_LINES("  version:              %u\n", version);
2110 	if (version >= 5) {
2111 		TRACE_LINES("  addressSize:          %u\n", addressSize);
2112 		TRACE_LINES("  segmentSelectorSize:  %u\n", segmentSelectorSize);
2113 	}
2114 	TRACE_LINES("  headerLength:         %" B_PRIu64 "\n", headerLength);
2115 	TRACE_LINES("  minInstructionLength: %u\n", minInstructionLength);
2116 	if (version >= 4)
2117 		TRACE_LINES("  maxOpsPerInstruction: %u\n", maxOpsPerInstruction);
2118 	TRACE_LINES("  defaultIsStatement:   %d\n", defaultIsStatement);
2119 	TRACE_LINES("  lineBase:             %d\n", lineBase);
2120 	TRACE_LINES("  lineRange:            %u\n", lineRange);
2121 	TRACE_LINES("  opcodeBase:           %u\n", opcodeBase);
2122 
2123 	if (version >= 5) {
2124 		uint8 dirEntryFormatCount = dataReader.Read<uint8>(0);
2125 		TRACE_LINES("  dirEntryFormatCount:  %u\n", dirEntryFormatCount);
2126 
2127 		off_t dirEntryFormatOffset = dataReader.Offset();
2128 		for (unsigned int i = 0; i < dirEntryFormatCount; i++) {
2129 			TRACE_LINES_ONLY(uint64 content =)
2130 				dataReader.ReadUnsignedLEB128(0);
2131 			TRACE_LINES_ONLY(uint64 format =)
2132 				dataReader.ReadUnsignedLEB128(0);
2133 
2134 			TRACE_LINES("    content:            %" B_PRIu64 "\n", content);
2135 			TRACE_LINES("    format:             %" B_PRIu64 "\n", format);
2136 		}
2137 		off_t dirEntryFormatLength = dataReader.Offset() - dirEntryFormatOffset;
2138 		DataReader dirEntryFormatReader = dataReader.RestrictedReader(-dirEntryFormatLength,
2139 			dirEntryFormatLength);
2140 
2141 		uint8 dirCount = dataReader.Read<uint8>(0);
2142 		TRACE_LINES("  dirCount:             %u\n", dirCount);
2143 
2144 		for (unsigned int i = 0; i < dirCount; i++) {
2145 			dirEntryFormatReader.SeekAbsolute(0);
2146 			for (unsigned int j = 0; j < dirEntryFormatCount; j++) {
2147 				uint64 content = dirEntryFormatReader.ReadUnsignedLEB128(0);
2148 				uint64 format = dirEntryFormatReader.ReadUnsignedLEB128(0);
2149 				if (content != DW_LNCT_path) {
2150 					WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2151 						"field in dirs %" PRIu64 "\n", fName, content);
2152 					return B_UNSUPPORTED;
2153 				}
2154 
2155 				const char* directory;
2156 				status_t res = _ParseLineInfoFormatString(unit, dataReader, format, directory);
2157 				if (res != B_OK)
2158 					return res;
2159 				TRACE_LINES("    \"%s\"\n", directory);
2160 
2161 				if (!unit->AddDirectory(directory))
2162 					return B_NO_MEMORY;
2163 
2164 			}
2165 		}
2166 
2167 		uint8 fileNameEntryFormatCount = dataReader.Read<uint8>(0);
2168 		TRACE_LINES("  fileNameFormatCount:  %u\n", fileNameEntryFormatCount);
2169 
2170 		off_t fileNameEntryFormatOffset = dataReader.Offset();
2171 		for (unsigned int i = 0; i < fileNameEntryFormatCount; i++) {
2172 			TRACE_LINES_ONLY(uint64 content =)
2173 				dataReader.ReadUnsignedLEB128(0);
2174 			TRACE_LINES_ONLY(uint64 format =)
2175 				dataReader.ReadUnsignedLEB128(0);
2176 
2177 			TRACE_LINES("    content:            %" B_PRIu64 "\n", content);
2178 			TRACE_LINES("    format:             %" B_PRIu64 "\n", format);
2179 		}
2180 		off_t fileNameEntryFormatLength = dataReader.Offset() - fileNameEntryFormatOffset;
2181 		DataReader fileNameEntryFormatReader = dataReader.RestrictedReader(-fileNameEntryFormatLength,
2182 			fileNameEntryFormatLength);
2183 
2184 		uint8 fileNameCount = dataReader.Read<uint8>(0);
2185 		TRACE_LINES("  fileNameCount:        %u\n", dirCount);
2186 
2187 		for (unsigned int i = 0; i < fileNameCount; i++) {
2188 			const char* fileName = NULL;
2189 			uint64 dirIndex = 0xffffffffffffffffull;
2190 			uint64 modificationTime = 0;
2191 			uint64 fileLength = 0;
2192 
2193 			fileNameEntryFormatReader.SeekAbsolute(0);
2194 			for (unsigned int j = 0; j < fileNameEntryFormatCount; j++) {
2195 
2196 				uint64 content = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
2197 				uint64 format = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
2198 				status_t res;
2199 				switch (content) {
2200 					case DW_LNCT_path:
2201 						res = _ParseLineInfoFormatString(unit, dataReader,
2202 							format, fileName);
2203 						if (res != B_OK)
2204 							return res;
2205 						break;
2206 					case DW_LNCT_directory_index:
2207 						res = _ParseLineInfoFormatUint(unit, dataReader,
2208 							format, dirIndex);
2209 						if (res != B_OK)
2210 							return res;
2211 						break;
2212 					case DW_LNCT_timestamp:
2213 						res = _ParseLineInfoFormatUint(unit, dataReader,
2214 							format, modificationTime);
2215 						if (res != B_OK)
2216 							return res;
2217 						break;
2218 					case DW_LNCT_size:
2219 						res = _ParseLineInfoFormatUint(unit, dataReader,
2220 							format, fileLength);
2221 						if (res != B_OK)
2222 							return res;
2223 						break;
2224 					case DW_LNCT_MD5:
2225 						if (format != DW_FORM_data16)
2226 							return B_BAD_DATA;
2227 
2228 						dataReader.Skip(16);
2229 						break;
2230 					default:
2231 						WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2232 							"field in files %" PRIu64 "\n",
2233 							fName, content);
2234 						return B_UNSUPPORTED;
2235 				}
2236 			}
2237 
2238 			if ((fileName != NULL) && (dirIndex != 0xffffffffffffffffull)) {
2239 				TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 "\n",
2240 					fileName, dirIndex);
2241 
2242 				if (!unit->AddFile(fileName, dirIndex))
2243 					return B_NO_MEMORY;
2244 			}
2245 		}
2246 	} else {
2247 		// include directories
2248 		TRACE_LINES("  include directories:\n");
2249 		while (const char* directory = dataReader.ReadString()) {
2250 			if (*directory == '\0')
2251 				break;
2252 			TRACE_LINES("    \"%s\"\n", directory);
2253 
2254 			if (!unit->AddDirectory(directory))
2255 				return B_NO_MEMORY;
2256 		}
2257 
2258 		// file names
2259 		TRACE_LINES("  files:\n");
2260 		while (const char* file = dataReader.ReadString()) {
2261 			if (*file == '\0')
2262 				break;
2263 			uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
2264 			TRACE_LINES_ONLY(uint64 modificationTime =)
2265 				dataReader.ReadUnsignedLEB128(0);
2266 			TRACE_LINES_ONLY(uint64 fileLength =)
2267 				dataReader.ReadUnsignedLEB128(0);
2268 
2269 			if (dataReader.HasOverflow())
2270 				return B_BAD_DATA;
2271 
2272 			TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
2273 				", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
2274 				fileLength);
2275 
2276 			if (!unit->AddFile(file, dirIndex))
2277 				return B_NO_MEMORY;
2278 		}
2279 	}
2280 
2281 	off_t readerOffset = dataReader.Offset();
2282 	if ((uint64)readerOffset > readerOffset + headerLength)
2283 		return B_BAD_DATA;
2284 	off_t offsetToProgram = headerOffset + headerLength - readerOffset;
2285 
2286 	const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
2287 	size_t programSize = unitLength - (readerOffset - unitOffset);
2288 
2289 	return unit->GetLineNumberProgram().Init(program, programSize,
2290 		minInstructionLength, defaultIsStatement, lineBase, lineRange,
2291 			opcodeBase, standardOpcodeLengths);
2292 }
2293 
2294 
2295 status_t
_UnwindCallFrame(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,target_addr_t location,const FDELookupInfo * info,const DwarfTargetInterface * inputInterface,DwarfTargetInterface * outputInterface,target_addr_t & _framePointer)2296 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
2297 	DIESubprogram* subprogramEntry, target_addr_t location,
2298 	const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
2299 	DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
2300 {
2301 	ElfSection* currentFrameSection = (info->ehFrame)
2302 		? fEHFrameSection : fDebugFrameSection;
2303 
2304 	TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
2305 
2306 	DataReader dataReader((uint8*)currentFrameSection->Data(),
2307 		currentFrameSection->Size(),
2308 		unit != NULL ? unit->AddressSize() : addressSize,
2309 		unit != NULL ? unit->IsBigEndian() : isBigEndian);
2310 	dataReader.SeekAbsolute(info->fdeOffset);
2311 
2312 	bool dwarf64;
2313 	uint64 length = dataReader.ReadInitialLength(dwarf64);
2314 	uint64 lengthOffset = dataReader.Offset();
2315 
2316 	CfaContext context;
2317 	CIEAugmentation cieAugmentation;
2318 	// when using .eh_frame format, we need to parse the CIE's
2319 	// augmentation up front in order to know how the FDE's addresses
2320 	//  will be represented
2321 	DataReader cieReader;
2322 	off_t cieRemaining;
2323 	status_t error = _ParseCIEHeader(currentFrameSection,
2324 		info->ehFrame, unit, addressSize, isBigEndian, context, info->cieOffset,
2325 		cieAugmentation, cieReader, cieRemaining);
2326 	if (error != B_OK)
2327 		return error;
2328 	if (cieReader.HasOverflow())
2329 		return B_BAD_DATA;
2330 	if (cieRemaining < 0)
2331 		return B_BAD_DATA;
2332 
2333 	// skip CIE ID, initial offset and range, since we already know those
2334 	// from FDELookupInfo.
2335 	dwarf64	? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2336 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
2337 		currentFrameSection);
2338 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
2339 		currentFrameSection, true);
2340 
2341 	TRACE_CFI("  found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
2342 		"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
2343 		"range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
2344 		info->cieOffset, info->start, info->end - info->start);
2345 
2346 	context.SetLocation(location, info->start);
2347 	uint32 registerCount = outputInterface->CountRegisters();
2348 	error = context.Init(registerCount);
2349 	if (error != B_OK)
2350 		return error;
2351 
2352 	error = outputInterface->InitRegisterRules(context);
2353 	if (error != B_OK)
2354 		return error;
2355 
2356 	// process the CIE's frame info instructions
2357 	cieReader = cieReader.RestrictedReader(cieRemaining);
2358 	error = _ParseFrameInfoInstructions(unit, context,
2359 		cieReader, cieAugmentation);
2360 	if (error != B_OK)
2361 		return error;
2362 
2363 	// read the FDE augmentation data (if any)
2364 	FDEAugmentation fdeAugmentation;
2365 	error = cieAugmentation.ReadFDEData(dataReader,
2366 		fdeAugmentation);
2367 	if (error != B_OK) {
2368 		TRACE_CFI("  failed to read FDE augmentation data!\n");
2369 		return error;
2370 	}
2371 
2372 	error = context.SaveInitialRuleSet();
2373 	if (error != B_OK)
2374 		return error;
2375 
2376 	uint64 remaining = lengthOffset + length - dataReader.Offset();
2377 	if (remaining < 0)
2378 		return B_BAD_DATA;
2379 
2380 	DataReader restrictedReader =
2381 		dataReader.RestrictedReader(remaining);
2382 	error = _ParseFrameInfoInstructions(unit, context,
2383 		restrictedReader, cieAugmentation);
2384 	if (error != B_OK)
2385 		return error;
2386 
2387 	TRACE_CFI("  found row!\n");
2388 
2389 	// apply the rules of the final row
2390 	// get the frameAddress first
2391 	target_addr_t frameAddress;
2392 	CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
2393 	switch (cfaCfaRule->Type()) {
2394 		case CFA_CFA_RULE_REGISTER_OFFSET:
2395 		{
2396 			BVariant value;
2397 			if (!inputInterface->GetRegisterValue(
2398 					cfaCfaRule->Register(), value)
2399 				|| !value.IsNumber()) {
2400 				return B_UNSUPPORTED;
2401 			}
2402 			frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
2403 			break;
2404 		}
2405 		case CFA_CFA_RULE_EXPRESSION:
2406 		{
2407 			error = EvaluateExpression(unit, addressSize, isBigEndian,
2408 				subprogramEntry,
2409 				cfaCfaRule->Expression().block,
2410 				cfaCfaRule->Expression().size,
2411 				inputInterface, location, 0, 0, false,
2412 				frameAddress);
2413 			if (error != B_OK)
2414 				return error;
2415 			break;
2416 		}
2417 		case CFA_CFA_RULE_UNDEFINED:
2418 		default:
2419 			return B_BAD_VALUE;
2420 	}
2421 
2422 	TRACE_CFI("  frame address: %#" B_PRIx64 "\n", frameAddress);
2423 
2424 	// apply the register rules
2425 	for (uint32 i = 0; i < registerCount; i++) {
2426 		TRACE_CFI("  reg %" B_PRIu32 "\n", i);
2427 
2428 		uint32 valueType = outputInterface->RegisterValueType(i);
2429 		if (valueType == 0)
2430 			continue;
2431 
2432 		CfaRule* rule = context.RegisterRule(i);
2433 		if (rule == NULL)
2434 			continue;
2435 
2436 		// apply the rule
2437 		switch (rule->Type()) {
2438 			case CFA_RULE_SAME_VALUE:
2439 			{
2440 				TRACE_CFI("  -> CFA_RULE_SAME_VALUE\n");
2441 
2442 				BVariant value;
2443 				if (inputInterface->GetRegisterValue(i, value))
2444 					outputInterface->SetRegisterValue(i, value);
2445 				break;
2446 			}
2447 			case CFA_RULE_LOCATION_OFFSET:
2448 			{
2449 				TRACE_CFI("  -> CFA_RULE_LOCATION_OFFSET: %"
2450 					B_PRId64 "\n", rule->Offset());
2451 
2452 				BVariant value;
2453 				if (inputInterface->ReadValueFromMemory(
2454 						frameAddress + rule->Offset(), valueType,
2455 						value)) {
2456 					outputInterface->SetRegisterValue(i, value);
2457 				}
2458 				break;
2459 			}
2460 			case CFA_RULE_VALUE_OFFSET:
2461 				TRACE_CFI("  -> CFA_RULE_VALUE_OFFSET\n");
2462 
2463 				outputInterface->SetRegisterValue(i,
2464 					frameAddress + rule->Offset());
2465 				break;
2466 			case CFA_RULE_REGISTER:
2467 			{
2468 				TRACE_CFI("  -> CFA_RULE_REGISTER\n");
2469 
2470 				BVariant value;
2471 				if (inputInterface->GetRegisterValue(
2472 						rule->Register(), value)) {
2473 					outputInterface->SetRegisterValue(i, value);
2474 				}
2475 				break;
2476 			}
2477 			case CFA_RULE_LOCATION_EXPRESSION:
2478 			{
2479 				TRACE_CFI("  -> CFA_RULE_LOCATION_EXPRESSION\n");
2480 
2481 				target_addr_t address;
2482 				error = EvaluateExpression(unit, addressSize, isBigEndian,
2483 					subprogramEntry,
2484 					rule->Expression().block,
2485 					rule->Expression().size,
2486 					inputInterface, location, frameAddress,
2487 					frameAddress, true, address);
2488 				BVariant value;
2489 				if (error == B_OK
2490 					&& inputInterface->ReadValueFromMemory(address,
2491 						valueType, value)) {
2492 					outputInterface->SetRegisterValue(i, value);
2493 				}
2494 				break;
2495 			}
2496 			case CFA_RULE_VALUE_EXPRESSION:
2497 			{
2498 				TRACE_CFI("  -> CFA_RULE_VALUE_EXPRESSION\n");
2499 
2500 				target_addr_t value;
2501 				error = EvaluateExpression(unit, addressSize, isBigEndian,
2502 					subprogramEntry,
2503 					rule->Expression().block,
2504 					rule->Expression().size,
2505 					inputInterface, location, frameAddress,
2506 					frameAddress, true, value);
2507 				if (error == B_OK)
2508 					outputInterface->SetRegisterValue(i, value);
2509 				break;
2510 			}
2511 			case CFA_RULE_UNDEFINED:
2512 				TRACE_CFI("  -> CFA_RULE_UNDEFINED\n");
2513 			default:
2514 				break;
2515 		}
2516 	}
2517 
2518 	_framePointer = frameAddress;
2519 
2520 	return B_OK;
2521 }
2522 
2523 
2524 status_t
_ParseCIEHeader(ElfSection * debugFrameSection,bool usingEHFrameSection,CompilationUnit * unit,uint8 addressSize,bool isBigEndian,CfaContext & context,off_t cieOffset,CIEAugmentation & cieAugmentation,DataReader & dataReader,off_t & _cieRemaining)2525 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection,
2526 	bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
2527 	CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation,
2528 	DataReader& dataReader, off_t& _cieRemaining)
2529 {
2530 	if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size())
2531 		return B_BAD_DATA;
2532 
2533 	dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset,
2534 		debugFrameSection->Size() - cieOffset,
2535 		unit != NULL ? unit->AddressSize() : addressSize,
2536 		unit != NULL ? unit->IsBigEndian() : isBigEndian);
2537 
2538 	// length
2539 	bool dwarf64;
2540 	uint64 length = dataReader.ReadInitialLength(dwarf64);
2541 	if (length > (uint64)dataReader.BytesRemaining())
2542 		return B_BAD_DATA;
2543 
2544 	off_t lengthOffset = dataReader.Offset();
2545 
2546 	// CIE ID/CIE pointer
2547 	uint64 cieID = dwarf64
2548 		? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2549 	if (usingEHFrameSection) {
2550 		if (cieID != 0)
2551 			return B_BAD_DATA;
2552 	} else {
2553 		if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
2554 			return B_BAD_DATA;
2555 	}
2556 
2557 	uint8 version = dataReader.Read<uint8>(0);
2558 	if (version != 1) {
2559 		TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", "
2560 			"version: %u -- unsupported\n",	length, (uint64)cieOffset, version);
2561 		return B_UNSUPPORTED;
2562 	}
2563 
2564 	// read the augmentation string
2565 	cieAugmentation.Init(dataReader);
2566 
2567 	// in the cause of augmentation string "eh",
2568 	// the exception table pointer is located immediately before the
2569 	// code/data alignment values. We have no use for it so simply skip.
2570 	if (strcmp(cieAugmentation.String(), "eh") == 0)
2571 		dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32));
2572 
2573 	context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0));
2574 	context.SetDataAlignment(dataReader.ReadSignedLEB128(0));
2575 	context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0));
2576 
2577 	TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: "
2578 		"%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %"
2579 		B_PRId32 ", return address reg: %" B_PRIu32 "\n", length,
2580 		(uint64)cieOffset, version, cieAugmentation.String(),
2581 		context.CodeAlignment(), context.DataAlignment(),
2582 		context.ReturnAddressRegister());
2583 
2584 	status_t error = cieAugmentation.Read(dataReader);
2585 	if (error != B_OK) {
2586 		TRACE_CFI("  cie: length: %" B_PRIu64 ", version: %u, augmentation: "
2587 			"\"%s\" -- unsupported\n", length, version,
2588 			cieAugmentation.String());
2589 		return error;
2590 	}
2591 
2592 	if (dataReader.HasOverflow())
2593 		return B_BAD_DATA;
2594 
2595 	_cieRemaining = length -(dataReader.Offset() - lengthOffset);
2596 	if (_cieRemaining < 0)
2597 		return B_BAD_DATA;
2598 
2599 	return B_OK;
2600 }
2601 
2602 
2603 status_t
_ParseFrameInfoInstructions(CompilationUnit * unit,CfaContext & context,DataReader & dataReader,CIEAugmentation & augmentation)2604 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit,
2605 	CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation)
2606 {
2607 	while (dataReader.BytesRemaining() > 0) {
2608 		TRACE_CFI("    [%2" B_PRId64 "]", dataReader.BytesRemaining());
2609 
2610 		uint8 opcode = dataReader.Read<uint8>(0);
2611 		if ((opcode >> 6) != 0) {
2612 			uint32 operand = opcode & 0x3f;
2613 
2614 			switch (opcode >> 6) {
2615 				case DW_CFA_advance_loc:
2616 				{
2617 					TRACE_CFI("    DW_CFA_advance_loc: %#" B_PRIx32 "\n",
2618 						operand);
2619 
2620 					target_addr_t location = context.Location()
2621 						+ operand * context.CodeAlignment();
2622 					if (location > context.TargetLocation())
2623 						return B_OK;
2624 					context.SetLocation(location);
2625 					break;
2626 				}
2627 				case DW_CFA_offset:
2628 				{
2629 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2630 					TRACE_CFI("    DW_CFA_offset: reg: %" B_PRIu32 ", offset: "
2631 						"%" B_PRIu64 "\n", operand, offset);
2632 
2633 					if (CfaRule* rule = context.RegisterRule(operand)) {
2634 						rule->SetToLocationOffset(
2635 							offset * context.DataAlignment());
2636 					}
2637 					break;
2638 				}
2639 				case DW_CFA_restore:
2640 				{
2641 					TRACE_CFI("    DW_CFA_restore: %#" B_PRIx32 "\n", operand);
2642 
2643 					context.RestoreRegisterRule(operand);
2644 					break;
2645 				}
2646 			}
2647 		} else {
2648 			switch (opcode) {
2649 				case DW_CFA_nop:
2650 				{
2651 					TRACE_CFI("    DW_CFA_nop\n");
2652 					break;
2653 				}
2654 				case DW_CFA_set_loc:
2655 				{
2656 					target_addr_t location = augmentation.ReadEncodedAddress(
2657 							dataReader, fElfFile, fDebugFrameSection);
2658 
2659 					TRACE_CFI("    DW_CFA_set_loc: %#" B_PRIx64 "\n", location);
2660 
2661 					if (location < context.Location())
2662 						return B_BAD_VALUE;
2663 					if (location > context.TargetLocation())
2664 						return B_OK;
2665 					context.SetLocation(location);
2666 					break;
2667 				}
2668 				case DW_CFA_advance_loc1:
2669 				{
2670 					uint32 delta = dataReader.Read<uint8>(0);
2671 
2672 					TRACE_CFI("    DW_CFA_advance_loc1: %#" B_PRIx32 "\n",
2673 						delta);
2674 
2675 					target_addr_t location = context.Location()
2676 						+ delta * context.CodeAlignment();
2677 					if (location > context.TargetLocation())
2678 						return B_OK;
2679 					context.SetLocation(location);
2680 					break;
2681 				}
2682 				case DW_CFA_advance_loc2:
2683 				{
2684 					uint32 delta = dataReader.Read<uint16>(0);
2685 
2686 					TRACE_CFI("    DW_CFA_advance_loc2: %#" B_PRIx32 "\n",
2687 						delta);
2688 
2689 					target_addr_t location = context.Location()
2690 						+ delta * context.CodeAlignment();
2691 					if (location > context.TargetLocation())
2692 						return B_OK;
2693 					context.SetLocation(location);
2694 					break;
2695 				}
2696 				case DW_CFA_advance_loc4:
2697 				{
2698 					uint32 delta = dataReader.Read<uint32>(0);
2699 
2700 					TRACE_CFI("    DW_CFA_advance_loc4: %#" B_PRIx32 "\n",
2701 						delta);
2702 
2703 					target_addr_t location = context.Location()
2704 						+ delta * context.CodeAlignment();
2705 					if (location > context.TargetLocation())
2706 						return B_OK;
2707 					context.SetLocation(location);
2708 					break;
2709 				}
2710 				case DW_CFA_offset_extended:
2711 				{
2712 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2713 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2714 
2715 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2716 						"offset: %" B_PRIu64 "\n", reg, offset);
2717 
2718 					if (CfaRule* rule = context.RegisterRule(reg)) {
2719 						rule->SetToLocationOffset(
2720 							offset * context.DataAlignment());
2721 					}
2722 					break;
2723 				}
2724 				case DW_CFA_restore_extended:
2725 				{
2726 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2727 
2728 					TRACE_CFI("    DW_CFA_restore_extended: %#" B_PRIx32 "\n",
2729 						reg);
2730 
2731 					context.RestoreRegisterRule(reg);
2732 					break;
2733 				}
2734 				case DW_CFA_undefined:
2735 				{
2736 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2737 
2738 					TRACE_CFI("    DW_CFA_undefined: %" B_PRIu32 "\n", reg);
2739 
2740 					if (CfaRule* rule = context.RegisterRule(reg))
2741 						rule->SetToUndefined();
2742 					break;
2743 				}
2744 				case DW_CFA_same_value:
2745 				{
2746 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2747 
2748 					TRACE_CFI("    DW_CFA_same_value: %" B_PRIu32 "\n", reg);
2749 
2750 					if (CfaRule* rule = context.RegisterRule(reg))
2751 						rule->SetToSameValue();
2752 					break;
2753 				}
2754 				case DW_CFA_register:
2755 				{
2756 					uint32 reg1 = dataReader.ReadUnsignedLEB128(0);
2757 					uint32 reg2 = dataReader.ReadUnsignedLEB128(0);
2758 
2759 					TRACE_CFI("    DW_CFA_register: reg1: %" B_PRIu32 ", reg2: "
2760 						"%" B_PRIu32 "\n", reg1, reg2);
2761 
2762 					if (CfaRule* rule = context.RegisterRule(reg1))
2763 						rule->SetToValueOffset(reg2);
2764 					break;
2765 				}
2766 				case DW_CFA_remember_state:
2767 				{
2768 					TRACE_CFI("    DW_CFA_remember_state\n");
2769 
2770 					status_t error = context.PushRuleSet();
2771 					if (error != B_OK)
2772 						return error;
2773 					break;
2774 				}
2775 				case DW_CFA_restore_state:
2776 				{
2777 					TRACE_CFI("    DW_CFA_restore_state\n");
2778 
2779 					status_t error = context.PopRuleSet();
2780 					if (error != B_OK)
2781 						return error;
2782 					break;
2783 				}
2784 				case DW_CFA_def_cfa:
2785 				{
2786 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2787 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2788 
2789 					TRACE_CFI("    DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: "
2790 						"%" B_PRIu64 "\n", reg, offset);
2791 
2792 					context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset);
2793 					break;
2794 				}
2795 				case DW_CFA_def_cfa_register:
2796 				{
2797 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2798 
2799 					TRACE_CFI("    DW_CFA_def_cfa_register: %" B_PRIu32 "\n",
2800 						reg);
2801 
2802 					if (context.GetCfaCfaRule()->Type()
2803 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2804 						return B_BAD_DATA;
2805 					}
2806 					context.GetCfaCfaRule()->SetRegister(reg);
2807 					break;
2808 				}
2809 				case DW_CFA_def_cfa_offset:
2810 				{
2811 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2812 
2813 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRIu64 "\n",
2814 						offset);
2815 
2816 					if (context.GetCfaCfaRule()->Type()
2817 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2818 						return B_BAD_DATA;
2819 					}
2820 					context.GetCfaCfaRule()->SetOffset(offset);
2821 					break;
2822 				}
2823 				case DW_CFA_def_cfa_expression:
2824 				{
2825 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2826 					uint8* block = (uint8*)dataReader.Data();
2827 					dataReader.Skip(blockLength);
2828 
2829 					TRACE_CFI("    DW_CFA_def_cfa_expression: %p, %" B_PRIu64
2830 						"\n", block, blockLength);
2831 
2832 					context.GetCfaCfaRule()->SetToExpression(block,
2833 						blockLength);
2834 					break;
2835 				}
2836 				case DW_CFA_expression:
2837 				{
2838 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2839 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2840 					uint8* block = (uint8*)dataReader.Data();
2841 					dataReader.Skip(blockLength);
2842 
2843 					TRACE_CFI("    DW_CFA_expression: reg: %" B_PRIu32 ", "
2844 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2845 
2846 					if (CfaRule* rule = context.RegisterRule(reg))
2847 						rule->SetToLocationExpression(block, blockLength);
2848 					break;
2849 				}
2850 				case DW_CFA_offset_extended_sf:
2851 				{
2852 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2853 					int64 offset = dataReader.ReadSignedLEB128(0);
2854 
2855 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2856 						"offset: %" B_PRId64 "\n", reg, offset);
2857 
2858 					if (CfaRule* rule = context.RegisterRule(reg)) {
2859 						rule->SetToLocationOffset(
2860 							offset * (int32)context.DataAlignment());
2861 					}
2862 					break;
2863 				}
2864 				case DW_CFA_def_cfa_sf:
2865 				{
2866 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2867 					int64 offset = dataReader.ReadSignedLEB128(0);
2868 
2869 					TRACE_CFI("    DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", "
2870 						"offset: %" B_PRId64 "\n", reg, offset);
2871 
2872 					context.GetCfaCfaRule()->SetToRegisterOffset(reg,
2873 						offset * (int32)context.DataAlignment());
2874 					break;
2875 				}
2876 				case DW_CFA_def_cfa_offset_sf:
2877 				{
2878 					int64 offset = dataReader.ReadSignedLEB128(0);
2879 
2880 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRId64 "\n",
2881 						offset);
2882 
2883 					if (context.GetCfaCfaRule()->Type()
2884 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2885 						return B_BAD_DATA;
2886 					}
2887 					context.GetCfaCfaRule()->SetOffset(
2888 						offset * (int32)context.DataAlignment());
2889 					break;
2890 				}
2891 				case DW_CFA_val_offset:
2892 				{
2893 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2894 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2895 
2896 					TRACE_CFI("    DW_CFA_val_offset: reg: %" B_PRIu32 ", "
2897 						"offset: %" B_PRIu64 "\n", reg, offset);
2898 
2899 					if (CfaRule* rule = context.RegisterRule(reg)) {
2900 						rule->SetToValueOffset(
2901 							offset * context.DataAlignment());
2902 					}
2903 					break;
2904 				}
2905 				case DW_CFA_val_offset_sf:
2906 				{
2907 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2908 					int64 offset = dataReader.ReadSignedLEB128(0);
2909 
2910 					TRACE_CFI("    DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", "
2911 						"offset: %" B_PRId64 "\n", reg, offset);
2912 
2913 					if (CfaRule* rule = context.RegisterRule(reg)) {
2914 						rule->SetToValueOffset(
2915 							offset * (int32)context.DataAlignment());
2916 					}
2917 					break;
2918 				}
2919 				case DW_CFA_val_expression:
2920 				{
2921 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2922 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2923 					uint8* block = (uint8*)dataReader.Data();
2924 					dataReader.Skip(blockLength);
2925 
2926 					TRACE_CFI("    DW_CFA_val_expression: reg: %" B_PRIu32 ", "
2927 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2928 
2929 					if (CfaRule* rule = context.RegisterRule(reg))
2930 						rule->SetToValueExpression(block, blockLength);
2931 					break;
2932 				}
2933 
2934 				// extensions
2935 				case DW_CFA_MIPS_advance_loc8:
2936 				{
2937 					uint64 delta = dataReader.Read<uint64>(0);
2938 
2939 					TRACE_CFI("    DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n",
2940 						delta);
2941 
2942 					target_addr_t location = context.Location()
2943 						+ delta * context.CodeAlignment();
2944 					if (location > context.TargetLocation())
2945 						return B_OK;
2946 					context.SetLocation(location);
2947 					break;
2948 				}
2949 				case DW_CFA_GNU_window_save:
2950 				{
2951 					// SPARC specific, no args
2952 					TRACE_CFI("    DW_CFA_GNU_window_save\n");
2953 
2954 					// TODO: Implement once we have SPARC support!
2955 					break;
2956 				}
2957 				case DW_CFA_GNU_args_size:
2958 				{
2959 					// Updates the total size of arguments on the stack.
2960 					TRACE_CFI_ONLY(uint64 size =)
2961 						dataReader.ReadUnsignedLEB128(0);
2962 
2963 					TRACE_CFI("    DW_CFA_GNU_args_size: %" B_PRIu64 "\n",
2964 						size);
2965 // TODO: Implement!
2966 					break;
2967 				}
2968 				case DW_CFA_GNU_negative_offset_extended:
2969 				{
2970 					// obsolete
2971 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2972 					int64 offset = dataReader.ReadSignedLEB128(0);
2973 
2974 					TRACE_CFI("    DW_CFA_GNU_negative_offset_extended: "
2975 						"reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg,
2976 						offset);
2977 
2978 					if (CfaRule* rule = context.RegisterRule(reg)) {
2979 						rule->SetToLocationOffset(
2980 							offset * (int32)context.DataAlignment());
2981 					}
2982 					break;
2983 				}
2984 
2985 				default:
2986 					TRACE_CFI("    unknown opcode %u!\n", opcode);
2987 					return B_BAD_DATA;
2988 			}
2989 		}
2990 	}
2991 
2992 	return B_OK;
2993 }
2994 
2995 
2996 status_t
_ParsePublicTypesInfo(uint8 _addressSize,bool isBigEndian)2997 DwarfFile::_ParsePublicTypesInfo(uint8 _addressSize, bool isBigEndian)
2998 {
2999 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n");
3000 	if (fDebugPublicTypesSection == NULL) {
3001 		TRACE_PUBTYPES("  -> no public types section\n");
3002 		return B_ENTRY_NOT_FOUND;
3003 	}
3004 
3005 	DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(),
3006 		fDebugPublicTypesSection->Size(), _addressSize, isBigEndian);
3007 
3008 	while (dataReader.BytesRemaining() > 0) {
3009 		bool dwarf64;
3010 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
3011 
3012 		off_t unitLengthOffset = dataReader.Offset();
3013 			// the unitLength starts here
3014 
3015 		if (dataReader.HasOverflow())
3016 			return B_BAD_DATA;
3017 
3018 		if (unitLengthOffset + unitLength
3019 				> (uint64)fDebugPublicTypesSection->Size()) {
3020 			WARNING("Invalid public types set unit length.\n");
3021 			break;
3022 		}
3023 
3024 		DataReader unitDataReader(dataReader.Data(), unitLength, _addressSize, isBigEndian);
3025 		_ParsePublicTypesInfo(unitDataReader, dwarf64);
3026 
3027 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
3028 	}
3029 
3030 	return B_OK;
3031 }
3032 
3033 
3034 status_t
_ParsePublicTypesInfo(DataReader & dataReader,bool dwarf64)3035 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64)
3036 {
3037 	int version = dataReader.Read<uint16>(0);
3038 	if (version != 2) {
3039 		TRACE_PUBTYPES("  pubtypes version %d unsupported\n", version);
3040 		return B_UNSUPPORTED;
3041 	}
3042 
3043 	TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64
3044 		? dataReader.Read<uint64>(0)
3045 		: (uint64)dataReader.Read<uint32>(0);
3046 	TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64
3047 		? dataReader.Read<uint64>(0)
3048 		: (uint64)dataReader.Read<uint32>(0);
3049 
3050 	if (dataReader.HasOverflow())
3051 		return B_BAD_DATA;
3052 
3053 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
3054 		"info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset,
3055 		debugInfoSize);
3056 
3057 	while (dataReader.BytesRemaining() > 0) {
3058 		off_t entryOffset = dwarf64
3059 			? dataReader.Read<uint64>(0)
3060 			: (uint64)dataReader.Read<uint32>(0);
3061 		if (entryOffset == 0)
3062 			return B_OK;
3063 
3064 		TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString();
3065 
3066 		TRACE_PUBTYPES("  \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset);
3067 	}
3068 
3069 	return B_OK;
3070 }
3071 
3072 
3073 status_t
_GetAbbreviationTable(off_t offset,AbbreviationTable * & _table)3074 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
3075 {
3076 	// check, whether we've already loaded it
3077 	for (AbbreviationTableList::Iterator it
3078 				= fAbbreviationTables.GetIterator();
3079 			AbbreviationTable* table = it.Next();) {
3080 		if (offset == table->Offset()) {
3081 			_table = table;
3082 			return B_OK;
3083 		}
3084 	}
3085 
3086 	// create a new table
3087 	AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset);
3088 	if (table == NULL)
3089 		return B_NO_MEMORY;
3090 
3091 	status_t error = table->Init(fDebugAbbrevSection->Data(),
3092 		fDebugAbbrevSection->Size());
3093 	if (error != B_OK) {
3094 		delete table;
3095 		return error;
3096 	}
3097 
3098 	fAbbreviationTables.Add(table);
3099 	_table = table;
3100 	return B_OK;
3101 }
3102 
3103 
3104 DebugInfoEntry*
_ResolveReference(BaseUnit * unit,uint64 offset,uint8 refType) const3105 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
3106 	uint8 refType) const
3107 {
3108 	switch (refType) {
3109 		case dwarf_reference_type_local:
3110 			return unit->EntryForOffset(offset);
3111 			break;
3112 		case dwarf_reference_type_global:
3113 		{
3114 			CompilationUnit* unit = _GetContainingCompilationUnit(offset);
3115 			if (unit == NULL)
3116 				break;
3117 
3118 			offset -= unit->HeaderOffset();
3119 			DebugInfoEntry* entry = unit->EntryForOffset(offset);
3120 			if (entry != NULL)
3121 				return entry;
3122 			break;
3123 		}
3124 		case dwarf_reference_type_signature:
3125 		{
3126 			TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset);
3127 			TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
3128 			if (entry != NULL && entry->unit != NULL)
3129 				return entry->unit->TypeEntry();
3130 			break;
3131 		}
3132 	}
3133 
3134 	return NULL;
3135 }
3136 
3137 
3138 status_t
_GetLocationExpression(CompilationUnit * unit,const LocationDescription * location,target_addr_t instructionPointer,const void * & _expression,off_t & _length) const3139 DwarfFile::_GetLocationExpression(CompilationUnit* unit,
3140 	const LocationDescription* location, target_addr_t instructionPointer,
3141 	const void*& _expression, off_t& _length) const
3142 {
3143 	if (!location->IsValid())
3144 		return B_BAD_VALUE;
3145 
3146 	if (location->IsExpression()) {
3147 		_expression = location->expression.data;
3148 		_length = location->expression.length;
3149 		return B_OK;
3150 	}
3151 
3152 	if (location->IsLocationList() && instructionPointer != 0) {
3153 		return _FindLocationExpression(unit, location->listOffset,
3154 			instructionPointer, _expression, _length);
3155 	}
3156 
3157 	return B_BAD_VALUE;
3158 }
3159 
3160 
3161 status_t
_FindLocationExpression(CompilationUnit * unit,uint64 offset,target_addr_t address,const void * & _expression,off_t & _length) const3162 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset,
3163 	target_addr_t address, const void*& _expression, off_t& _length) const
3164 {
3165 	if (unit == NULL)
3166 		return B_BAD_VALUE;
3167 
3168 	if (fDebugLocationSection == NULL)
3169 		return B_ENTRY_NOT_FOUND;
3170 
3171 	if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size())
3172 		return B_BAD_DATA;
3173 
3174 	target_addr_t baseAddress = unit->AddressRangeBase();
3175 	target_addr_t maxAddress = unit->MaxAddress();
3176 
3177 	DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset,
3178 		fDebugLocationSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
3179 	while (true) {
3180 		target_addr_t start = dataReader.ReadAddress(0);
3181 		target_addr_t end = dataReader.ReadAddress(0);
3182 		if (dataReader.HasOverflow())
3183 			return B_BAD_DATA;
3184 
3185 		if (start == 0 && end == 0)
3186 			return B_ENTRY_NOT_FOUND;
3187 
3188 		if (start == maxAddress) {
3189 			baseAddress = end;
3190 			continue;
3191 		}
3192 
3193 		uint16 expressionLength = dataReader.Read<uint16>(0);
3194 		const void* expression = dataReader.Data();
3195 		if (!dataReader.Skip(expressionLength))
3196 			return B_BAD_DATA;
3197 
3198 		if (start == end)
3199 			continue;
3200 
3201 		start += baseAddress;
3202 		end += baseAddress;
3203 
3204 		if (address >= start && address < end) {
3205 			_expression = expression;
3206 			_length = expressionLength;
3207 			return B_OK;
3208 		}
3209 	}
3210 }
3211 
3212 
3213 status_t
_LocateDebugInfo(BString & _requiredExternalFileName,const char * locatedFilePath)3214 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName,
3215 	const char* locatedFilePath)
3216 {
3217 	ElfFile* debugInfoFile = fElfFile;
3218 	ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink");
3219 	if (debugLinkSection != NULL) {
3220 		AutoSectionPutter putter(fElfFile, debugLinkSection);
3221 
3222 		// the file specifies a debug link, look at its target instead
3223 		// for debug information.
3224 		// Format: null-terminated filename, as many 0 padding bytes as
3225 		// needed to reach the next 32-bit address boundary, followed
3226 		// by a 32-bit CRC
3227 
3228 		BString debugPath;
3229 		if (locatedFilePath)
3230 			debugPath = locatedFilePath;
3231 		else {
3232 			status_t result = _GetDebugInfoPath(
3233 				(const char*)debugLinkSection->Data(),
3234 				_requiredExternalFileName);
3235 			if (result != B_OK)
3236 				return result;
3237 			debugPath = _requiredExternalFileName;
3238 		}
3239 
3240 		if (fAlternateName != NULL)
3241 			free(fAlternateName);
3242 
3243 		fAlternateName = strdup(debugPath.String());
3244 
3245 		if (fAlternateName == NULL)
3246 			return B_NO_MEMORY;
3247 
3248 /*
3249 		// TODO: validate CRC
3250 		int32 debugCRC = *(int32*)((char*)debugLinkSection->Data()
3251 			+ debugLinkSection->Size() - sizeof(int32));
3252 */
3253 		if (fAlternateElfFile == NULL) {
3254 			fAlternateElfFile = new(std::nothrow) ElfFile;
3255 			if (fAlternateElfFile == NULL)
3256 				return B_NO_MEMORY;
3257 		}
3258 
3259 		status_t result = fAlternateElfFile->Init(fAlternateName);
3260 		if (result != B_OK)
3261 			return result;
3262 
3263 		debugInfoFile = fAlternateElfFile;
3264 	}
3265 
3266 	// get the interesting sections
3267 	fDebugInfoSection = debugInfoFile->GetSection(".debug_info");
3268 	fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev");
3269 	if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
3270 		TRACE_DIE("DwarfManager::File::Load(\"%s\"): no "
3271 			".debug_info or .debug_abbrev.\n", fName);
3272 
3273 		// if we at least have an EH frame, use that for stack unwinding
3274 		// if nothing else.
3275 		fEHFrameSection = fElfFile->GetSection(".eh_frame");
3276 		if (fEHFrameSection == NULL)
3277 			return B_ERROR;
3278 	}
3279 
3280 	return B_OK;
3281 }
3282 
3283 
3284 status_t
_GetDebugInfoPath(const char * debugFileName,BString & _infoPath) const3285 DwarfFile::_GetDebugInfoPath(const char* debugFileName,
3286 	BString& _infoPath) const
3287 {
3288 	// first, see if we have a relative match to our local directory
3289 	BPath basePath;
3290 	status_t result = basePath.SetTo(fName);
3291 	if (result != B_OK)
3292 		return result;
3293 	basePath.GetParent(&basePath);
3294 	if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(),
3295 			"add-ons") == 0) {
3296 		_infoPath.SetToFormat("%s/../debug/%s", basePath.Path(),
3297 			debugFileName);
3298 	} else
3299 		_infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName);
3300 
3301 	BEntry entry(_infoPath.String());
3302 	result = entry.InitCheck();
3303 	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
3304 		return result;
3305 	if (entry.Exists())
3306 		return B_OK;
3307 
3308 	// If the above search failed, check if our image is located in any
3309 	// of the system installation paths, and attempt to locate the debug info
3310 	// file in the corresponding well-known location
3311 	BString pathSuffix;
3312 	pathSuffix.SetToFormat("debug/%s", debugFileName);
3313 
3314 	BPathFinder finder(fName);
3315 	result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY,
3316 		pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath);
3317 	if (result == B_OK) {
3318 		_infoPath = basePath.Path();
3319 		return B_OK;
3320 	} else {
3321 		// if we failed to find a match, then it's up to the user to
3322 		// locate it. As such, return the external info file name
3323 		// for user interface purposes.
3324 		_infoPath.SetTo(debugFileName);
3325 	}
3326 
3327 	return B_ENTRY_NOT_FOUND;
3328 }
3329 
3330 
3331 TypeUnitTableEntry*
_GetTypeUnit(uint64 signature) const3332 DwarfFile::_GetTypeUnit(uint64 signature) const
3333 {
3334 	return fTypeUnits.Lookup(signature);
3335 }
3336 
3337 
3338 CompilationUnit*
_GetContainingCompilationUnit(off_t refAddr) const3339 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
3340 {
3341 	if (fCompilationUnits.IsEmpty())
3342 		return NULL;
3343 
3344 	// binary search
3345 	int lower = 0;
3346 	int upper = fCompilationUnits.CountItems() - 1;
3347 	while (lower < upper) {
3348 		int mid = (lower + upper + 1) / 2;
3349 		if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr)
3350 			upper = mid - 1;
3351 		else
3352 			lower = mid;
3353 	}
3354 
3355 	CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
3356 	return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
3357 }
3358 
3359 
3360 DwarfFile::FDELookupInfo*
_GetContainingFDEInfo(target_addr_t offset) const3361 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
3362 {
3363 	FDELookupInfo* info = NULL;
3364 	if (fDebugFrameSection != NULL) {
3365 		info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
3366 		if (info != NULL)
3367 			return info;
3368 	}
3369 
3370 	return _GetContainingFDEInfo(offset, fEHFrameInfos);
3371 }
3372 
3373 
3374 DwarfFile::FDELookupInfo*
_GetContainingFDEInfo(target_addr_t offset,const FDEInfoList & infoList) const3375 DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
3376 	const FDEInfoList& infoList) const
3377 {
3378 	// binary search
3379 	int lower = 0;
3380 	int upper = infoList.CountItems() - 1;
3381 	if (upper < 0)
3382 		return NULL;
3383 
3384 	while (lower < upper) {
3385 		int mid = (lower + upper + 1) / 2;
3386 		if (offset < infoList.ItemAt(mid)->start)
3387 			upper = mid - 1;
3388 		else
3389 			lower = mid;
3390 	}
3391 
3392 	FDELookupInfo* info = infoList.ItemAt(lower);
3393 	return info->ContainsAddress(offset) ? info : NULL;
3394 }
3395