xref: /haiku/src/kits/debugger/dwarf/DwarfFile.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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:
39 	AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection)
40 		:
41 		fElfFile(elfFile),
42 		fElfSection(elfSection)
43 	{
44 	}
45 
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:
64 	ExpressionEvaluationContext(DwarfFile* file, CompilationUnit* unit,
65 		uint8 addressSize, 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,
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 
85 	virtual bool GetObjectAddress(target_addr_t& _address)
86 	{
87 		if (!fHasObjectPointer)
88 			return false;
89 
90 		_address = fObjectPointer;
91 		return true;
92 	}
93 
94 	virtual bool GetFrameAddress(target_addr_t& _address)
95 	{
96 		if (fFramePointer == 0)
97 			return false;
98 
99 		_address = fFramePointer;
100 		return true;
101 	}
102 
103 	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 
144 	virtual bool GetTLSAddress(target_addr_t localAddress,
145 		target_addr_t& _address)
146 	{
147 		// TODO:...
148 		return false;
149 	}
150 
151 	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 {
234 	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 
245 	void Init(DataReader& dataReader)
246 	{
247 		fFlags = 0;
248 		fString = dataReader.ReadString();
249 	}
250 
251 	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 
319 	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 
339 	const char* String() const
340 	{
341 		return fString;
342 	}
343 
344 	bool HasData() const
345 	{
346 		return (fFlags & CFI_AUGMENTATION_DATA) != 0;
347 	}
348 
349 	bool HasFDEAddressFormat() const
350 	{
351 		return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0;
352 	}
353 
354 	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 
384 	uint8 FDEAddressType() const
385 	{
386 		return fAddressEncoding & 0x70;
387 	}
388 
389 	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:
450 	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 
461 	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 
471 	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 
487 DwarfFile::DwarfFile()
488 	:
489 	fName(NULL),
490 	fAlternateName(NULL),
491 	fElfFile(NULL),
492 	fAlternateElfFile(NULL),
493 	fDebugInfoSection(NULL),
494 	fDebugAbbrevSection(NULL),
495 	fDebugStringSection(NULL),
496 	fDebugRangesSection(NULL),
497 	fDebugLineSection(NULL),
498 	fDebugFrameSection(NULL),
499 	fEHFrameSection(NULL),
500 	fDebugLocationSection(NULL),
501 	fDebugPublicTypesSection(NULL),
502 	fDebugTypesSection(NULL),
503 	fCompilationUnits(20, true),
504 	fTypeUnits(),
505 	fDebugFrameInfos(100, true),
506 	fEHFrameInfos(100, true),
507 	fTypesSectionRequired(false),
508 	fFinished(false),
509 	fItaniumEHFrameFormat(false),
510 	fFinishError(B_OK)
511 {
512 }
513 
514 
515 DwarfFile::~DwarfFile()
516 {
517 	while (AbbreviationTable* table = fAbbreviationTables.RemoveHead())
518 		delete table;
519 
520 	if (fElfFile != NULL) {
521 		ElfFile* debugInfoFile = fAlternateElfFile != NULL
522 			? fAlternateElfFile : fElfFile;
523 
524 		debugInfoFile->PutSection(fDebugInfoSection);
525 		debugInfoFile->PutSection(fDebugAbbrevSection);
526 		debugInfoFile->PutSection(fDebugStringSection);
527 		debugInfoFile->PutSection(fDebugRangesSection);
528 		debugInfoFile->PutSection(fDebugLineSection);
529 		debugInfoFile->PutSection(fDebugFrameSection);
530 		fElfFile->PutSection(fEHFrameSection);
531 		debugInfoFile->PutSection(fDebugLocationSection);
532 		debugInfoFile->PutSection(fDebugPublicTypesSection);
533 		delete fElfFile;
534 		delete fAlternateElfFile;
535 	}
536 
537 	TypeUnitTableEntry* entry = fTypeUnits.Clear(true);
538 	while (entry != NULL) {
539 		TypeUnitTableEntry* nextEntry = entry->next;
540 		delete entry;
541 		entry = nextEntry;
542 	}
543 
544 	free(fName);
545 	free(fAlternateName);
546 }
547 
548 
549 status_t
550 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
551 {
552 	fName = strdup(fileName);
553 	if (fName == NULL)
554 		return B_NO_MEMORY;
555 
556 	status_t error = fTypeUnits.Init();
557 	if (error != B_OK)
558 		return error;
559 
560 	// load the ELF file
561 	fElfFile = new(std::nothrow) ElfFile;
562 	if (fElfFile == NULL)
563 		return B_NO_MEMORY;
564 
565 	error = fElfFile->Init(fileName);
566 	if (error != B_OK)
567 		return error;
568 
569 	return _LocateDebugInfo(_requiredExternalFile);
570 }
571 
572 
573 status_t
574 DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath)
575 {
576 	status_t error = B_OK;
577 	if (fDebugInfoSection == NULL) {
578 		BString path;
579 		error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty()
580 				? NULL : externalInfoFilePath.String());
581 		if (error != B_OK)
582 			return error;
583 	}
584 
585 	ElfFile* debugInfoFile = fAlternateElfFile != NULL
586 		? fAlternateElfFile : fElfFile;
587 
588 	// non mandatory sections
589 	fDebugStringSection = debugInfoFile->GetSection(".debug_str");
590 	fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
591 	fDebugLineSection = debugInfoFile->GetSection(".debug_line");
592 	fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
593 
594 	if (fDebugFrameSection != NULL) {
595 		error = _ParseFrameSection(fDebugFrameSection, addressSize, false,
596 			fDebugFrameInfos);
597 		if (error != B_OK)
598 			return error;
599 	}
600 
601 	// .eh_frame doesn't appear to get copied into separate debug
602 	// info files properly, therefore always use it off the main
603 	// executable image
604 	if (fEHFrameSection == NULL)
605 		fEHFrameSection = fElfFile->GetSection(".eh_frame");
606 
607 	if (fEHFrameSection != NULL) {
608 		error = _ParseFrameSection(fEHFrameSection, addressSize, true,
609 			fEHFrameInfos);
610 		if (error != B_OK)
611 			return error;
612 	}
613 
614 	fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
615 	fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
616 
617 	if (fDebugInfoSection == NULL) {
618 		fFinished = true;
619 		return B_OK;
620 	}
621 
622 	error = _ParseDebugInfoSection();
623 	if (error != B_OK)
624 		return error;
625 
626 	if (fTypesSectionRequired) {
627 		fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
628 		if (fDebugTypesSection == NULL) {
629 			WARNING(".debug_types section required but missing.\n");
630 			return B_BAD_DATA;
631 		}
632 		error = _ParseTypesSection();
633 		if (error != B_OK)
634 			return error;
635 	}
636 
637 	return B_OK;
638 }
639 
640 
641 status_t
642 DwarfFile::FinishLoading()
643 {
644 	if (fFinished)
645 		return B_OK;
646 	if (fFinishError != B_OK)
647 		return fFinishError;
648 
649 	status_t error;
650 	for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator();
651 		TypeUnitTableEntry* entry = it.Next();) {
652 		error = _FinishUnit(entry->unit);
653 		if (error != B_OK)
654 			return fFinishError = error;
655 	}
656 
657 	for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
658 			i++) {
659 		error = _FinishUnit(unit);
660 		if (error != B_OK)
661 			return fFinishError = error;
662 	}
663 
664 	_ParsePublicTypesInfo();
665 
666 	fFinished = true;
667 	return B_OK;
668 }
669 
670 
671 int32
672 DwarfFile::CountCompilationUnits() const
673 {
674 	return fCompilationUnits.CountItems();
675 }
676 
677 
678 CompilationUnit*
679 DwarfFile::CompilationUnitAt(int32 index) const
680 {
681 	return fCompilationUnits.ItemAt(index);
682 }
683 
684 
685 CompilationUnit*
686 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const
687 {
688 	// find the root of the tree the entry lives in
689 	while (entry != NULL && entry->Parent() != NULL)
690 		entry = entry->Parent();
691 
692 	// that should be the compilation unit entry
693 	const DIECompileUnitBase* unitEntry
694 		= dynamic_cast<const DIECompileUnitBase*>(entry);
695 	if (unitEntry == NULL)
696 		return NULL;
697 
698 	// find the compilation unit
699 	for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
700 			i++) {
701 		if (unit->UnitEntry() == unitEntry)
702 			return unit;
703 	}
704 
705 	return NULL;
706 }
707 
708 
709 TargetAddressRangeList*
710 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
711 {
712 	if (unit == NULL || fDebugRangesSection == NULL)
713 		return NULL;
714 
715 	if (offset >= (uint64)fDebugRangesSection->Size())
716 		return NULL;
717 
718 	TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList;
719 	if (ranges == NULL) {
720 		ERROR("Out of memory.\n");
721 		return NULL;
722 	}
723 	BReference<TargetAddressRangeList> rangesReference(ranges, true);
724 
725 	target_addr_t baseAddress = unit->AddressRangeBase();
726 	target_addr_t maxAddress = unit->MaxAddress();
727 
728 	DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset,
729 		fDebugRangesSection->Size() - offset, unit->AddressSize());
730 	while (true) {
731 		target_addr_t start = dataReader.ReadAddress(0);
732 		target_addr_t end = dataReader.ReadAddress(0);
733 		if (dataReader.HasOverflow())
734 			return NULL;
735 
736 		if (start == 0 && end == 0)
737 			break;
738 		if (start == maxAddress) {
739 			baseAddress = end;
740 			continue;
741 		}
742 		if (start == end)
743 			continue;
744 
745 		if (!ranges->AddRange(baseAddress + start, end - start)) {
746 			ERROR("Out of memory.\n");
747 			return NULL;
748 		}
749 	}
750 
751 	return rangesReference.Detach();
752 }
753 
754 
755 status_t
756 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
757 	DIESubprogram* subprogramEntry, target_addr_t location,
758 	const DwarfTargetInterface* inputInterface,
759 	DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
760 {
761 	FDELookupInfo* info = _GetContainingFDEInfo(location);
762 	if (info == NULL)
763 		return B_ENTRY_NOT_FOUND;
764 
765 	return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info,
766 		inputInterface, outputInterface, _framePointer);
767 }
768 
769 
770 status_t
771 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize,
772 	DIESubprogram* subprogramEntry, const void* expression,
773 	off_t expressionLength, const DwarfTargetInterface* targetInterface,
774 	target_addr_t instructionPointer, target_addr_t framePointer,
775 	target_addr_t valueToPush, bool pushValue, target_addr_t& _result)
776 {
777 	ExpressionEvaluationContext context(this, unit, addressSize,
778 		subprogramEntry, targetInterface, instructionPointer, 0, false,
779 		framePointer, 0);
780 	DwarfExpressionEvaluator evaluator(&context);
781 
782 	if (pushValue && evaluator.Push(valueToPush) != B_OK)
783 		return B_NO_MEMORY;
784 
785 	return evaluator.Evaluate(expression, expressionLength, _result);
786 }
787 
788 
789 status_t
790 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize,
791 	DIESubprogram* subprogramEntry, const LocationDescription* location,
792 	const DwarfTargetInterface* targetInterface,
793 	target_addr_t instructionPointer, target_addr_t objectPointer,
794 	bool hasObjectPointer, target_addr_t framePointer,
795 	target_addr_t relocationDelta, ValueLocation& _result)
796 {
797 	// get the expression
798 	const void* expression;
799 	off_t expressionLength;
800 	status_t error = _GetLocationExpression(unit, location, instructionPointer,
801 		expression, expressionLength);
802 	if (error != B_OK)
803 		return error;
804 
805 	// evaluate it
806 	ExpressionEvaluationContext context(this, unit, addressSize,
807 		subprogramEntry, targetInterface, instructionPointer, objectPointer,
808 		hasObjectPointer, framePointer, relocationDelta);
809 	DwarfExpressionEvaluator evaluator(&context);
810 	return evaluator.EvaluateLocation(expression, expressionLength,
811 		_result);
812 }
813 
814 
815 status_t
816 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize,
817 	DIESubprogram* subprogramEntry, const ConstantAttributeValue* value,
818 	const DwarfTargetInterface* targetInterface,
819 	target_addr_t instructionPointer, target_addr_t framePointer,
820 	BVariant& _result)
821 {
822 	if (!value->IsValid())
823 		return B_BAD_VALUE;
824 
825 	switch (value->attributeClass) {
826 		case ATTRIBUTE_CLASS_CONSTANT:
827 			_result.SetTo(value->constant);
828 			return B_OK;
829 		case ATTRIBUTE_CLASS_STRING:
830 			_result.SetTo(value->string);
831 			return B_OK;
832 		case ATTRIBUTE_CLASS_BLOCK:
833 		{
834 			target_addr_t result;
835 			status_t error = EvaluateExpression(unit, addressSize,
836 				subprogramEntry, value->block.data, value->block.length,
837 				targetInterface, instructionPointer, framePointer, 0, false,
838 				result);
839 			if (error != B_OK)
840 				return error;
841 
842 			_result.SetTo(result);
843 			return B_OK;
844 		}
845 		default:
846 			return B_BAD_VALUE;
847 	}
848 }
849 
850 
851 status_t
852 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize,
853 	DIESubprogram* subprogramEntry, const DynamicAttributeValue* value,
854 	const DwarfTargetInterface* targetInterface,
855 	target_addr_t instructionPointer, target_addr_t framePointer,
856 	BVariant& _result, DIEType** _type)
857 {
858 	if (!value->IsValid())
859 		return B_BAD_VALUE;
860 
861 	DIEType* dummyType;
862 	if (_type == NULL)
863 		_type = &dummyType;
864 
865 	switch (value->attributeClass) {
866 		case ATTRIBUTE_CLASS_CONSTANT:
867 			_result.SetTo(value->constant);
868 			*_type = NULL;
869 			return B_OK;
870 
871 		case ATTRIBUTE_CLASS_REFERENCE:
872 		{
873 			// TODO: The specs are a bit fuzzy on this one: "the value is a
874 			// reference to another entity whose value is the value of the
875 			// attribute". Supposedly that also means e.g. if the referenced
876 			// entity is a variable, we should read the value of that variable.
877 			// ATM we only check for the types that can have a DW_AT_const_value
878 			// attribute and evaluate it, if present.
879 			DebugInfoEntry* entry = value->reference;
880 			if (entry == NULL)
881 				return B_BAD_VALUE;
882 
883 			const ConstantAttributeValue* constantValue = NULL;
884 			DIEType* type = NULL;
885 
886 			switch (entry->Tag()) {
887 				case DW_TAG_constant:
888 				{
889 					DIEConstant* constantEntry
890 						= dynamic_cast<DIEConstant*>(entry);
891 					constantValue = constantEntry->ConstValue();
892 					type = constantEntry->GetType();
893 					break;
894 				}
895 				case DW_TAG_enumerator:
896 					constantValue = dynamic_cast<DIEEnumerator*>(entry)
897 						->ConstValue();
898 					if (DIEEnumerationType* enumerationType
899 							= dynamic_cast<DIEEnumerationType*>(
900 								entry->Parent())) {
901 						type = enumerationType->GetType();
902 					}
903 					break;
904 				case DW_TAG_formal_parameter:
905 				{
906 					DIEFormalParameter* parameterEntry
907 						= dynamic_cast<DIEFormalParameter*>(entry);
908 					constantValue = parameterEntry->ConstValue();
909 					type = parameterEntry->GetType();
910 					break;
911 				}
912 				case DW_TAG_template_value_parameter:
913 				{
914 					DIETemplateValueParameter* parameterEntry
915 						= dynamic_cast<DIETemplateValueParameter*>(entry);
916 					constantValue = parameterEntry->ConstValue();
917 					type = parameterEntry->GetType();
918 					break;
919 				}
920 				case DW_TAG_variable:
921 				{
922 					DIEVariable* variableEntry
923 						= dynamic_cast<DIEVariable*>(entry);
924 					constantValue = variableEntry->ConstValue();
925 					type = variableEntry->GetType();
926 					break;
927 				}
928 				default:
929 					return B_BAD_VALUE;
930 			}
931 
932 			if (constantValue == NULL || !constantValue->IsValid())
933 				return B_BAD_VALUE;
934 
935 			status_t error = EvaluateConstantValue(unit, addressSize,
936 				subprogramEntry, constantValue, targetInterface,
937 				instructionPointer, framePointer, _result);
938 			if (error != B_OK)
939 				return error;
940 
941 			*_type = type;
942 			return B_OK;
943 		}
944 
945 		case ATTRIBUTE_CLASS_BLOCK:
946 		{
947 			target_addr_t result;
948 			status_t error = EvaluateExpression(unit, addressSize,
949 				subprogramEntry, value->block.data, value->block.length,
950 				targetInterface, instructionPointer, framePointer, 0, false,
951 				result);
952 			if (error != B_OK)
953 				return error;
954 
955 			_result.SetTo(result);
956 			*_type = NULL;
957 			return B_OK;
958 		}
959 
960 		default:
961 			return B_BAD_VALUE;
962 	}
963 }
964 
965 
966 status_t
967 DwarfFile::_ParseDebugInfoSection()
968 {
969 	// iterate through the debug info section
970 	DataReader dataReader(fDebugInfoSection->Data(),
971 		fDebugInfoSection->Size(), 4);
972 			// address size doesn't matter here
973 	while (dataReader.HasData()) {
974 		off_t unitHeaderOffset = dataReader.Offset();
975 		bool dwarf64;
976 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
977 
978 		off_t unitLengthOffset = dataReader.Offset();
979 			// the unitLength starts here
980 
981 		if (unitLengthOffset + unitLength
982 				> (uint64)fDebugInfoSection->Size()) {
983 			WARNING("\"%s\": Invalid compilation unit length.\n", fName);
984 			break;
985 		}
986 
987 		int version = dataReader.Read<uint16>(0);
988 		off_t abbrevOffset = dwarf64
989 			? dataReader.Read<uint64>(0)
990 			: dataReader.Read<uint32>(0);
991 		uint8 addressSize = dataReader.Read<uint8>(0);
992 
993 		if (dataReader.HasOverflow()) {
994 			WARNING("\"%s\": Unexpected end of data in compilation unit "
995 				"header.\n", fName);
996 			break;
997 		}
998 
999 		TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
1000 			", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
1001 			dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
1002 
1003 		if (version < 2 || version > 4) {
1004 			WARNING("\"%s\": Unsupported compilation unit version: %d\n",
1005 				fName, version);
1006 			break;
1007 		}
1008 
1009 		if (addressSize != 4 && addressSize != 8) {
1010 			WARNING("\"%s\": Unsupported address size: %d\n", fName,
1011 				addressSize);
1012 			break;
1013 		}
1014 		dataReader.SetAddressSize(addressSize);
1015 
1016 		off_t unitContentOffset = dataReader.Offset();
1017 
1018 		// create a compilation unit object
1019 		CompilationUnit* unit = new(std::nothrow) CompilationUnit(
1020 			unitHeaderOffset, unitContentOffset,
1021 			unitLength + (unitLengthOffset - unitHeaderOffset),
1022 			abbrevOffset, addressSize, dwarf64);
1023 		if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
1024 			delete unit;
1025 			return B_NO_MEMORY;
1026 		}
1027 
1028 		// parse the debug info for the unit
1029 		status_t error = _ParseCompilationUnit(unit);
1030 		if (error != B_OK)
1031 			return error;
1032 
1033 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1034 	}
1035 
1036 	return B_OK;
1037 }
1038 
1039 
1040 status_t
1041 DwarfFile::_ParseTypesSection()
1042 {
1043 	DataReader dataReader(fDebugTypesSection->Data(),
1044 		fDebugTypesSection->Size(), 4);
1045 	while (dataReader.HasData()) {
1046 		off_t unitHeaderOffset = dataReader.Offset();
1047 		bool dwarf64;
1048 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1049 
1050 		off_t unitLengthOffset = dataReader.Offset();
1051 			// the unitLength starts here
1052 
1053 		if (unitLengthOffset + unitLength
1054 				> (uint64)fDebugTypesSection->Size()) {
1055 			WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n",
1056 				unitHeaderOffset);
1057 			break;
1058 		}
1059 
1060 		int version = dataReader.Read<uint16>(0);
1061 		off_t abbrevOffset = dwarf64
1062 			? dataReader.Read<uint64>(0)
1063 			: dataReader.Read<uint32>(0);
1064 		uint8 addressSize = dataReader.Read<uint8>(0);
1065 
1066 		if (dataReader.HasOverflow()) {
1067 			WARNING("Unexpected end of data in type unit header at %#"
1068 				B_PRIx64 ".\n", unitHeaderOffset);
1069 			break;
1070 		}
1071 
1072 		dataReader.SetAddressSize(addressSize);
1073 
1074 		uint64 signature = dataReader.Read<uint64>(0);
1075 
1076 		off_t typeOffset = dwarf64
1077 			? dataReader.Read<uint64>(0)
1078 			: dataReader.Read<uint32>(0);
1079 
1080 		off_t unitContentOffset = dataReader.Offset();
1081 
1082 		TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64
1083 			", abbrevOffset: %" B_PRIdOFF ", address size: %d, "
1084 			"signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n",
1085 			dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize,
1086 			signature, typeOffset);
1087 
1088 		if (version > 4) {
1089 			WARNING("\"%s\": Unsupported type unit version: %d\n",
1090 				fName, version);
1091 			break;
1092 		}
1093 
1094 		if (addressSize != 4 && addressSize != 8) {
1095 			WARNING("\"%s\": Unsupported address size: %d\n", fName,
1096 				addressSize);
1097 			break;
1098 		}
1099 
1100 		// create a type unit object
1101 		TypeUnit* unit = new(std::nothrow) TypeUnit(
1102 			unitHeaderOffset, unitContentOffset,
1103 			unitLength + (unitLengthOffset - unitHeaderOffset),
1104 			abbrevOffset, typeOffset, addressSize, signature, dwarf64);
1105 		if (unit == NULL)
1106 			return B_NO_MEMORY;
1107 
1108 		// parse the debug info for the unit
1109 		status_t error = _ParseTypeUnit(unit);
1110 		if (error != B_OK)
1111 			return error;
1112 
1113 		// TODO: it should theoretically never happen that we get a duplicate,
1114 		// but it wouldn't hurt to check since that situation would potentially
1115 		// be problematic.
1116 		if (fTypeUnits.Lookup(signature) == NULL) {
1117 			TypeUnitTableEntry* entry = new(std::nothrow)
1118 				TypeUnitTableEntry(signature, unit);
1119 			if (entry == NULL)
1120 				return B_NO_MEMORY;
1121 
1122 			fTypeUnits.Insert(entry);
1123 		}
1124 
1125 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1126 	}
1127 
1128 	return B_OK;
1129 }
1130 
1131 
1132 status_t
1133 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize,
1134 	bool ehFrame, FDEInfoList& infos)
1135 {
1136 	if (ehFrame) {
1137 		fItaniumEHFrameFormat = section->IsWritable();
1138 			// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
1139 			// .eh_frame sections. The ones generated by GCC 2 are writable,
1140 			// the ones generated by GCC 4 aren't.
1141 	}
1142 
1143 	DataReader dataReader((uint8*)section->Data(),
1144 		section->Size(), addressSize);
1145 
1146 	while (dataReader.BytesRemaining() > 0) {
1147 		// length
1148 		bool dwarf64;
1149 		off_t entryOffset = dataReader.Offset();
1150 		uint64 length = dataReader.ReadInitialLength(dwarf64);
1151 
1152 		TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF
1153 			", length: %" B_PRId64 "\n", entryOffset, length);
1154 
1155 		if (length > (uint64)dataReader.BytesRemaining())
1156 			return B_BAD_DATA;
1157 		off_t lengthOffset = dataReader.Offset();
1158 
1159 		// If the length is 0, it means a terminator of the CIE.
1160 		// Then just skip this .debug_frame/.eh_frame section.
1161 		if (length == 0)
1162 			return B_OK;
1163 
1164 		// CIE ID/CIE pointer
1165 		uint64 cieID = dwarf64
1166 			? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1167 
1168 		// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
1169 		if (ehFrame
1170 			? cieID == 0
1171 			: (dwarf64
1172 				? cieID == 0xffffffffffffffffULL
1173 				: cieID == 0xffffffff)) {
1174 			// this is a CIE -- skip it
1175 		} else {
1176 			// this is a FDE
1177 			uint64 initialLocationOffset = dataReader.Offset();
1178 			// In .eh_frame the CIE offset is a relative back offset.
1179 			if (ehFrame) {
1180 				if (cieID > (uint64)lengthOffset) {
1181 					TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
1182 						"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
1183 					break;
1184 				}
1185 				// convert to a section relative offset
1186 				cieID = lengthOffset - cieID;
1187 			}
1188 
1189 
1190 			CfaContext context;
1191 			CIEAugmentation cieAugmentation;
1192 			// when using .eh_frame format, we need to parse the CIE's
1193 			// augmentation up front in order to know how the FDE's addresses
1194 			//  will be represented
1195 			DataReader cieReader;
1196 			off_t cieRemaining;
1197 			status_t error = _ParseCIEHeader(section, ehFrame, NULL,
1198 				addressSize, context, cieID, cieAugmentation, cieReader,
1199 				cieRemaining);
1200 			if (error != B_OK)
1201 				return error;
1202 			if (cieReader.HasOverflow())
1203 				return B_BAD_DATA;
1204 			if (cieRemaining < 0)
1205 				return B_BAD_DATA;
1206 
1207 			target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
1208 				dataReader, fElfFile, section);
1209 			target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
1210 				dataReader, fElfFile, section, true);
1211 
1212 			if (dataReader.HasOverflow())
1213 				return B_BAD_DATA;
1214 
1215 			if ((cieAugmentation.FDEAddressType()
1216 					& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
1217 				initialLocation += initialLocationOffset;
1218 			}
1219 
1220 			// for unknown reasons, the debug frame sections generated by gcc
1221 			// sometimes contain duplicates at different offsets within the
1222 			// section. In such a case, simply skip the duplicates.
1223 			FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
1224 				infos);
1225 			if (temp == NULL) {
1226 				FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
1227 					initialLocation, initialLocation + addressRange - 1,
1228 					entryOffset, cieID, ehFrame);
1229 				if (info == NULL)
1230 					return B_NO_MEMORY;
1231 
1232 				ObjectDeleter<FDELookupInfo> infoDeleter(info);
1233 				if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
1234 					return B_NO_MEMORY;
1235 
1236 				infoDeleter.Detach();
1237 			}
1238 		}
1239 
1240 		dataReader.SeekAbsolute(lengthOffset + length);
1241 	}
1242 
1243 	return B_OK;
1244 }
1245 
1246 
1247 status_t
1248 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
1249 {
1250 	AbbreviationTable* abbreviationTable;
1251 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1252 		abbreviationTable);
1253 	if (error != B_OK)
1254 		return error;
1255 
1256 	unit->SetAbbreviationTable(abbreviationTable);
1257 
1258 	DataReader dataReader(
1259 		(const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(),
1260 		unit->ContentSize(), unit->AddressSize());
1261 
1262 	DebugInfoEntry* entry;
1263 	bool endOfEntryList;
1264 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1265 		endOfEntryList);
1266 	if (error != B_OK)
1267 		return error;
1268 
1269 	DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry);
1270 	if (unitEntry == NULL) {
1271 		WARNING("No compilation unit entry in .debug_info section.\n");
1272 		return B_BAD_DATA;
1273 	}
1274 
1275 	unit->SetUnitEntry(unitEntry);
1276 
1277 	TRACE_DIE_ONLY(
1278 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1279 			dataReader.BytesRemaining());
1280 		if (dataReader.HasData()) {
1281 			TRACE_DIE("  ");
1282 			while (dataReader.HasData())
1283 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1284 			TRACE_DIE("\n");
1285 		}
1286 	)
1287 	return B_OK;
1288 }
1289 
1290 
1291 status_t
1292 DwarfFile::_ParseTypeUnit(TypeUnit* unit)
1293 {
1294 	AbbreviationTable* abbreviationTable;
1295 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1296 		abbreviationTable);
1297 	if (error != B_OK)
1298 		return error;
1299 
1300 	unit->SetAbbreviationTable(abbreviationTable);
1301 
1302 	DataReader dataReader(
1303 		(const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
1304 		unit->ContentSize(), unit->AddressSize());
1305 
1306 	DebugInfoEntry* entry;
1307 	bool endOfEntryList;
1308 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1309 		endOfEntryList);
1310 	if (error != B_OK)
1311 		return error;
1312 
1313 	DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
1314 	if (unitEntry == NULL) {
1315 		WARNING("No type unit entry in .debug_types section.\n");
1316 		return B_BAD_DATA;
1317 	}
1318 
1319 	unit->SetUnitEntry(unitEntry);
1320 	DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset());
1321 	if (typeEntry == NULL) {
1322 		WARNING("No type found for type unit %p at specified offset %"
1323 			B_PRId64 ".\n", unit, unit->TypeOffset());
1324 		return B_BAD_DATA;
1325 	}
1326 	unit->SetTypeEntry(typeEntry);
1327 
1328 	TRACE_DIE_ONLY(
1329 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1330 			dataReader.BytesRemaining());
1331 		if (dataReader.HasData()) {
1332 			TRACE_DIE("  ");
1333 			while (dataReader.HasData())
1334 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1335 			TRACE_DIE("\n");
1336 		}
1337 	)
1338 	return B_OK;
1339 }
1340 
1341 
1342 status_t
1343 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
1344 	BaseUnit* unit, AbbreviationTable* abbreviationTable,
1345 	DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
1346 {
1347 	off_t entryOffset = dataReader.Offset()
1348 		+ unit->RelativeContentOffset();
1349 
1350 	uint32 code = dataReader.ReadUnsignedLEB128(0);
1351 	if (code == 0) {
1352 		if (dataReader.HasOverflow()) {
1353 			WARNING("Unexpected end of .debug_info section.\n");
1354 			return B_BAD_DATA;
1355 		}
1356 		_entry = NULL;
1357 		_endOfEntryList = true;
1358 		return B_OK;
1359 	}
1360 
1361 	// get the corresponding abbreviation entry
1362 	AbbreviationEntry abbreviationEntry;
1363 	if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
1364 		WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
1365 		return B_BAD_DATA;
1366 	}
1367 
1368 	DebugInfoEntry* entry;
1369 	status_t error = fDebugInfoFactory.CreateDebugInfoEntry(
1370 		abbreviationEntry.Tag(), entry);
1371 	if (error != B_OK) {
1372 		WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %"
1373 			B_PRIu32 "\n", abbreviationEntry.Tag(), code);
1374 		return error;
1375 	}
1376 
1377 	ObjectDeleter<DebugInfoEntry> entryDeleter(entry);
1378 
1379 	TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%"
1380 		B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset,
1381 		abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
1382 		abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
1383 
1384 	error = unit->AddDebugInfoEntry(entry, entryOffset);
1385 
1386 	if (error != B_OK)
1387 		return error;
1388 
1389 	// parse the attributes (supply NULL entry to avoid adding them yet)
1390 	error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
1391 	if (error != B_OK)
1392 		return error;
1393 
1394 	// parse children, if the entry has any
1395 	if (abbreviationEntry.HasChildren()) {
1396 		while (true) {
1397 			DebugInfoEntry* childEntry;
1398 			bool endOfEntryList;
1399 			status_t error = _ParseDebugInfoEntry(dataReader,
1400 				unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
1401 			if (error != B_OK)
1402 				return error;
1403 
1404 			// add the child to our entry
1405 			if (childEntry != NULL) {
1406 				if (entry != NULL) {
1407 					error = entry->AddChild(childEntry);
1408 					if (error == B_OK) {
1409 						childEntry->SetParent(entry);
1410 					} else if (error == ENTRY_NOT_HANDLED) {
1411 						error = B_OK;
1412 						TRACE_DIE("%*s  -> child unhandled\n", level * 2, "");
1413 					}
1414 
1415 					if (error != B_OK) {
1416 						delete childEntry;
1417 						return error;
1418 					}
1419 				} else
1420 					delete childEntry;
1421 			}
1422 
1423 			if (endOfEntryList)
1424 				break;
1425 		}
1426 	}
1427 
1428 	entryDeleter.Detach();
1429 	_entry = entry;
1430 	_endOfEntryList = false;
1431 	return B_OK;
1432 }
1433 
1434 
1435 status_t
1436 DwarfFile::_FinishUnit(BaseUnit* unit)
1437 {
1438 	CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
1439 	bool isTypeUnit = compilationUnit == NULL;
1440 	TRACE_DIE("\nfinishing %s unit %p\n",
1441 		isTypeUnit ? "type" : "compilation", unit);
1442 
1443 
1444 	AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
1445 
1446 	ElfSection* section = isTypeUnit
1447 			? fDebugTypesSection : fDebugInfoSection;
1448 	DataReader dataReader(
1449 		(const uint8*)section->Data() + unit->HeaderOffset(),
1450 		unit->TotalSize(), unit->AddressSize());
1451 
1452 	DebugInfoEntryInitInfo entryInitInfo;
1453 
1454 	int entryCount = unit->CountEntries();
1455 	for (int i = 0; i < entryCount; i++) {
1456 		// get the entry
1457 		DebugInfoEntry* entry;
1458 		off_t offset;
1459 		unit->GetEntryAt(i, entry, offset);
1460 
1461 		TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset);
1462 
1463 		// seek the reader to the entry
1464 		dataReader.SeekAbsolute(offset);
1465 
1466 		// read the entry code
1467 		uint32 code = dataReader.ReadUnsignedLEB128(0);
1468 
1469 		// get the respective abbreviation entry
1470 		AbbreviationEntry abbreviationEntry;
1471 		abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry);
1472 
1473 		// initialization before setting the attributes
1474 		status_t error = entry->InitAfterHierarchy(entryInitInfo);
1475 		if (error != B_OK) {
1476 			WARNING("Init after hierarchy failed!\n");
1477 			return error;
1478 		}
1479 
1480 		// parse the attributes -- this time pass the entry, so that the
1481 		// attribute get set on it
1482 		error = _ParseEntryAttributes(dataReader, unit, entry,
1483 			abbreviationEntry);
1484 		if (error != B_OK)
1485 			return error;
1486 
1487 		// initialization after setting the attributes
1488 		error = entry->InitAfterAttributes(entryInitInfo);
1489 		if (error != B_OK) {
1490 			WARNING("Init after attributes failed!\n");
1491 			return error;
1492 		}
1493 	}
1494 
1495 	// set the compilation unit's source language
1496 	unit->SetSourceLanguage(entryInitInfo.languageInfo);
1497 
1498 	if (isTypeUnit)
1499 		return B_OK;
1500 
1501 	// resolve the compilation unit's address range list
1502 	if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
1503 			compilationUnit->UnitEntry()->AddressRangesOffset())) {
1504 		compilationUnit->SetAddressRanges(ranges);
1505 		ranges->ReleaseReference();
1506 	}
1507 
1508 	// add compilation dir to directory list
1509 	const char* compilationDir = compilationUnit->UnitEntry()
1510 		->CompilationDir();
1511 	if (!compilationUnit->AddDirectory(compilationDir != NULL
1512 				? compilationDir : ".")) {
1513 		return B_NO_MEMORY;
1514 	}
1515 
1516 	// parse line info header
1517 	if (fDebugLineSection != NULL)
1518 		_ParseLineInfo(compilationUnit);
1519 
1520 	return B_OK;
1521 }
1522 
1523 
1524 status_t
1525 DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
1526 	BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
1527 {
1528 	uint32 attributeName;
1529 	uint32 attributeForm;
1530 	while (abbreviationEntry.GetNextAttribute(attributeName,
1531 			attributeForm)) {
1532 		// resolve attribute form indirection
1533 		if (attributeForm == DW_FORM_indirect)
1534 			attributeForm = dataReader.ReadUnsignedLEB128(0);
1535 
1536 		// prepare an AttributeValue
1537 		AttributeValue attributeValue;
1538 		attributeValue.attributeForm = attributeForm;
1539 		bool isSigned = false;
1540 
1541 		// Read the attribute value according to the attribute's form. For
1542 		// the forms that don't map to a single attribute class only or
1543 		// those that need additional processing, we read a temporary value
1544 		// first.
1545 		uint64 value = 0;
1546 		off_t blockLength = 0;
1547 		off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
1548 		uint8 refType = dwarf_reference_type_local;
1549 
1550 		switch (attributeForm) {
1551 			case DW_FORM_addr:
1552 				value = dataReader.ReadAddress(0);
1553 				break;
1554 			case DW_FORM_block2:
1555 				blockLength = dataReader.Read<uint16>(0);
1556 				break;
1557 			case DW_FORM_block4:
1558 				blockLength = dataReader.Read<uint32>(0);
1559 				break;
1560 			case DW_FORM_data2:
1561 				value = dataReader.Read<uint16>(0);
1562 				break;
1563 			case DW_FORM_data4:
1564 				value = dataReader.Read<uint32>(0);
1565 				break;
1566 			case DW_FORM_data8:
1567 				value = dataReader.Read<uint64>(0);
1568 				break;
1569 			case DW_FORM_string:
1570 				attributeValue.SetToString(dataReader.ReadString());
1571 				break;
1572 			case DW_FORM_block:
1573 			case DW_FORM_exprloc:
1574 				blockLength = dataReader.ReadUnsignedLEB128(0);
1575 				break;
1576 			case DW_FORM_block1:
1577 				blockLength = dataReader.Read<uint8>(0);
1578 				break;
1579 			case DW_FORM_data1:
1580 				value = dataReader.Read<uint8>(0);
1581 				break;
1582 			case DW_FORM_flag:
1583 				attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0);
1584 				break;
1585 			case DW_FORM_sdata:
1586 				value = dataReader.ReadSignedLEB128(0);
1587 				isSigned = true;
1588 				break;
1589 			case DW_FORM_strp:
1590 			{
1591 				if (fDebugStringSection != NULL) {
1592 					uint64 offset = unit->IsDwarf64()
1593 						? dataReader.Read<uint64>(0)
1594 						: dataReader.Read<uint32>(0);
1595 					if (offset >= fDebugStringSection->Size()) {
1596 						WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1597 							offset);
1598 						return B_BAD_DATA;
1599 					}
1600 					attributeValue.SetToString(
1601 						(const char*)fDebugStringSection->Data() + offset);
1602 				} else {
1603 					WARNING("Invalid DW_FORM_strp: no string section!\n");
1604 					return B_BAD_DATA;
1605 				}
1606 				break;
1607 			}
1608 			case DW_FORM_udata:
1609 				value = dataReader.ReadUnsignedLEB128(0);
1610 				break;
1611 			case DW_FORM_ref_addr:
1612 				value = unit->IsDwarf64()
1613 					? dataReader.Read<uint64>(0)
1614 					: (uint64)dataReader.Read<uint32>(0);
1615 				refType = dwarf_reference_type_global;
1616 				break;
1617 			case DW_FORM_ref1:
1618 				value = dataReader.Read<uint8>(0);
1619 				break;
1620 			case DW_FORM_ref2:
1621 				value = dataReader.Read<uint16>(0);
1622 				break;
1623 			case DW_FORM_ref4:
1624 				value = dataReader.Read<uint32>(0);
1625 				break;
1626 			case DW_FORM_ref8:
1627 				value = dataReader.Read<uint64>(0);
1628 				break;
1629 			case DW_FORM_ref_udata:
1630 				value = dataReader.ReadUnsignedLEB128(0);
1631 				break;
1632 			case DW_FORM_flag_present:
1633 				attributeValue.SetToFlag(true);
1634 				break;
1635 			case DW_FORM_ref_sig8:
1636 				fTypesSectionRequired = true;
1637 				value = dataReader.Read<uint64>(0);
1638 				refType = dwarf_reference_type_signature;
1639 				break;
1640 			case DW_FORM_sec_offset:
1641 				value = unit->IsDwarf64()
1642 					? dataReader.Read<uint64>(0)
1643 					: (uint64)dataReader.Read<uint32>(0);
1644 				break;
1645 			case DW_FORM_indirect:
1646 			default:
1647 				WARNING("Unsupported attribute form: %" B_PRIu32 "\n",
1648 					attributeForm);
1649 				return B_BAD_DATA;
1650 		}
1651 
1652 		// get the attribute class -- skip the attribute, if we can't handle
1653 		// it
1654 		uint8 attributeClass = get_attribute_class(attributeName,
1655 			attributeForm);
1656 
1657 		if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
1658 			TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
1659 				B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
1660 				get_attribute_name_name(attributeName), attributeName,
1661 				get_attribute_form_name(attributeForm), attributeForm);
1662 			continue;
1663 		}
1664 
1665 		// set the attribute value according to the attribute's class
1666 		switch (attributeClass) {
1667 			case ATTRIBUTE_CLASS_ADDRESS:
1668 				attributeValue.SetToAddress(value);
1669 				break;
1670 			case ATTRIBUTE_CLASS_BLOCK:
1671 				attributeValue.SetToBlock(dataReader.Data(), blockLength);
1672 				dataReader.Skip(blockLength);
1673 				break;
1674 			case ATTRIBUTE_CLASS_CONSTANT:
1675 				attributeValue.SetToConstant(value, isSigned);
1676 				break;
1677 			case ATTRIBUTE_CLASS_LINEPTR:
1678 				attributeValue.SetToLinePointer(value);
1679 				break;
1680 			case ATTRIBUTE_CLASS_LOCLISTPTR:
1681 				attributeValue.SetToLocationListPointer(value);
1682 				break;
1683 			case ATTRIBUTE_CLASS_MACPTR:
1684 				attributeValue.SetToMacroPointer(value);
1685 				break;
1686 			case ATTRIBUTE_CLASS_RANGELISTPTR:
1687 				attributeValue.SetToRangeListPointer(value);
1688 				break;
1689 			case ATTRIBUTE_CLASS_REFERENCE:
1690 				if (entry != NULL) {
1691 					attributeValue.SetToReference(_ResolveReference(
1692 						unit, value, refType));
1693 					if (attributeValue.reference == NULL) {
1694 						// gcc 2 apparently somtimes produces DW_AT_sibling
1695 						// attributes pointing to the end of the sibling list.
1696 						// Just ignore those.
1697 						if (attributeName == DW_AT_sibling)
1698 							continue;
1699 
1700 						WARNING("Failed to resolve reference on entry %p: "
1701 							"(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
1702 							"(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
1703 							entry,
1704 							valueOffset,
1705 							get_attribute_name_name(attributeName),
1706 							attributeName,
1707 							get_attribute_form_name(attributeForm),
1708 							attributeForm, value);
1709 						return B_ENTRY_NOT_FOUND;
1710 					}
1711 				}
1712 				break;
1713 			case ATTRIBUTE_CLASS_FLAG:
1714 			case ATTRIBUTE_CLASS_STRING:
1715 				// already set
1716 				break;
1717 		}
1718 
1719 		if (dataReader.HasOverflow()) {
1720 			WARNING("Unexpected end of .debug_info section.\n");
1721 			return B_BAD_DATA;
1722 		}
1723 
1724 		TRACE_DIE_ONLY(
1725 			char buffer[1024];
1726 			TRACE_DIE("  attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
1727 				valueOffset,
1728 				get_attribute_name_name(attributeName),
1729 				get_attribute_form_name(attributeForm), attributeClass,
1730 				attributeValue.ToString(buffer, sizeof(buffer)));
1731 		)
1732 
1733 		// add the attribute
1734 		if (entry != NULL) {
1735 			DebugInfoEntrySetter attributeSetter
1736 				= get_attribute_name_setter(attributeName);
1737 			if (attributeSetter != 0) {
1738 				status_t error = (entry->*attributeSetter)(attributeName,
1739 					attributeValue);
1740 
1741 				if (error == ATTRIBUTE_NOT_HANDLED) {
1742 					error = B_OK;
1743 					TRACE_DIE("    -> unhandled\n");
1744 				}
1745 
1746 				if (error != B_OK) {
1747 					WARNING("Failed to set attribute: name: %s, form: %s: %s\n",
1748 						get_attribute_name_name(attributeName),
1749 						get_attribute_form_name(attributeForm),
1750 						strerror(error));
1751 				}
1752 			} else
1753 				TRACE_DIE("    -> no attribute setter!\n");
1754 		}
1755 	}
1756 
1757 	return B_OK;
1758 }
1759 
1760 
1761 status_t
1762 DwarfFile::_ParseLineInfo(CompilationUnit* unit)
1763 {
1764 	off_t offset = unit->UnitEntry()->StatementListOffset();
1765 
1766 	TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit,
1767 		offset);
1768 
1769 	DataReader dataReader((uint8*)fDebugLineSection->Data() + offset,
1770 		fDebugLineSection->Size() - offset, unit->AddressSize());
1771 
1772 	// unit length
1773 	bool dwarf64;
1774 	uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1775 	if (unitLength > (uint64)dataReader.BytesRemaining())
1776 		return B_BAD_DATA;
1777 	off_t unitOffset = dataReader.Offset();
1778 
1779 	// version (uhalf)
1780 	uint16 version = dataReader.Read<uint16>(0);
1781 
1782 	// header_length (4/8)
1783 	uint64 headerLength = dwarf64
1784 		? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
1785 	off_t headerOffset = dataReader.Offset();
1786 
1787 	if ((uint64)dataReader.BytesRemaining() < headerLength)
1788 		return B_BAD_DATA;
1789 
1790 	// minimum instruction length
1791 	uint8 minInstructionLength = dataReader.Read<uint8>(0);
1792 
1793 	// default is statement
1794 	bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
1795 
1796 	// line_base (sbyte)
1797 	int8 lineBase = (int8)dataReader.Read<uint8>(0);
1798 
1799 	// line_range (ubyte)
1800 	uint8 lineRange = dataReader.Read<uint8>(0);
1801 
1802 	// opcode_base (ubyte)
1803 	uint8 opcodeBase = dataReader.Read<uint8>(0);
1804 
1805 	// standard_opcode_lengths (ubyte[])
1806 	const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
1807 	dataReader.Skip(opcodeBase - 1);
1808 
1809 	if (dataReader.HasOverflow())
1810 		return B_BAD_DATA;
1811 
1812 	if (version != 2 && version != 3)
1813 		return B_UNSUPPORTED;
1814 
1815 	TRACE_LINES("  unitLength:           %" B_PRIu64 "\n", unitLength);
1816 	TRACE_LINES("  version:              %u\n", version);
1817 	TRACE_LINES("  headerLength:         %" B_PRIu64 "\n", headerLength);
1818 	TRACE_LINES("  minInstructionLength: %u\n", minInstructionLength);
1819 	TRACE_LINES("  defaultIsStatement:   %d\n", defaultIsStatement);
1820 	TRACE_LINES("  lineBase:             %d\n", lineBase);
1821 	TRACE_LINES("  lineRange:            %u\n", lineRange);
1822 	TRACE_LINES("  opcodeBase:           %u\n", opcodeBase);
1823 
1824 	// include directories
1825 	TRACE_LINES("  include directories:\n");
1826 	while (const char* directory = dataReader.ReadString()) {
1827 		if (*directory == '\0')
1828 			break;
1829 		TRACE_LINES("    \"%s\"\n", directory);
1830 
1831 		if (!unit->AddDirectory(directory))
1832 			return B_NO_MEMORY;
1833 	}
1834 
1835 	// file names
1836 	TRACE_LINES("  files:\n");
1837 	while (const char* file = dataReader.ReadString()) {
1838 		if (*file == '\0')
1839 			break;
1840 		uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
1841 		TRACE_LINES_ONLY(uint64 modificationTime =)
1842 			dataReader.ReadUnsignedLEB128(0);
1843 		TRACE_LINES_ONLY(uint64 fileLength =)
1844 			dataReader.ReadUnsignedLEB128(0);
1845 
1846 		if (dataReader.HasOverflow())
1847 			return B_BAD_DATA;
1848 
1849 		TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
1850 			", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
1851 			fileLength);
1852 
1853 		if (!unit->AddFile(file, dirIndex))
1854 			return B_NO_MEMORY;
1855 	}
1856 
1857 	off_t readerOffset = dataReader.Offset();
1858 	if ((uint64)readerOffset > readerOffset + headerLength)
1859 		return B_BAD_DATA;
1860 	off_t offsetToProgram = headerOffset + headerLength - readerOffset;
1861 
1862 	const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
1863 	size_t programSize = unitLength - (readerOffset - unitOffset);
1864 
1865 	return unit->GetLineNumberProgram().Init(program, programSize,
1866 		minInstructionLength, defaultIsStatement, lineBase, lineRange,
1867 			opcodeBase, standardOpcodeLengths);
1868 }
1869 
1870 
1871 status_t
1872 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
1873 	DIESubprogram* subprogramEntry, target_addr_t location,
1874 	const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
1875 	DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
1876 {
1877 	ElfSection* currentFrameSection = (info->ehFrame)
1878 		? fEHFrameSection : fDebugFrameSection;
1879 
1880 	TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
1881 
1882 	DataReader dataReader((uint8*)currentFrameSection->Data(),
1883 		currentFrameSection->Size(), unit != NULL
1884 			? unit->AddressSize() : addressSize);
1885 	dataReader.SeekAbsolute(info->fdeOffset);
1886 
1887 	bool dwarf64;
1888 	uint64 length = dataReader.ReadInitialLength(dwarf64);
1889 	uint64 lengthOffset = dataReader.Offset();
1890 
1891 	CfaContext context;
1892 	CIEAugmentation cieAugmentation;
1893 	// when using .eh_frame format, we need to parse the CIE's
1894 	// augmentation up front in order to know how the FDE's addresses
1895 	//  will be represented
1896 	DataReader cieReader;
1897 	off_t cieRemaining;
1898 	status_t error = _ParseCIEHeader(currentFrameSection,
1899 		info->ehFrame, unit, addressSize, context, info->cieOffset,
1900 		cieAugmentation, cieReader, cieRemaining);
1901 	if (error != B_OK)
1902 		return error;
1903 	if (cieReader.HasOverflow())
1904 		return B_BAD_DATA;
1905 	if (cieRemaining < 0)
1906 		return B_BAD_DATA;
1907 
1908 	// skip CIE ID, initial offset and range, since we already know those
1909 	// from FDELookupInfo.
1910 	dwarf64	? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1911 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1912 		currentFrameSection);
1913 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1914 		currentFrameSection, true);
1915 
1916 	TRACE_CFI("  found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
1917 		"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
1918 		"range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
1919 		info->cieOffset, info->start, info->end - info->start);
1920 
1921 	context.SetLocation(location, info->start);
1922 	uint32 registerCount = outputInterface->CountRegisters();
1923 	error = context.Init(registerCount);
1924 	if (error != B_OK)
1925 		return error;
1926 
1927 	error = outputInterface->InitRegisterRules(context);
1928 	if (error != B_OK)
1929 		return error;
1930 
1931 	// process the CIE's frame info instructions
1932 	cieReader = cieReader.RestrictedReader(cieRemaining);
1933 	error = _ParseFrameInfoInstructions(unit, context,
1934 		cieReader, cieAugmentation);
1935 	if (error != B_OK)
1936 		return error;
1937 
1938 	// read the FDE augmentation data (if any)
1939 	FDEAugmentation fdeAugmentation;
1940 	error = cieAugmentation.ReadFDEData(dataReader,
1941 		fdeAugmentation);
1942 	if (error != B_OK) {
1943 		TRACE_CFI("  failed to read FDE augmentation data!\n");
1944 		return error;
1945 	}
1946 
1947 	error = context.SaveInitialRuleSet();
1948 	if (error != B_OK)
1949 		return error;
1950 
1951 	uint64 remaining = lengthOffset + length - dataReader.Offset();
1952 	if (remaining < 0)
1953 		return B_BAD_DATA;
1954 
1955 	DataReader restrictedReader =
1956 		dataReader.RestrictedReader(remaining);
1957 	error = _ParseFrameInfoInstructions(unit, context,
1958 		restrictedReader, cieAugmentation);
1959 	if (error != B_OK)
1960 		return error;
1961 
1962 	TRACE_CFI("  found row!\n");
1963 
1964 	// apply the rules of the final row
1965 	// get the frameAddress first
1966 	target_addr_t frameAddress;
1967 	CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
1968 	switch (cfaCfaRule->Type()) {
1969 		case CFA_CFA_RULE_REGISTER_OFFSET:
1970 		{
1971 			BVariant value;
1972 			if (!inputInterface->GetRegisterValue(
1973 					cfaCfaRule->Register(), value)
1974 				|| !value.IsNumber()) {
1975 				return B_UNSUPPORTED;
1976 			}
1977 			frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
1978 			break;
1979 		}
1980 		case CFA_CFA_RULE_EXPRESSION:
1981 		{
1982 			error = EvaluateExpression(unit, addressSize,
1983 				subprogramEntry,
1984 				cfaCfaRule->Expression().block,
1985 				cfaCfaRule->Expression().size,
1986 				inputInterface, location, 0, 0, false,
1987 				frameAddress);
1988 			if (error != B_OK)
1989 				return error;
1990 			break;
1991 		}
1992 		case CFA_CFA_RULE_UNDEFINED:
1993 		default:
1994 			return B_BAD_VALUE;
1995 	}
1996 
1997 	TRACE_CFI("  frame address: %#" B_PRIx64 "\n", frameAddress);
1998 
1999 	// apply the register rules
2000 	for (uint32 i = 0; i < registerCount; i++) {
2001 		TRACE_CFI("  reg %" B_PRIu32 "\n", i);
2002 
2003 		uint32 valueType = outputInterface->RegisterValueType(i);
2004 		if (valueType == 0)
2005 			continue;
2006 
2007 		CfaRule* rule = context.RegisterRule(i);
2008 		if (rule == NULL)
2009 			continue;
2010 
2011 		// apply the rule
2012 		switch (rule->Type()) {
2013 			case CFA_RULE_SAME_VALUE:
2014 			{
2015 				TRACE_CFI("  -> CFA_RULE_SAME_VALUE\n");
2016 
2017 				BVariant value;
2018 				if (inputInterface->GetRegisterValue(i, value))
2019 					outputInterface->SetRegisterValue(i, value);
2020 				break;
2021 			}
2022 			case CFA_RULE_LOCATION_OFFSET:
2023 			{
2024 				TRACE_CFI("  -> CFA_RULE_LOCATION_OFFSET: %"
2025 					B_PRId64 "\n", rule->Offset());
2026 
2027 				BVariant value;
2028 				if (inputInterface->ReadValueFromMemory(
2029 						frameAddress + rule->Offset(), valueType,
2030 						value)) {
2031 					outputInterface->SetRegisterValue(i, value);
2032 				}
2033 				break;
2034 			}
2035 			case CFA_RULE_VALUE_OFFSET:
2036 				TRACE_CFI("  -> CFA_RULE_VALUE_OFFSET\n");
2037 
2038 				outputInterface->SetRegisterValue(i,
2039 					frameAddress + rule->Offset());
2040 				break;
2041 			case CFA_RULE_REGISTER:
2042 			{
2043 				TRACE_CFI("  -> CFA_RULE_REGISTER\n");
2044 
2045 				BVariant value;
2046 				if (inputInterface->GetRegisterValue(
2047 						rule->Register(), value)) {
2048 					outputInterface->SetRegisterValue(i, value);
2049 				}
2050 				break;
2051 			}
2052 			case CFA_RULE_LOCATION_EXPRESSION:
2053 			{
2054 				TRACE_CFI("  -> CFA_RULE_LOCATION_EXPRESSION\n");
2055 
2056 				target_addr_t address;
2057 				error = EvaluateExpression(unit, addressSize,
2058 					subprogramEntry,
2059 					rule->Expression().block,
2060 					rule->Expression().size,
2061 					inputInterface, location, frameAddress,
2062 					frameAddress, true, address);
2063 				BVariant value;
2064 				if (error == B_OK
2065 					&& inputInterface->ReadValueFromMemory(address,
2066 						valueType, value)) {
2067 					outputInterface->SetRegisterValue(i, value);
2068 				}
2069 				break;
2070 			}
2071 			case CFA_RULE_VALUE_EXPRESSION:
2072 			{
2073 				TRACE_CFI("  -> CFA_RULE_VALUE_EXPRESSION\n");
2074 
2075 				target_addr_t value;
2076 				error = EvaluateExpression(unit, addressSize,
2077 					subprogramEntry,
2078 					rule->Expression().block,
2079 					rule->Expression().size,
2080 					inputInterface, location, frameAddress,
2081 					frameAddress, true, value);
2082 				if (error == B_OK)
2083 					outputInterface->SetRegisterValue(i, value);
2084 				break;
2085 			}
2086 			case CFA_RULE_UNDEFINED:
2087 				TRACE_CFI("  -> CFA_RULE_UNDEFINED\n");
2088 			default:
2089 				break;
2090 		}
2091 	}
2092 
2093 	_framePointer = frameAddress;
2094 
2095 	return B_OK;
2096 }
2097 
2098 
2099 status_t
2100 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection,
2101 	bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize,
2102 	CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation,
2103 	DataReader& dataReader, off_t& _cieRemaining)
2104 {
2105 	if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size())
2106 		return B_BAD_DATA;
2107 
2108 	dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset,
2109 		debugFrameSection->Size() - cieOffset, unit != NULL
2110 			? unit->AddressSize() : addressSize);
2111 
2112 	// length
2113 	bool dwarf64;
2114 	uint64 length = dataReader.ReadInitialLength(dwarf64);
2115 	if (length > (uint64)dataReader.BytesRemaining())
2116 		return B_BAD_DATA;
2117 
2118 	off_t lengthOffset = dataReader.Offset();
2119 
2120 	// CIE ID/CIE pointer
2121 	uint64 cieID = dwarf64
2122 		? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2123 	if (usingEHFrameSection) {
2124 		if (cieID != 0)
2125 			return B_BAD_DATA;
2126 	} else {
2127 		if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
2128 			return B_BAD_DATA;
2129 	}
2130 
2131 	uint8 version = dataReader.Read<uint8>(0);
2132 	if (version != 1) {
2133 		TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", "
2134 			"version: %u -- unsupported\n",	length, (uint64)cieOffset, version);
2135 		return B_UNSUPPORTED;
2136 	}
2137 
2138 	// read the augmentation string
2139 	cieAugmentation.Init(dataReader);
2140 
2141 	// in the cause of augmentation string "eh",
2142 	// the exception table pointer is located immediately before the
2143 	// code/data alignment values. We have no use for it so simply skip.
2144 	if (strcmp(cieAugmentation.String(), "eh") == 0)
2145 		dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32));
2146 
2147 	context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0));
2148 	context.SetDataAlignment(dataReader.ReadSignedLEB128(0));
2149 	context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0));
2150 
2151 	TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: "
2152 		"%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %"
2153 		B_PRId32 ", return address reg: %" B_PRIu32 "\n", length,
2154 		(uint64)cieOffset, version, cieAugmentation.String(),
2155 		context.CodeAlignment(), context.DataAlignment(),
2156 		context.ReturnAddressRegister());
2157 
2158 	status_t error = cieAugmentation.Read(dataReader);
2159 	if (error != B_OK) {
2160 		TRACE_CFI("  cie: length: %" B_PRIu64 ", version: %u, augmentation: "
2161 			"\"%s\" -- unsupported\n", length, version,
2162 			cieAugmentation.String());
2163 		return error;
2164 	}
2165 
2166 	if (dataReader.HasOverflow())
2167 		return B_BAD_DATA;
2168 
2169 	_cieRemaining = length -(dataReader.Offset() - lengthOffset);
2170 	if (_cieRemaining < 0)
2171 		return B_BAD_DATA;
2172 
2173 	return B_OK;
2174 }
2175 
2176 
2177 status_t
2178 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit,
2179 	CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation)
2180 {
2181 	while (dataReader.BytesRemaining() > 0) {
2182 		TRACE_CFI("    [%2" B_PRId64 "]", dataReader.BytesRemaining());
2183 
2184 		uint8 opcode = dataReader.Read<uint8>(0);
2185 		if ((opcode >> 6) != 0) {
2186 			uint32 operand = opcode & 0x3f;
2187 
2188 			switch (opcode >> 6) {
2189 				case DW_CFA_advance_loc:
2190 				{
2191 					TRACE_CFI("    DW_CFA_advance_loc: %#" B_PRIx32 "\n",
2192 						operand);
2193 
2194 					target_addr_t location = context.Location()
2195 						+ operand * context.CodeAlignment();
2196 					if (location > context.TargetLocation())
2197 						return B_OK;
2198 					context.SetLocation(location);
2199 					break;
2200 				}
2201 				case DW_CFA_offset:
2202 				{
2203 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2204 					TRACE_CFI("    DW_CFA_offset: reg: %" B_PRIu32 ", offset: "
2205 						"%" B_PRIu64 "\n", operand, offset);
2206 
2207 					if (CfaRule* rule = context.RegisterRule(operand)) {
2208 						rule->SetToLocationOffset(
2209 							offset * context.DataAlignment());
2210 					}
2211 					break;
2212 				}
2213 				case DW_CFA_restore:
2214 				{
2215 					TRACE_CFI("    DW_CFA_restore: %#" B_PRIx32 "\n", operand);
2216 
2217 					context.RestoreRegisterRule(operand);
2218 					break;
2219 				}
2220 			}
2221 		} else {
2222 			switch (opcode) {
2223 				case DW_CFA_nop:
2224 				{
2225 					TRACE_CFI("    DW_CFA_nop\n");
2226 					break;
2227 				}
2228 				case DW_CFA_set_loc:
2229 				{
2230 					target_addr_t location = augmentation.ReadEncodedAddress(
2231 							dataReader, fElfFile, fDebugFrameSection);
2232 
2233 					TRACE_CFI("    DW_CFA_set_loc: %#" B_PRIx64 "\n", location);
2234 
2235 					if (location < context.Location())
2236 						return B_BAD_VALUE;
2237 					if (location > context.TargetLocation())
2238 						return B_OK;
2239 					context.SetLocation(location);
2240 					break;
2241 				}
2242 				case DW_CFA_advance_loc1:
2243 				{
2244 					uint32 delta = dataReader.Read<uint8>(0);
2245 
2246 					TRACE_CFI("    DW_CFA_advance_loc1: %#" B_PRIx32 "\n",
2247 						delta);
2248 
2249 					target_addr_t location = context.Location()
2250 						+ delta * context.CodeAlignment();
2251 					if (location > context.TargetLocation())
2252 						return B_OK;
2253 					context.SetLocation(location);
2254 					break;
2255 				}
2256 				case DW_CFA_advance_loc2:
2257 				{
2258 					uint32 delta = dataReader.Read<uint16>(0);
2259 
2260 					TRACE_CFI("    DW_CFA_advance_loc2: %#" B_PRIx32 "\n",
2261 						delta);
2262 
2263 					target_addr_t location = context.Location()
2264 						+ delta * context.CodeAlignment();
2265 					if (location > context.TargetLocation())
2266 						return B_OK;
2267 					context.SetLocation(location);
2268 					break;
2269 				}
2270 				case DW_CFA_advance_loc4:
2271 				{
2272 					uint32 delta = dataReader.Read<uint32>(0);
2273 
2274 					TRACE_CFI("    DW_CFA_advance_loc4: %#" B_PRIx32 "\n",
2275 						delta);
2276 
2277 					target_addr_t location = context.Location()
2278 						+ delta * context.CodeAlignment();
2279 					if (location > context.TargetLocation())
2280 						return B_OK;
2281 					context.SetLocation(location);
2282 					break;
2283 				}
2284 				case DW_CFA_offset_extended:
2285 				{
2286 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2287 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2288 
2289 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2290 						"offset: %" B_PRIu64 "\n", reg, offset);
2291 
2292 					if (CfaRule* rule = context.RegisterRule(reg)) {
2293 						rule->SetToLocationOffset(
2294 							offset * context.DataAlignment());
2295 					}
2296 					break;
2297 				}
2298 				case DW_CFA_restore_extended:
2299 				{
2300 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2301 
2302 					TRACE_CFI("    DW_CFA_restore_extended: %#" B_PRIx32 "\n",
2303 						reg);
2304 
2305 					context.RestoreRegisterRule(reg);
2306 					break;
2307 				}
2308 				case DW_CFA_undefined:
2309 				{
2310 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2311 
2312 					TRACE_CFI("    DW_CFA_undefined: %" B_PRIu32 "\n", reg);
2313 
2314 					if (CfaRule* rule = context.RegisterRule(reg))
2315 						rule->SetToUndefined();
2316 					break;
2317 				}
2318 				case DW_CFA_same_value:
2319 				{
2320 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2321 
2322 					TRACE_CFI("    DW_CFA_same_value: %" B_PRIu32 "\n", reg);
2323 
2324 					if (CfaRule* rule = context.RegisterRule(reg))
2325 						rule->SetToSameValue();
2326 					break;
2327 				}
2328 				case DW_CFA_register:
2329 				{
2330 					uint32 reg1 = dataReader.ReadUnsignedLEB128(0);
2331 					uint32 reg2 = dataReader.ReadUnsignedLEB128(0);
2332 
2333 					TRACE_CFI("    DW_CFA_register: reg1: %" B_PRIu32 ", reg2: "
2334 						"%" B_PRIu32 "\n", reg1, reg2);
2335 
2336 					if (CfaRule* rule = context.RegisterRule(reg1))
2337 						rule->SetToValueOffset(reg2);
2338 					break;
2339 				}
2340 				case DW_CFA_remember_state:
2341 				{
2342 					TRACE_CFI("    DW_CFA_remember_state\n");
2343 
2344 					status_t error = context.PushRuleSet();
2345 					if (error != B_OK)
2346 						return error;
2347 					break;
2348 				}
2349 				case DW_CFA_restore_state:
2350 				{
2351 					TRACE_CFI("    DW_CFA_restore_state\n");
2352 
2353 					status_t error = context.PopRuleSet();
2354 					if (error != B_OK)
2355 						return error;
2356 					break;
2357 				}
2358 				case DW_CFA_def_cfa:
2359 				{
2360 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2361 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2362 
2363 					TRACE_CFI("    DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: "
2364 						"%" B_PRIu64 "\n", reg, offset);
2365 
2366 					context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset);
2367 					break;
2368 				}
2369 				case DW_CFA_def_cfa_register:
2370 				{
2371 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2372 
2373 					TRACE_CFI("    DW_CFA_def_cfa_register: %" B_PRIu32 "\n",
2374 						reg);
2375 
2376 					if (context.GetCfaCfaRule()->Type()
2377 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2378 						return B_BAD_DATA;
2379 					}
2380 					context.GetCfaCfaRule()->SetRegister(reg);
2381 					break;
2382 				}
2383 				case DW_CFA_def_cfa_offset:
2384 				{
2385 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2386 
2387 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRIu64 "\n",
2388 						offset);
2389 
2390 					if (context.GetCfaCfaRule()->Type()
2391 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2392 						return B_BAD_DATA;
2393 					}
2394 					context.GetCfaCfaRule()->SetOffset(offset);
2395 					break;
2396 				}
2397 				case DW_CFA_def_cfa_expression:
2398 				{
2399 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2400 					uint8* block = (uint8*)dataReader.Data();
2401 					dataReader.Skip(blockLength);
2402 
2403 					TRACE_CFI("    DW_CFA_def_cfa_expression: %p, %" B_PRIu64
2404 						"\n", block, blockLength);
2405 
2406 					context.GetCfaCfaRule()->SetToExpression(block,
2407 						blockLength);
2408 					break;
2409 				}
2410 				case DW_CFA_expression:
2411 				{
2412 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2413 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2414 					uint8* block = (uint8*)dataReader.Data();
2415 					dataReader.Skip(blockLength);
2416 
2417 					TRACE_CFI("    DW_CFA_expression: reg: %" B_PRIu32 ", "
2418 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2419 
2420 					if (CfaRule* rule = context.RegisterRule(reg))
2421 						rule->SetToLocationExpression(block, blockLength);
2422 					break;
2423 				}
2424 				case DW_CFA_offset_extended_sf:
2425 				{
2426 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2427 					int64 offset = dataReader.ReadSignedLEB128(0);
2428 
2429 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2430 						"offset: %" B_PRId64 "\n", reg, offset);
2431 
2432 					if (CfaRule* rule = context.RegisterRule(reg)) {
2433 						rule->SetToLocationOffset(
2434 							offset * (int32)context.DataAlignment());
2435 					}
2436 					break;
2437 				}
2438 				case DW_CFA_def_cfa_sf:
2439 				{
2440 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2441 					int64 offset = dataReader.ReadSignedLEB128(0);
2442 
2443 					TRACE_CFI("    DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", "
2444 						"offset: %" B_PRId64 "\n", reg, offset);
2445 
2446 					context.GetCfaCfaRule()->SetToRegisterOffset(reg,
2447 						offset * (int32)context.DataAlignment());
2448 					break;
2449 				}
2450 				case DW_CFA_def_cfa_offset_sf:
2451 				{
2452 					int64 offset = dataReader.ReadSignedLEB128(0);
2453 
2454 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRId64 "\n",
2455 						offset);
2456 
2457 					if (context.GetCfaCfaRule()->Type()
2458 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2459 						return B_BAD_DATA;
2460 					}
2461 					context.GetCfaCfaRule()->SetOffset(
2462 						offset * (int32)context.DataAlignment());
2463 					break;
2464 				}
2465 				case DW_CFA_val_offset:
2466 				{
2467 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2468 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2469 
2470 					TRACE_CFI("    DW_CFA_val_offset: reg: %" B_PRIu32 ", "
2471 						"offset: %" B_PRIu64 "\n", reg, offset);
2472 
2473 					if (CfaRule* rule = context.RegisterRule(reg)) {
2474 						rule->SetToValueOffset(
2475 							offset * context.DataAlignment());
2476 					}
2477 					break;
2478 				}
2479 				case DW_CFA_val_offset_sf:
2480 				{
2481 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2482 					int64 offset = dataReader.ReadSignedLEB128(0);
2483 
2484 					TRACE_CFI("    DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", "
2485 						"offset: %" B_PRId64 "\n", reg, offset);
2486 
2487 					if (CfaRule* rule = context.RegisterRule(reg)) {
2488 						rule->SetToValueOffset(
2489 							offset * (int32)context.DataAlignment());
2490 					}
2491 					break;
2492 				}
2493 				case DW_CFA_val_expression:
2494 				{
2495 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2496 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2497 					uint8* block = (uint8*)dataReader.Data();
2498 					dataReader.Skip(blockLength);
2499 
2500 					TRACE_CFI("    DW_CFA_val_expression: reg: %" B_PRIu32 ", "
2501 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2502 
2503 					if (CfaRule* rule = context.RegisterRule(reg))
2504 						rule->SetToValueExpression(block, blockLength);
2505 					break;
2506 				}
2507 
2508 				// extensions
2509 				case DW_CFA_MIPS_advance_loc8:
2510 				{
2511 					uint64 delta = dataReader.Read<uint64>(0);
2512 
2513 					TRACE_CFI("    DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n",
2514 						delta);
2515 
2516 					target_addr_t location = context.Location()
2517 						+ delta * context.CodeAlignment();
2518 					if (location > context.TargetLocation())
2519 						return B_OK;
2520 					context.SetLocation(location);
2521 					break;
2522 				}
2523 				case DW_CFA_GNU_window_save:
2524 				{
2525 					// SPARC specific, no args
2526 					TRACE_CFI("    DW_CFA_GNU_window_save\n");
2527 
2528 					// TODO: Implement once we have SPARC support!
2529 					break;
2530 				}
2531 				case DW_CFA_GNU_args_size:
2532 				{
2533 					// Updates the total size of arguments on the stack.
2534 					TRACE_CFI_ONLY(uint64 size =)
2535 						dataReader.ReadUnsignedLEB128(0);
2536 
2537 					TRACE_CFI("    DW_CFA_GNU_args_size: %" B_PRIu64 "\n",
2538 						size);
2539 // TODO: Implement!
2540 					break;
2541 				}
2542 				case DW_CFA_GNU_negative_offset_extended:
2543 				{
2544 					// obsolete
2545 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2546 					int64 offset = dataReader.ReadSignedLEB128(0);
2547 
2548 					TRACE_CFI("    DW_CFA_GNU_negative_offset_extended: "
2549 						"reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg,
2550 						offset);
2551 
2552 					if (CfaRule* rule = context.RegisterRule(reg)) {
2553 						rule->SetToLocationOffset(
2554 							offset * (int32)context.DataAlignment());
2555 					}
2556 					break;
2557 				}
2558 
2559 				default:
2560 					TRACE_CFI("    unknown opcode %u!\n", opcode);
2561 					return B_BAD_DATA;
2562 			}
2563 		}
2564 	}
2565 
2566 	return B_OK;
2567 }
2568 
2569 
2570 status_t
2571 DwarfFile::_ParsePublicTypesInfo()
2572 {
2573 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n");
2574 	if (fDebugPublicTypesSection == NULL) {
2575 		TRACE_PUBTYPES("  -> no public types section\n");
2576 		return B_ENTRY_NOT_FOUND;
2577 	}
2578 
2579 	DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(),
2580 		fDebugPublicTypesSection->Size(), 4);
2581 		// address size doesn't matter at this point
2582 
2583 	while (dataReader.BytesRemaining() > 0) {
2584 		bool dwarf64;
2585 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
2586 
2587 		off_t unitLengthOffset = dataReader.Offset();
2588 			// the unitLength starts here
2589 
2590 		if (dataReader.HasOverflow())
2591 			return B_BAD_DATA;
2592 
2593 		if (unitLengthOffset + unitLength
2594 				> (uint64)fDebugPublicTypesSection->Size()) {
2595 			WARNING("Invalid public types set unit length.\n");
2596 			break;
2597 		}
2598 
2599 		DataReader unitDataReader(dataReader.Data(), unitLength, 4);
2600 			// address size doesn't matter
2601 		_ParsePublicTypesInfo(unitDataReader, dwarf64);
2602 
2603 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
2604 	}
2605 
2606 	return B_OK;
2607 }
2608 
2609 
2610 status_t
2611 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64)
2612 {
2613 	int version = dataReader.Read<uint16>(0);
2614 	if (version != 2) {
2615 		TRACE_PUBTYPES("  pubtypes version %d unsupported\n", version);
2616 		return B_UNSUPPORTED;
2617 	}
2618 
2619 	TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64
2620 		? dataReader.Read<uint64>(0)
2621 		: (uint64)dataReader.Read<uint32>(0);
2622 	TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64
2623 		? dataReader.Read<uint64>(0)
2624 		: (uint64)dataReader.Read<uint32>(0);
2625 
2626 	if (dataReader.HasOverflow())
2627 		return B_BAD_DATA;
2628 
2629 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
2630 		"info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset,
2631 		debugInfoSize);
2632 
2633 	while (dataReader.BytesRemaining() > 0) {
2634 		off_t entryOffset = dwarf64
2635 			? dataReader.Read<uint64>(0)
2636 			: (uint64)dataReader.Read<uint32>(0);
2637 		if (entryOffset == 0)
2638 			return B_OK;
2639 
2640 		TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString();
2641 
2642 		TRACE_PUBTYPES("  \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset);
2643 	}
2644 
2645 	return B_OK;
2646 }
2647 
2648 
2649 status_t
2650 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
2651 {
2652 	// check, whether we've already loaded it
2653 	for (AbbreviationTableList::Iterator it
2654 				= fAbbreviationTables.GetIterator();
2655 			AbbreviationTable* table = it.Next();) {
2656 		if (offset == table->Offset()) {
2657 			_table = table;
2658 			return B_OK;
2659 		}
2660 	}
2661 
2662 	// create a new table
2663 	AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset);
2664 	if (table == NULL)
2665 		return B_NO_MEMORY;
2666 
2667 	status_t error = table->Init(fDebugAbbrevSection->Data(),
2668 		fDebugAbbrevSection->Size());
2669 	if (error != B_OK) {
2670 		delete table;
2671 		return error;
2672 	}
2673 
2674 	fAbbreviationTables.Add(table);
2675 	_table = table;
2676 	return B_OK;
2677 }
2678 
2679 
2680 DebugInfoEntry*
2681 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
2682 	uint8 refType) const
2683 {
2684 	switch (refType) {
2685 		case dwarf_reference_type_local:
2686 			return unit->EntryForOffset(offset);
2687 			break;
2688 		case dwarf_reference_type_global:
2689 		{
2690 			CompilationUnit* unit = _GetContainingCompilationUnit(offset);
2691 			if (unit == NULL)
2692 				break;
2693 
2694 			offset -= unit->HeaderOffset();
2695 			DebugInfoEntry* entry = unit->EntryForOffset(offset);
2696 			if (entry != NULL)
2697 				return entry;
2698 			break;
2699 		}
2700 		case dwarf_reference_type_signature:
2701 		{
2702 			TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset);
2703 			TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
2704 			if (entry != NULL && entry->unit != NULL)
2705 				return entry->unit->TypeEntry();
2706 			break;
2707 		}
2708 	}
2709 
2710 	return NULL;
2711 }
2712 
2713 
2714 status_t
2715 DwarfFile::_GetLocationExpression(CompilationUnit* unit,
2716 	const LocationDescription* location, target_addr_t instructionPointer,
2717 	const void*& _expression, off_t& _length) const
2718 {
2719 	if (!location->IsValid())
2720 		return B_BAD_VALUE;
2721 
2722 	if (location->IsExpression()) {
2723 		_expression = location->expression.data;
2724 		_length = location->expression.length;
2725 		return B_OK;
2726 	}
2727 
2728 	if (location->IsLocationList() && instructionPointer != 0) {
2729 		return _FindLocationExpression(unit, location->listOffset,
2730 			instructionPointer, _expression, _length);
2731 	}
2732 
2733 	return B_BAD_VALUE;
2734 }
2735 
2736 
2737 status_t
2738 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset,
2739 	target_addr_t address, const void*& _expression, off_t& _length) const
2740 {
2741 	if (unit == NULL)
2742 		return B_BAD_VALUE;
2743 
2744 	if (fDebugLocationSection == NULL)
2745 		return B_ENTRY_NOT_FOUND;
2746 
2747 	if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size())
2748 		return B_BAD_DATA;
2749 
2750 	target_addr_t baseAddress = unit->AddressRangeBase();
2751 	target_addr_t maxAddress = unit->MaxAddress();
2752 
2753 	DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset,
2754 		fDebugLocationSection->Size() - offset, unit->AddressSize());
2755 	while (true) {
2756 		target_addr_t start = dataReader.ReadAddress(0);
2757 		target_addr_t end = dataReader.ReadAddress(0);
2758 		if (dataReader.HasOverflow())
2759 			return B_BAD_DATA;
2760 
2761 		if (start == 0 && end == 0)
2762 			return B_ENTRY_NOT_FOUND;
2763 
2764 		if (start == maxAddress) {
2765 			baseAddress = end;
2766 			continue;
2767 		}
2768 
2769 		uint16 expressionLength = dataReader.Read<uint16>(0);
2770 		const void* expression = dataReader.Data();
2771 		if (!dataReader.Skip(expressionLength))
2772 			return B_BAD_DATA;
2773 
2774 		if (start == end)
2775 			continue;
2776 
2777 		start += baseAddress;
2778 		end += baseAddress;
2779 
2780 		if (address >= start && address < end) {
2781 			_expression = expression;
2782 			_length = expressionLength;
2783 			return B_OK;
2784 		}
2785 	}
2786 }
2787 
2788 
2789 status_t
2790 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName,
2791 	const char* locatedFilePath)
2792 {
2793 	ElfFile* debugInfoFile = fElfFile;
2794 	ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink");
2795 	if (debugLinkSection != NULL) {
2796 		AutoSectionPutter putter(fElfFile, debugLinkSection);
2797 
2798 		// the file specifies a debug link, look at its target instead
2799 		// for debug information.
2800 		// Format: null-terminated filename, as many 0 padding bytes as
2801 		// needed to reach the next 32-bit address boundary, followed
2802 		// by a 32-bit CRC
2803 
2804 		BString debugPath;
2805 		if (locatedFilePath)
2806 			debugPath = locatedFilePath;
2807 		else {
2808 			status_t result = _GetDebugInfoPath(
2809 				(const char*)debugLinkSection->Data(),
2810 				_requiredExternalFileName);
2811 			if (result != B_OK)
2812 				return result;
2813 			debugPath = _requiredExternalFileName;
2814 		}
2815 
2816 		if (fAlternateName != NULL)
2817 			free(fAlternateName);
2818 
2819 		fAlternateName = strdup(debugPath.String());
2820 
2821 		if (fAlternateName == NULL)
2822 			return B_NO_MEMORY;
2823 
2824 /*
2825 		// TODO: validate CRC
2826 		int32 debugCRC = *(int32*)((char*)debugLinkSection->Data()
2827 			+ debugLinkSection->Size() - sizeof(int32));
2828 */
2829 		if (fAlternateElfFile == NULL) {
2830 			fAlternateElfFile = new(std::nothrow) ElfFile;
2831 			if (fAlternateElfFile == NULL)
2832 				return B_NO_MEMORY;
2833 		}
2834 
2835 		status_t result = fAlternateElfFile->Init(fAlternateName);
2836 		if (result != B_OK)
2837 			return result;
2838 
2839 		debugInfoFile = fAlternateElfFile;
2840 	}
2841 
2842 	// get the interesting sections
2843 	fDebugInfoSection = debugInfoFile->GetSection(".debug_info");
2844 	fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev");
2845 	if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
2846 		WARNING("DwarfManager::File::Load(\"%s\"): no "
2847 			".debug_info or .debug_abbrev.\n", fName);
2848 
2849 		// if we at least have an EH frame, use that for stack unwinding
2850 		// if nothing else.
2851 		fEHFrameSection = fElfFile->GetSection(".eh_frame");
2852 		if (fEHFrameSection == NULL)
2853 			return B_ERROR;
2854 	}
2855 
2856 	return B_OK;
2857 }
2858 
2859 
2860 status_t
2861 DwarfFile::_GetDebugInfoPath(const char* debugFileName,
2862 	BString& _infoPath) const
2863 {
2864 	// first, see if we have a relative match to our local directory
2865 	BPath basePath;
2866 	status_t result = basePath.SetTo(fName);
2867 	if (result != B_OK)
2868 		return result;
2869 	basePath.GetParent(&basePath);
2870 	if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(),
2871 			"add-ons") == 0) {
2872 		_infoPath.SetToFormat("%s/../debug/%s", basePath.Path(),
2873 			debugFileName);
2874 	} else
2875 		_infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName);
2876 
2877 	BEntry entry(_infoPath.String());
2878 	result = entry.InitCheck();
2879 	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
2880 		return result;
2881 	if (entry.Exists())
2882 		return B_OK;
2883 
2884 	// If the above search failed, check if our image is located in any
2885 	// of the system installation paths, and attempt to locate the debug info
2886 	// file in the corresponding well-known location
2887 	BString pathSuffix;
2888 	pathSuffix.SetToFormat("debug/%s", debugFileName);
2889 
2890 	BPathFinder finder(fName);
2891 	result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY,
2892 		pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath);
2893 	if (result == B_OK) {
2894 		_infoPath = basePath.Path();
2895 		return B_OK;
2896 	} else {
2897 		// if we failed to find a match, then it's up to the user to
2898 		// locate it. As such, return the external info file name
2899 		// for user interface purposes.
2900 		_infoPath.SetTo(debugFileName);
2901 	}
2902 
2903 	return B_ENTRY_NOT_FOUND;
2904 }
2905 
2906 
2907 TypeUnitTableEntry*
2908 DwarfFile::_GetTypeUnit(uint64 signature) const
2909 {
2910 	return fTypeUnits.Lookup(signature);
2911 }
2912 
2913 
2914 CompilationUnit*
2915 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
2916 {
2917 	if (fCompilationUnits.IsEmpty())
2918 		return NULL;
2919 
2920 	// binary search
2921 	int lower = 0;
2922 	int upper = fCompilationUnits.CountItems() - 1;
2923 	while (lower < upper) {
2924 		int mid = (lower + upper + 1) / 2;
2925 		if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr)
2926 			upper = mid - 1;
2927 		else
2928 			lower = mid;
2929 	}
2930 
2931 	CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
2932 	return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
2933 }
2934 
2935 
2936 DwarfFile::FDELookupInfo*
2937 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
2938 {
2939 	FDELookupInfo* info = NULL;
2940 	if (fDebugFrameSection != NULL) {
2941 		info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
2942 		if (info != NULL)
2943 			return info;
2944 	}
2945 
2946 	return _GetContainingFDEInfo(offset, fEHFrameInfos);
2947 }
2948 
2949 
2950 DwarfFile::FDELookupInfo*
2951 DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
2952 	const FDEInfoList& infoList) const
2953 {
2954 	// binary search
2955 	int lower = 0;
2956 	int upper = infoList.CountItems() - 1;
2957 	if (upper < 0)
2958 		return NULL;
2959 
2960 	while (lower < upper) {
2961 		int mid = (lower + upper + 1) / 2;
2962 		if (offset < infoList.ItemAt(mid)->start)
2963 			upper = mid - 1;
2964 		else
2965 			lower = mid;
2966 	}
2967 
2968 	FDELookupInfo* info = infoList.ItemAt(lower);
2969 	return info->ContainsAddress(offset) ? info : NULL;
2970 }
2971