xref: /haiku/src/kits/debugger/dwarf/DwarfFile.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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 		// CIE ID/CIE pointer
1160 		uint64 cieID = dwarf64
1161 			? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1162 
1163 		// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
1164 		if (ehFrame
1165 			? cieID == 0
1166 			: (dwarf64
1167 				? cieID == 0xffffffffffffffffULL
1168 				: cieID == 0xffffffff)) {
1169 			// this is a CIE -- skip it
1170 		} else {
1171 			// this is a FDE
1172 			uint64 initialLocationOffset = dataReader.Offset();
1173 			// In .eh_frame the CIE offset is a relative back offset.
1174 			if (ehFrame) {
1175 				if (cieID > (uint64)lengthOffset) {
1176 					TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
1177 						"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
1178 					break;
1179 				}
1180 				// convert to a section relative offset
1181 				cieID = lengthOffset - cieID;
1182 			}
1183 
1184 
1185 			CfaContext context;
1186 			CIEAugmentation cieAugmentation;
1187 			// when using .eh_frame format, we need to parse the CIE's
1188 			// augmentation up front in order to know how the FDE's addresses
1189 			//  will be represented
1190 			DataReader cieReader;
1191 			off_t cieRemaining;
1192 			status_t error = _ParseCIEHeader(section, ehFrame, NULL,
1193 				addressSize, context, cieID, cieAugmentation, cieReader,
1194 				cieRemaining);
1195 			if (error != B_OK)
1196 				return error;
1197 			if (cieReader.HasOverflow())
1198 				return B_BAD_DATA;
1199 			if (cieRemaining < 0)
1200 				return B_BAD_DATA;
1201 
1202 			target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
1203 				dataReader, fElfFile, section);
1204 			target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
1205 				dataReader, fElfFile, section, true);
1206 
1207 			if (dataReader.HasOverflow())
1208 				return B_BAD_DATA;
1209 
1210 			if ((cieAugmentation.FDEAddressType()
1211 					& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
1212 				initialLocation += initialLocationOffset;
1213 			}
1214 
1215 			// for unknown reasons, the debug frame sections generated by gcc
1216 			// sometimes contain duplicates at different offsets within the
1217 			// section. In such a case, simply skip the duplicates.
1218 			FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
1219 				infos);
1220 			if (temp == NULL) {
1221 				FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
1222 					initialLocation, initialLocation + addressRange - 1,
1223 					entryOffset, cieID, ehFrame);
1224 				if (info == NULL)
1225 					return B_NO_MEMORY;
1226 
1227 				ObjectDeleter<FDELookupInfo> infoDeleter(info);
1228 				if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
1229 					return B_NO_MEMORY;
1230 
1231 				infoDeleter.Detach();
1232 			}
1233 		}
1234 
1235 		dataReader.SeekAbsolute(lengthOffset + length);
1236 	}
1237 
1238 	return B_OK;
1239 }
1240 
1241 
1242 status_t
1243 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
1244 {
1245 	AbbreviationTable* abbreviationTable;
1246 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1247 		abbreviationTable);
1248 	if (error != B_OK)
1249 		return error;
1250 
1251 	unit->SetAbbreviationTable(abbreviationTable);
1252 
1253 	DataReader dataReader(
1254 		(const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(),
1255 		unit->ContentSize(), unit->AddressSize());
1256 
1257 	DebugInfoEntry* entry;
1258 	bool endOfEntryList;
1259 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1260 		endOfEntryList);
1261 	if (error != B_OK)
1262 		return error;
1263 
1264 	DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry);
1265 	if (unitEntry == NULL) {
1266 		WARNING("No compilation unit entry in .debug_info section.\n");
1267 		return B_BAD_DATA;
1268 	}
1269 
1270 	unit->SetUnitEntry(unitEntry);
1271 
1272 	TRACE_DIE_ONLY(
1273 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1274 			dataReader.BytesRemaining());
1275 		if (dataReader.HasData()) {
1276 			TRACE_DIE("  ");
1277 			while (dataReader.HasData())
1278 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1279 			TRACE_DIE("\n");
1280 		}
1281 	)
1282 	return B_OK;
1283 }
1284 
1285 
1286 status_t
1287 DwarfFile::_ParseTypeUnit(TypeUnit* unit)
1288 {
1289 	AbbreviationTable* abbreviationTable;
1290 	status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1291 		abbreviationTable);
1292 	if (error != B_OK)
1293 		return error;
1294 
1295 	unit->SetAbbreviationTable(abbreviationTable);
1296 
1297 	DataReader dataReader(
1298 		(const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
1299 		unit->ContentSize(), unit->AddressSize());
1300 
1301 	DebugInfoEntry* entry;
1302 	bool endOfEntryList;
1303 	error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1304 		endOfEntryList);
1305 	if (error != B_OK)
1306 		return error;
1307 
1308 	DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
1309 	if (unitEntry == NULL) {
1310 		WARNING("No type unit entry in .debug_types section.\n");
1311 		return B_BAD_DATA;
1312 	}
1313 
1314 	unit->SetUnitEntry(unitEntry);
1315 	DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset());
1316 	if (typeEntry == NULL) {
1317 		WARNING("No type found for type unit %p at specified offset %"
1318 			B_PRId64 ".\n", unit, unit->TypeOffset());
1319 		return B_BAD_DATA;
1320 	}
1321 	unit->SetTypeEntry(typeEntry);
1322 
1323 	TRACE_DIE_ONLY(
1324 		TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1325 			dataReader.BytesRemaining());
1326 		if (dataReader.HasData()) {
1327 			TRACE_DIE("  ");
1328 			while (dataReader.HasData())
1329 				TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1330 			TRACE_DIE("\n");
1331 		}
1332 	)
1333 	return B_OK;
1334 }
1335 
1336 
1337 status_t
1338 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
1339 	BaseUnit* unit, AbbreviationTable* abbreviationTable,
1340 	DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
1341 {
1342 	off_t entryOffset = dataReader.Offset()
1343 		+ unit->RelativeContentOffset();
1344 
1345 	uint32 code = dataReader.ReadUnsignedLEB128(0);
1346 	if (code == 0) {
1347 		if (dataReader.HasOverflow()) {
1348 			WARNING("Unexpected end of .debug_info section.\n");
1349 			return B_BAD_DATA;
1350 		}
1351 		_entry = NULL;
1352 		_endOfEntryList = true;
1353 		return B_OK;
1354 	}
1355 
1356 	// get the corresponding abbreviation entry
1357 	AbbreviationEntry abbreviationEntry;
1358 	if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
1359 		WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
1360 		return B_BAD_DATA;
1361 	}
1362 
1363 	DebugInfoEntry* entry;
1364 	status_t error = fDebugInfoFactory.CreateDebugInfoEntry(
1365 		abbreviationEntry.Tag(), entry);
1366 	if (error != B_OK) {
1367 		WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %"
1368 			B_PRIu32 "\n", abbreviationEntry.Tag(), code);
1369 		return error;
1370 	}
1371 
1372 	ObjectDeleter<DebugInfoEntry> entryDeleter(entry);
1373 
1374 	TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%"
1375 		B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset,
1376 		abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
1377 		abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
1378 
1379 	error = unit->AddDebugInfoEntry(entry, entryOffset);
1380 
1381 	if (error != B_OK)
1382 		return error;
1383 
1384 	// parse the attributes (supply NULL entry to avoid adding them yet)
1385 	error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
1386 	if (error != B_OK)
1387 		return error;
1388 
1389 	// parse children, if the entry has any
1390 	if (abbreviationEntry.HasChildren()) {
1391 		while (true) {
1392 			DebugInfoEntry* childEntry;
1393 			bool endOfEntryList;
1394 			status_t error = _ParseDebugInfoEntry(dataReader,
1395 				unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
1396 			if (error != B_OK)
1397 				return error;
1398 
1399 			// add the child to our entry
1400 			if (childEntry != NULL) {
1401 				if (entry != NULL) {
1402 					error = entry->AddChild(childEntry);
1403 					if (error == B_OK) {
1404 						childEntry->SetParent(entry);
1405 					} else if (error == ENTRY_NOT_HANDLED) {
1406 						error = B_OK;
1407 						TRACE_DIE("%*s  -> child unhandled\n", level * 2, "");
1408 					}
1409 
1410 					if (error != B_OK) {
1411 						delete childEntry;
1412 						return error;
1413 					}
1414 				} else
1415 					delete childEntry;
1416 			}
1417 
1418 			if (endOfEntryList)
1419 				break;
1420 		}
1421 	}
1422 
1423 	entryDeleter.Detach();
1424 	_entry = entry;
1425 	_endOfEntryList = false;
1426 	return B_OK;
1427 }
1428 
1429 
1430 status_t
1431 DwarfFile::_FinishUnit(BaseUnit* unit)
1432 {
1433 	CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
1434 	bool isTypeUnit = compilationUnit == NULL;
1435 	TRACE_DIE("\nfinishing %s unit %p\n",
1436 		isTypeUnit ? "type" : "compilation", unit);
1437 
1438 
1439 	AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
1440 
1441 	ElfSection* section = isTypeUnit
1442 			? fDebugTypesSection : fDebugInfoSection;
1443 	DataReader dataReader(
1444 		(const uint8*)section->Data() + unit->HeaderOffset(),
1445 		unit->TotalSize(), unit->AddressSize());
1446 
1447 	DebugInfoEntryInitInfo entryInitInfo;
1448 
1449 	int entryCount = unit->CountEntries();
1450 	for (int i = 0; i < entryCount; i++) {
1451 		// get the entry
1452 		DebugInfoEntry* entry;
1453 		off_t offset;
1454 		unit->GetEntryAt(i, entry, offset);
1455 
1456 		TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset);
1457 
1458 		// seek the reader to the entry
1459 		dataReader.SeekAbsolute(offset);
1460 
1461 		// read the entry code
1462 		uint32 code = dataReader.ReadUnsignedLEB128(0);
1463 
1464 		// get the respective abbreviation entry
1465 		AbbreviationEntry abbreviationEntry;
1466 		abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry);
1467 
1468 		// initialization before setting the attributes
1469 		status_t error = entry->InitAfterHierarchy(entryInitInfo);
1470 		if (error != B_OK) {
1471 			WARNING("Init after hierarchy failed!\n");
1472 			return error;
1473 		}
1474 
1475 		// parse the attributes -- this time pass the entry, so that the
1476 		// attribute get set on it
1477 		error = _ParseEntryAttributes(dataReader, unit, entry,
1478 			abbreviationEntry);
1479 		if (error != B_OK)
1480 			return error;
1481 
1482 		// initialization after setting the attributes
1483 		error = entry->InitAfterAttributes(entryInitInfo);
1484 		if (error != B_OK) {
1485 			WARNING("Init after attributes failed!\n");
1486 			return error;
1487 		}
1488 	}
1489 
1490 	// set the compilation unit's source language
1491 	unit->SetSourceLanguage(entryInitInfo.languageInfo);
1492 
1493 	if (isTypeUnit)
1494 		return B_OK;
1495 
1496 	// resolve the compilation unit's address range list
1497 	if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
1498 			compilationUnit->UnitEntry()->AddressRangesOffset())) {
1499 		compilationUnit->SetAddressRanges(ranges);
1500 		ranges->ReleaseReference();
1501 	}
1502 
1503 	// add compilation dir to directory list
1504 	const char* compilationDir = compilationUnit->UnitEntry()
1505 		->CompilationDir();
1506 	if (!compilationUnit->AddDirectory(compilationDir != NULL
1507 				? compilationDir : ".")) {
1508 		return B_NO_MEMORY;
1509 	}
1510 
1511 	// parse line info header
1512 	if (fDebugLineSection != NULL)
1513 		_ParseLineInfo(compilationUnit);
1514 
1515 	return B_OK;
1516 }
1517 
1518 
1519 status_t
1520 DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
1521 	BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
1522 {
1523 	uint32 attributeName;
1524 	uint32 attributeForm;
1525 	while (abbreviationEntry.GetNextAttribute(attributeName,
1526 			attributeForm)) {
1527 		// resolve attribute form indirection
1528 		if (attributeForm == DW_FORM_indirect)
1529 			attributeForm = dataReader.ReadUnsignedLEB128(0);
1530 
1531 		// prepare an AttributeValue
1532 		AttributeValue attributeValue;
1533 		attributeValue.attributeForm = attributeForm;
1534 		bool isSigned = false;
1535 
1536 		// Read the attribute value according to the attribute's form. For
1537 		// the forms that don't map to a single attribute class only or
1538 		// those that need additional processing, we read a temporary value
1539 		// first.
1540 		uint64 value = 0;
1541 		off_t blockLength = 0;
1542 		off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
1543 		uint8 refType = dwarf_reference_type_local;
1544 
1545 		switch (attributeForm) {
1546 			case DW_FORM_addr:
1547 				value = dataReader.ReadAddress(0);
1548 				break;
1549 			case DW_FORM_block2:
1550 				blockLength = dataReader.Read<uint16>(0);
1551 				break;
1552 			case DW_FORM_block4:
1553 				blockLength = dataReader.Read<uint32>(0);
1554 				break;
1555 			case DW_FORM_data2:
1556 				value = dataReader.Read<uint16>(0);
1557 				break;
1558 			case DW_FORM_data4:
1559 				value = dataReader.Read<uint32>(0);
1560 				break;
1561 			case DW_FORM_data8:
1562 				value = dataReader.Read<uint64>(0);
1563 				break;
1564 			case DW_FORM_string:
1565 				attributeValue.SetToString(dataReader.ReadString());
1566 				break;
1567 			case DW_FORM_block:
1568 			case DW_FORM_exprloc:
1569 				blockLength = dataReader.ReadUnsignedLEB128(0);
1570 				break;
1571 			case DW_FORM_block1:
1572 				blockLength = dataReader.Read<uint8>(0);
1573 				break;
1574 			case DW_FORM_data1:
1575 				value = dataReader.Read<uint8>(0);
1576 				break;
1577 			case DW_FORM_flag:
1578 				attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0);
1579 				break;
1580 			case DW_FORM_sdata:
1581 				value = dataReader.ReadSignedLEB128(0);
1582 				isSigned = true;
1583 				break;
1584 			case DW_FORM_strp:
1585 			{
1586 				if (fDebugStringSection != NULL) {
1587 					uint64 offset = unit->IsDwarf64()
1588 						? dataReader.Read<uint64>(0)
1589 						: dataReader.Read<uint32>(0);
1590 					if (offset >= fDebugStringSection->Size()) {
1591 						WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1592 							offset);
1593 						return B_BAD_DATA;
1594 					}
1595 					attributeValue.SetToString(
1596 						(const char*)fDebugStringSection->Data() + offset);
1597 				} else {
1598 					WARNING("Invalid DW_FORM_strp: no string section!\n");
1599 					return B_BAD_DATA;
1600 				}
1601 				break;
1602 			}
1603 			case DW_FORM_udata:
1604 				value = dataReader.ReadUnsignedLEB128(0);
1605 				break;
1606 			case DW_FORM_ref_addr:
1607 				value = unit->IsDwarf64()
1608 					? dataReader.Read<uint64>(0)
1609 					: (uint64)dataReader.Read<uint32>(0);
1610 				refType = dwarf_reference_type_global;
1611 				break;
1612 			case DW_FORM_ref1:
1613 				value = dataReader.Read<uint8>(0);
1614 				break;
1615 			case DW_FORM_ref2:
1616 				value = dataReader.Read<uint16>(0);
1617 				break;
1618 			case DW_FORM_ref4:
1619 				value = dataReader.Read<uint32>(0);
1620 				break;
1621 			case DW_FORM_ref8:
1622 				value = dataReader.Read<uint64>(0);
1623 				break;
1624 			case DW_FORM_ref_udata:
1625 				value = dataReader.ReadUnsignedLEB128(0);
1626 				break;
1627 			case DW_FORM_flag_present:
1628 				attributeValue.SetToFlag(true);
1629 				break;
1630 			case DW_FORM_ref_sig8:
1631 				fTypesSectionRequired = true;
1632 				value = dataReader.Read<uint64>(0);
1633 				refType = dwarf_reference_type_signature;
1634 				break;
1635 			case DW_FORM_sec_offset:
1636 				value = unit->IsDwarf64()
1637 					? dataReader.Read<uint64>(0)
1638 					: (uint64)dataReader.Read<uint32>(0);
1639 				break;
1640 			case DW_FORM_indirect:
1641 			default:
1642 				WARNING("Unsupported attribute form: %" B_PRIu32 "\n",
1643 					attributeForm);
1644 				return B_BAD_DATA;
1645 		}
1646 
1647 		// get the attribute class -- skip the attribute, if we can't handle
1648 		// it
1649 		uint8 attributeClass = get_attribute_class(attributeName,
1650 			attributeForm);
1651 
1652 		if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
1653 			TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
1654 				B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
1655 				get_attribute_name_name(attributeName), attributeName,
1656 				get_attribute_form_name(attributeForm), attributeForm);
1657 			continue;
1658 		}
1659 
1660 		// set the attribute value according to the attribute's class
1661 		switch (attributeClass) {
1662 			case ATTRIBUTE_CLASS_ADDRESS:
1663 				attributeValue.SetToAddress(value);
1664 				break;
1665 			case ATTRIBUTE_CLASS_BLOCK:
1666 				attributeValue.SetToBlock(dataReader.Data(), blockLength);
1667 				dataReader.Skip(blockLength);
1668 				break;
1669 			case ATTRIBUTE_CLASS_CONSTANT:
1670 				attributeValue.SetToConstant(value, isSigned);
1671 				break;
1672 			case ATTRIBUTE_CLASS_LINEPTR:
1673 				attributeValue.SetToLinePointer(value);
1674 				break;
1675 			case ATTRIBUTE_CLASS_LOCLISTPTR:
1676 				attributeValue.SetToLocationListPointer(value);
1677 				break;
1678 			case ATTRIBUTE_CLASS_MACPTR:
1679 				attributeValue.SetToMacroPointer(value);
1680 				break;
1681 			case ATTRIBUTE_CLASS_RANGELISTPTR:
1682 				attributeValue.SetToRangeListPointer(value);
1683 				break;
1684 			case ATTRIBUTE_CLASS_REFERENCE:
1685 				if (entry != NULL) {
1686 					attributeValue.SetToReference(_ResolveReference(
1687 						unit, value, refType));
1688 					if (attributeValue.reference == NULL) {
1689 						// gcc 2 apparently somtimes produces DW_AT_sibling
1690 						// attributes pointing to the end of the sibling list.
1691 						// Just ignore those.
1692 						if (attributeName == DW_AT_sibling)
1693 							continue;
1694 
1695 						WARNING("Failed to resolve reference on entry %p: "
1696 							"(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
1697 							"(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
1698 							entry,
1699 							valueOffset,
1700 							get_attribute_name_name(attributeName),
1701 							attributeName,
1702 							get_attribute_form_name(attributeForm),
1703 							attributeForm, value);
1704 						return B_ENTRY_NOT_FOUND;
1705 					}
1706 				}
1707 				break;
1708 			case ATTRIBUTE_CLASS_FLAG:
1709 			case ATTRIBUTE_CLASS_STRING:
1710 				// already set
1711 				break;
1712 		}
1713 
1714 		if (dataReader.HasOverflow()) {
1715 			WARNING("Unexpected end of .debug_info section.\n");
1716 			return B_BAD_DATA;
1717 		}
1718 
1719 		TRACE_DIE_ONLY(
1720 			char buffer[1024];
1721 			TRACE_DIE("  attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
1722 				valueOffset,
1723 				get_attribute_name_name(attributeName),
1724 				get_attribute_form_name(attributeForm), attributeClass,
1725 				attributeValue.ToString(buffer, sizeof(buffer)));
1726 		)
1727 
1728 		// add the attribute
1729 		if (entry != NULL) {
1730 			DebugInfoEntrySetter attributeSetter
1731 				= get_attribute_name_setter(attributeName);
1732 			if (attributeSetter != 0) {
1733 				status_t error = (entry->*attributeSetter)(attributeName,
1734 					attributeValue);
1735 
1736 				if (error == ATTRIBUTE_NOT_HANDLED) {
1737 					error = B_OK;
1738 					TRACE_DIE("    -> unhandled\n");
1739 				}
1740 
1741 				if (error != B_OK) {
1742 					WARNING("Failed to set attribute: name: %s, form: %s: %s\n",
1743 						get_attribute_name_name(attributeName),
1744 						get_attribute_form_name(attributeForm),
1745 						strerror(error));
1746 				}
1747 			} else
1748 				TRACE_DIE("    -> no attribute setter!\n");
1749 		}
1750 	}
1751 
1752 	return B_OK;
1753 }
1754 
1755 
1756 status_t
1757 DwarfFile::_ParseLineInfo(CompilationUnit* unit)
1758 {
1759 	off_t offset = unit->UnitEntry()->StatementListOffset();
1760 
1761 	TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit,
1762 		offset);
1763 
1764 	DataReader dataReader((uint8*)fDebugLineSection->Data() + offset,
1765 		fDebugLineSection->Size() - offset, unit->AddressSize());
1766 
1767 	// unit length
1768 	bool dwarf64;
1769 	uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1770 	if (unitLength > (uint64)dataReader.BytesRemaining())
1771 		return B_BAD_DATA;
1772 	off_t unitOffset = dataReader.Offset();
1773 
1774 	// version (uhalf)
1775 	uint16 version = dataReader.Read<uint16>(0);
1776 
1777 	// header_length (4/8)
1778 	uint64 headerLength = dwarf64
1779 		? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
1780 	off_t headerOffset = dataReader.Offset();
1781 
1782 	if ((uint64)dataReader.BytesRemaining() < headerLength)
1783 		return B_BAD_DATA;
1784 
1785 	// minimum instruction length
1786 	uint8 minInstructionLength = dataReader.Read<uint8>(0);
1787 
1788 	// default is statement
1789 	bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
1790 
1791 	// line_base (sbyte)
1792 	int8 lineBase = (int8)dataReader.Read<uint8>(0);
1793 
1794 	// line_range (ubyte)
1795 	uint8 lineRange = dataReader.Read<uint8>(0);
1796 
1797 	// opcode_base (ubyte)
1798 	uint8 opcodeBase = dataReader.Read<uint8>(0);
1799 
1800 	// standard_opcode_lengths (ubyte[])
1801 	const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
1802 	dataReader.Skip(opcodeBase - 1);
1803 
1804 	if (dataReader.HasOverflow())
1805 		return B_BAD_DATA;
1806 
1807 	if (version != 2 && version != 3)
1808 		return B_UNSUPPORTED;
1809 
1810 	TRACE_LINES("  unitLength:           %" B_PRIu64 "\n", unitLength);
1811 	TRACE_LINES("  version:              %u\n", version);
1812 	TRACE_LINES("  headerLength:         %" B_PRIu64 "\n", headerLength);
1813 	TRACE_LINES("  minInstructionLength: %u\n", minInstructionLength);
1814 	TRACE_LINES("  defaultIsStatement:   %d\n", defaultIsStatement);
1815 	TRACE_LINES("  lineBase:             %d\n", lineBase);
1816 	TRACE_LINES("  lineRange:            %u\n", lineRange);
1817 	TRACE_LINES("  opcodeBase:           %u\n", opcodeBase);
1818 
1819 	// include directories
1820 	TRACE_LINES("  include directories:\n");
1821 	while (const char* directory = dataReader.ReadString()) {
1822 		if (*directory == '\0')
1823 			break;
1824 		TRACE_LINES("    \"%s\"\n", directory);
1825 
1826 		if (!unit->AddDirectory(directory))
1827 			return B_NO_MEMORY;
1828 	}
1829 
1830 	// file names
1831 	TRACE_LINES("  files:\n");
1832 	while (const char* file = dataReader.ReadString()) {
1833 		if (*file == '\0')
1834 			break;
1835 		uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
1836 		TRACE_LINES_ONLY(uint64 modificationTime =)
1837 			dataReader.ReadUnsignedLEB128(0);
1838 		TRACE_LINES_ONLY(uint64 fileLength =)
1839 			dataReader.ReadUnsignedLEB128(0);
1840 
1841 		if (dataReader.HasOverflow())
1842 			return B_BAD_DATA;
1843 
1844 		TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
1845 			", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
1846 			fileLength);
1847 
1848 		if (!unit->AddFile(file, dirIndex))
1849 			return B_NO_MEMORY;
1850 	}
1851 
1852 	off_t readerOffset = dataReader.Offset();
1853 	if ((uint64)readerOffset > readerOffset + headerLength)
1854 		return B_BAD_DATA;
1855 	off_t offsetToProgram = headerOffset + headerLength - readerOffset;
1856 
1857 	const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
1858 	size_t programSize = unitLength - (readerOffset - unitOffset);
1859 
1860 	return unit->GetLineNumberProgram().Init(program, programSize,
1861 		minInstructionLength, defaultIsStatement, lineBase, lineRange,
1862 			opcodeBase, standardOpcodeLengths);
1863 }
1864 
1865 
1866 status_t
1867 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
1868 	DIESubprogram* subprogramEntry, target_addr_t location,
1869 	const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
1870 	DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
1871 {
1872 	ElfSection* currentFrameSection = (info->ehFrame)
1873 		? fEHFrameSection : fDebugFrameSection;
1874 
1875 	TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
1876 
1877 	DataReader dataReader((uint8*)currentFrameSection->Data(),
1878 		currentFrameSection->Size(), unit != NULL
1879 			? unit->AddressSize() : addressSize);
1880 	dataReader.SeekAbsolute(info->fdeOffset);
1881 
1882 	bool dwarf64;
1883 	uint64 length = dataReader.ReadInitialLength(dwarf64);
1884 	uint64 lengthOffset = dataReader.Offset();
1885 
1886 	CfaContext context;
1887 	CIEAugmentation cieAugmentation;
1888 	// when using .eh_frame format, we need to parse the CIE's
1889 	// augmentation up front in order to know how the FDE's addresses
1890 	//  will be represented
1891 	DataReader cieReader;
1892 	off_t cieRemaining;
1893 	status_t error = _ParseCIEHeader(currentFrameSection,
1894 		info->ehFrame, unit, addressSize, context, info->cieOffset,
1895 		cieAugmentation, cieReader, cieRemaining);
1896 	if (error != B_OK)
1897 		return error;
1898 	if (cieReader.HasOverflow())
1899 		return B_BAD_DATA;
1900 	if (cieRemaining < 0)
1901 		return B_BAD_DATA;
1902 
1903 	// skip CIE ID, initial offset and range, since we already know those
1904 	// from FDELookupInfo.
1905 	dwarf64	? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1906 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1907 		currentFrameSection);
1908 	cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1909 		currentFrameSection, true);
1910 
1911 	TRACE_CFI("  found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
1912 		"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
1913 		"range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
1914 		info->cieOffset, info->start, info->end - info->start);
1915 
1916 	context.SetLocation(location, info->start);
1917 	uint32 registerCount = outputInterface->CountRegisters();
1918 	error = context.Init(registerCount);
1919 	if (error != B_OK)
1920 		return error;
1921 
1922 	error = outputInterface->InitRegisterRules(context);
1923 	if (error != B_OK)
1924 		return error;
1925 
1926 	// process the CIE's frame info instructions
1927 	cieReader = cieReader.RestrictedReader(cieRemaining);
1928 	error = _ParseFrameInfoInstructions(unit, context,
1929 		cieReader, cieAugmentation);
1930 	if (error != B_OK)
1931 		return error;
1932 
1933 	// read the FDE augmentation data (if any)
1934 	FDEAugmentation fdeAugmentation;
1935 	error = cieAugmentation.ReadFDEData(dataReader,
1936 		fdeAugmentation);
1937 	if (error != B_OK) {
1938 		TRACE_CFI("  failed to read FDE augmentation data!\n");
1939 		return error;
1940 	}
1941 
1942 	error = context.SaveInitialRuleSet();
1943 	if (error != B_OK)
1944 		return error;
1945 
1946 	uint64 remaining = lengthOffset + length - dataReader.Offset();
1947 	if (remaining < 0)
1948 		return B_BAD_DATA;
1949 
1950 	DataReader restrictedReader =
1951 		dataReader.RestrictedReader(remaining);
1952 	error = _ParseFrameInfoInstructions(unit, context,
1953 		restrictedReader, cieAugmentation);
1954 	if (error != B_OK)
1955 		return error;
1956 
1957 	TRACE_CFI("  found row!\n");
1958 
1959 	// apply the rules of the final row
1960 	// get the frameAddress first
1961 	target_addr_t frameAddress;
1962 	CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
1963 	switch (cfaCfaRule->Type()) {
1964 		case CFA_CFA_RULE_REGISTER_OFFSET:
1965 		{
1966 			BVariant value;
1967 			if (!inputInterface->GetRegisterValue(
1968 					cfaCfaRule->Register(), value)
1969 				|| !value.IsNumber()) {
1970 				return B_UNSUPPORTED;
1971 			}
1972 			frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
1973 			break;
1974 		}
1975 		case CFA_CFA_RULE_EXPRESSION:
1976 		{
1977 			error = EvaluateExpression(unit, addressSize,
1978 				subprogramEntry,
1979 				cfaCfaRule->Expression().block,
1980 				cfaCfaRule->Expression().size,
1981 				inputInterface, location, 0, 0, false,
1982 				frameAddress);
1983 			if (error != B_OK)
1984 				return error;
1985 			break;
1986 		}
1987 		case CFA_CFA_RULE_UNDEFINED:
1988 		default:
1989 			return B_BAD_VALUE;
1990 	}
1991 
1992 	TRACE_CFI("  frame address: %#" B_PRIx64 "\n", frameAddress);
1993 
1994 	// apply the register rules
1995 	for (uint32 i = 0; i < registerCount; i++) {
1996 		TRACE_CFI("  reg %" B_PRIu32 "\n", i);
1997 
1998 		uint32 valueType = outputInterface->RegisterValueType(i);
1999 		if (valueType == 0)
2000 			continue;
2001 
2002 		CfaRule* rule = context.RegisterRule(i);
2003 		if (rule == NULL)
2004 			continue;
2005 
2006 		// apply the rule
2007 		switch (rule->Type()) {
2008 			case CFA_RULE_SAME_VALUE:
2009 			{
2010 				TRACE_CFI("  -> CFA_RULE_SAME_VALUE\n");
2011 
2012 				BVariant value;
2013 				if (inputInterface->GetRegisterValue(i, value))
2014 					outputInterface->SetRegisterValue(i, value);
2015 				break;
2016 			}
2017 			case CFA_RULE_LOCATION_OFFSET:
2018 			{
2019 				TRACE_CFI("  -> CFA_RULE_LOCATION_OFFSET: %"
2020 					B_PRId64 "\n", rule->Offset());
2021 
2022 				BVariant value;
2023 				if (inputInterface->ReadValueFromMemory(
2024 						frameAddress + rule->Offset(), valueType,
2025 						value)) {
2026 					outputInterface->SetRegisterValue(i, value);
2027 				}
2028 				break;
2029 			}
2030 			case CFA_RULE_VALUE_OFFSET:
2031 				TRACE_CFI("  -> CFA_RULE_VALUE_OFFSET\n");
2032 
2033 				outputInterface->SetRegisterValue(i,
2034 					frameAddress + rule->Offset());
2035 				break;
2036 			case CFA_RULE_REGISTER:
2037 			{
2038 				TRACE_CFI("  -> CFA_RULE_REGISTER\n");
2039 
2040 				BVariant value;
2041 				if (inputInterface->GetRegisterValue(
2042 						rule->Register(), value)) {
2043 					outputInterface->SetRegisterValue(i, value);
2044 				}
2045 				break;
2046 			}
2047 			case CFA_RULE_LOCATION_EXPRESSION:
2048 			{
2049 				TRACE_CFI("  -> CFA_RULE_LOCATION_EXPRESSION\n");
2050 
2051 				target_addr_t address;
2052 				error = EvaluateExpression(unit, addressSize,
2053 					subprogramEntry,
2054 					rule->Expression().block,
2055 					rule->Expression().size,
2056 					inputInterface, location, frameAddress,
2057 					frameAddress, true, address);
2058 				BVariant value;
2059 				if (error == B_OK
2060 					&& inputInterface->ReadValueFromMemory(address,
2061 						valueType, value)) {
2062 					outputInterface->SetRegisterValue(i, value);
2063 				}
2064 				break;
2065 			}
2066 			case CFA_RULE_VALUE_EXPRESSION:
2067 			{
2068 				TRACE_CFI("  -> CFA_RULE_VALUE_EXPRESSION\n");
2069 
2070 				target_addr_t value;
2071 				error = EvaluateExpression(unit, addressSize,
2072 					subprogramEntry,
2073 					rule->Expression().block,
2074 					rule->Expression().size,
2075 					inputInterface, location, frameAddress,
2076 					frameAddress, true, value);
2077 				if (error == B_OK)
2078 					outputInterface->SetRegisterValue(i, value);
2079 				break;
2080 			}
2081 			case CFA_RULE_UNDEFINED:
2082 				TRACE_CFI("  -> CFA_RULE_UNDEFINED\n");
2083 			default:
2084 				break;
2085 		}
2086 	}
2087 
2088 	_framePointer = frameAddress;
2089 
2090 	return B_OK;
2091 }
2092 
2093 
2094 status_t
2095 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection,
2096 	bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize,
2097 	CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation,
2098 	DataReader& dataReader, off_t& _cieRemaining)
2099 {
2100 	if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size())
2101 		return B_BAD_DATA;
2102 
2103 	dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset,
2104 		debugFrameSection->Size() - cieOffset, unit != NULL
2105 			? unit->AddressSize() : addressSize);
2106 
2107 	// length
2108 	bool dwarf64;
2109 	uint64 length = dataReader.ReadInitialLength(dwarf64);
2110 	if (length > (uint64)dataReader.BytesRemaining())
2111 		return B_BAD_DATA;
2112 
2113 	off_t lengthOffset = dataReader.Offset();
2114 
2115 	// CIE ID/CIE pointer
2116 	uint64 cieID = dwarf64
2117 		? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2118 	if (usingEHFrameSection) {
2119 		if (cieID != 0)
2120 			return B_BAD_DATA;
2121 	} else {
2122 		if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
2123 			return B_BAD_DATA;
2124 	}
2125 
2126 	uint8 version = dataReader.Read<uint8>(0);
2127 	if (version != 1) {
2128 		TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", "
2129 			"version: %u -- unsupported\n",	length, (uint64)cieOffset, version);
2130 		return B_UNSUPPORTED;
2131 	}
2132 
2133 	// read the augmentation string
2134 	cieAugmentation.Init(dataReader);
2135 
2136 	// in the cause of augmentation string "eh",
2137 	// the exception table pointer is located immediately before the
2138 	// code/data alignment values. We have no use for it so simply skip.
2139 	if (strcmp(cieAugmentation.String(), "eh") == 0)
2140 		dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32));
2141 
2142 	context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0));
2143 	context.SetDataAlignment(dataReader.ReadSignedLEB128(0));
2144 	context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0));
2145 
2146 	TRACE_CFI("  cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: "
2147 		"%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %"
2148 		B_PRId32 ", return address reg: %" B_PRIu32 "\n", length,
2149 		(uint64)cieOffset, version, cieAugmentation.String(),
2150 		context.CodeAlignment(), context.DataAlignment(),
2151 		context.ReturnAddressRegister());
2152 
2153 	status_t error = cieAugmentation.Read(dataReader);
2154 	if (error != B_OK) {
2155 		TRACE_CFI("  cie: length: %" B_PRIu64 ", version: %u, augmentation: "
2156 			"\"%s\" -- unsupported\n", length, version,
2157 			cieAugmentation.String());
2158 		return error;
2159 	}
2160 
2161 	if (dataReader.HasOverflow())
2162 		return B_BAD_DATA;
2163 
2164 	_cieRemaining = length -(dataReader.Offset() - lengthOffset);
2165 	if (_cieRemaining < 0)
2166 		return B_BAD_DATA;
2167 
2168 	return B_OK;
2169 }
2170 
2171 
2172 status_t
2173 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit,
2174 	CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation)
2175 {
2176 	while (dataReader.BytesRemaining() > 0) {
2177 		TRACE_CFI("    [%2" B_PRId64 "]", dataReader.BytesRemaining());
2178 
2179 		uint8 opcode = dataReader.Read<uint8>(0);
2180 		if ((opcode >> 6) != 0) {
2181 			uint32 operand = opcode & 0x3f;
2182 
2183 			switch (opcode >> 6) {
2184 				case DW_CFA_advance_loc:
2185 				{
2186 					TRACE_CFI("    DW_CFA_advance_loc: %#" B_PRIx32 "\n",
2187 						operand);
2188 
2189 					target_addr_t location = context.Location()
2190 						+ operand * context.CodeAlignment();
2191 					if (location > context.TargetLocation())
2192 						return B_OK;
2193 					context.SetLocation(location);
2194 					break;
2195 				}
2196 				case DW_CFA_offset:
2197 				{
2198 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2199 					TRACE_CFI("    DW_CFA_offset: reg: %" B_PRIu32 ", offset: "
2200 						"%" B_PRIu64 "\n", operand, offset);
2201 
2202 					if (CfaRule* rule = context.RegisterRule(operand)) {
2203 						rule->SetToLocationOffset(
2204 							offset * context.DataAlignment());
2205 					}
2206 					break;
2207 				}
2208 				case DW_CFA_restore:
2209 				{
2210 					TRACE_CFI("    DW_CFA_restore: %#" B_PRIx32 "\n", operand);
2211 
2212 					context.RestoreRegisterRule(operand);
2213 					break;
2214 				}
2215 			}
2216 		} else {
2217 			switch (opcode) {
2218 				case DW_CFA_nop:
2219 				{
2220 					TRACE_CFI("    DW_CFA_nop\n");
2221 					break;
2222 				}
2223 				case DW_CFA_set_loc:
2224 				{
2225 					target_addr_t location = augmentation.ReadEncodedAddress(
2226 							dataReader, fElfFile, fDebugFrameSection);
2227 
2228 					TRACE_CFI("    DW_CFA_set_loc: %#" B_PRIx64 "\n", location);
2229 
2230 					if (location < context.Location())
2231 						return B_BAD_VALUE;
2232 					if (location > context.TargetLocation())
2233 						return B_OK;
2234 					context.SetLocation(location);
2235 					break;
2236 				}
2237 				case DW_CFA_advance_loc1:
2238 				{
2239 					uint32 delta = dataReader.Read<uint8>(0);
2240 
2241 					TRACE_CFI("    DW_CFA_advance_loc1: %#" B_PRIx32 "\n",
2242 						delta);
2243 
2244 					target_addr_t location = context.Location()
2245 						+ delta * context.CodeAlignment();
2246 					if (location > context.TargetLocation())
2247 						return B_OK;
2248 					context.SetLocation(location);
2249 					break;
2250 				}
2251 				case DW_CFA_advance_loc2:
2252 				{
2253 					uint32 delta = dataReader.Read<uint16>(0);
2254 
2255 					TRACE_CFI("    DW_CFA_advance_loc2: %#" B_PRIx32 "\n",
2256 						delta);
2257 
2258 					target_addr_t location = context.Location()
2259 						+ delta * context.CodeAlignment();
2260 					if (location > context.TargetLocation())
2261 						return B_OK;
2262 					context.SetLocation(location);
2263 					break;
2264 				}
2265 				case DW_CFA_advance_loc4:
2266 				{
2267 					uint32 delta = dataReader.Read<uint32>(0);
2268 
2269 					TRACE_CFI("    DW_CFA_advance_loc4: %#" B_PRIx32 "\n",
2270 						delta);
2271 
2272 					target_addr_t location = context.Location()
2273 						+ delta * context.CodeAlignment();
2274 					if (location > context.TargetLocation())
2275 						return B_OK;
2276 					context.SetLocation(location);
2277 					break;
2278 				}
2279 				case DW_CFA_offset_extended:
2280 				{
2281 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2282 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2283 
2284 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2285 						"offset: %" B_PRIu64 "\n", reg, offset);
2286 
2287 					if (CfaRule* rule = context.RegisterRule(reg)) {
2288 						rule->SetToLocationOffset(
2289 							offset * context.DataAlignment());
2290 					}
2291 					break;
2292 				}
2293 				case DW_CFA_restore_extended:
2294 				{
2295 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2296 
2297 					TRACE_CFI("    DW_CFA_restore_extended: %#" B_PRIx32 "\n",
2298 						reg);
2299 
2300 					context.RestoreRegisterRule(reg);
2301 					break;
2302 				}
2303 				case DW_CFA_undefined:
2304 				{
2305 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2306 
2307 					TRACE_CFI("    DW_CFA_undefined: %" B_PRIu32 "\n", reg);
2308 
2309 					if (CfaRule* rule = context.RegisterRule(reg))
2310 						rule->SetToUndefined();
2311 					break;
2312 				}
2313 				case DW_CFA_same_value:
2314 				{
2315 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2316 
2317 					TRACE_CFI("    DW_CFA_same_value: %" B_PRIu32 "\n", reg);
2318 
2319 					if (CfaRule* rule = context.RegisterRule(reg))
2320 						rule->SetToSameValue();
2321 					break;
2322 				}
2323 				case DW_CFA_register:
2324 				{
2325 					uint32 reg1 = dataReader.ReadUnsignedLEB128(0);
2326 					uint32 reg2 = dataReader.ReadUnsignedLEB128(0);
2327 
2328 					TRACE_CFI("    DW_CFA_register: reg1: %" B_PRIu32 ", reg2: "
2329 						"%" B_PRIu32 "\n", reg1, reg2);
2330 
2331 					if (CfaRule* rule = context.RegisterRule(reg1))
2332 						rule->SetToValueOffset(reg2);
2333 					break;
2334 				}
2335 				case DW_CFA_remember_state:
2336 				{
2337 					TRACE_CFI("    DW_CFA_remember_state\n");
2338 
2339 					status_t error = context.PushRuleSet();
2340 					if (error != B_OK)
2341 						return error;
2342 					break;
2343 				}
2344 				case DW_CFA_restore_state:
2345 				{
2346 					TRACE_CFI("    DW_CFA_restore_state\n");
2347 
2348 					status_t error = context.PopRuleSet();
2349 					if (error != B_OK)
2350 						return error;
2351 					break;
2352 				}
2353 				case DW_CFA_def_cfa:
2354 				{
2355 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2356 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2357 
2358 					TRACE_CFI("    DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: "
2359 						"%" B_PRIu64 "\n", reg, offset);
2360 
2361 					context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset);
2362 					break;
2363 				}
2364 				case DW_CFA_def_cfa_register:
2365 				{
2366 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2367 
2368 					TRACE_CFI("    DW_CFA_def_cfa_register: %" B_PRIu32 "\n",
2369 						reg);
2370 
2371 					if (context.GetCfaCfaRule()->Type()
2372 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2373 						return B_BAD_DATA;
2374 					}
2375 					context.GetCfaCfaRule()->SetRegister(reg);
2376 					break;
2377 				}
2378 				case DW_CFA_def_cfa_offset:
2379 				{
2380 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2381 
2382 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRIu64 "\n",
2383 						offset);
2384 
2385 					if (context.GetCfaCfaRule()->Type()
2386 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2387 						return B_BAD_DATA;
2388 					}
2389 					context.GetCfaCfaRule()->SetOffset(offset);
2390 					break;
2391 				}
2392 				case DW_CFA_def_cfa_expression:
2393 				{
2394 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2395 					uint8* block = (uint8*)dataReader.Data();
2396 					dataReader.Skip(blockLength);
2397 
2398 					TRACE_CFI("    DW_CFA_def_cfa_expression: %p, %" B_PRIu64
2399 						"\n", block, blockLength);
2400 
2401 					context.GetCfaCfaRule()->SetToExpression(block,
2402 						blockLength);
2403 					break;
2404 				}
2405 				case DW_CFA_expression:
2406 				{
2407 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2408 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2409 					uint8* block = (uint8*)dataReader.Data();
2410 					dataReader.Skip(blockLength);
2411 
2412 					TRACE_CFI("    DW_CFA_expression: reg: %" B_PRIu32 ", "
2413 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2414 
2415 					if (CfaRule* rule = context.RegisterRule(reg))
2416 						rule->SetToLocationExpression(block, blockLength);
2417 					break;
2418 				}
2419 				case DW_CFA_offset_extended_sf:
2420 				{
2421 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2422 					int64 offset = dataReader.ReadSignedLEB128(0);
2423 
2424 					TRACE_CFI("    DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2425 						"offset: %" B_PRId64 "\n", reg, offset);
2426 
2427 					if (CfaRule* rule = context.RegisterRule(reg)) {
2428 						rule->SetToLocationOffset(
2429 							offset * (int32)context.DataAlignment());
2430 					}
2431 					break;
2432 				}
2433 				case DW_CFA_def_cfa_sf:
2434 				{
2435 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2436 					int64 offset = dataReader.ReadSignedLEB128(0);
2437 
2438 					TRACE_CFI("    DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", "
2439 						"offset: %" B_PRId64 "\n", reg, offset);
2440 
2441 					context.GetCfaCfaRule()->SetToRegisterOffset(reg,
2442 						offset * (int32)context.DataAlignment());
2443 					break;
2444 				}
2445 				case DW_CFA_def_cfa_offset_sf:
2446 				{
2447 					int64 offset = dataReader.ReadSignedLEB128(0);
2448 
2449 					TRACE_CFI("    DW_CFA_def_cfa_offset: %" B_PRId64 "\n",
2450 						offset);
2451 
2452 					if (context.GetCfaCfaRule()->Type()
2453 							!= CFA_CFA_RULE_REGISTER_OFFSET) {
2454 						return B_BAD_DATA;
2455 					}
2456 					context.GetCfaCfaRule()->SetOffset(
2457 						offset * (int32)context.DataAlignment());
2458 					break;
2459 				}
2460 				case DW_CFA_val_offset:
2461 				{
2462 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2463 					uint64 offset = dataReader.ReadUnsignedLEB128(0);
2464 
2465 					TRACE_CFI("    DW_CFA_val_offset: reg: %" B_PRIu32 ", "
2466 						"offset: %" B_PRIu64 "\n", reg, offset);
2467 
2468 					if (CfaRule* rule = context.RegisterRule(reg)) {
2469 						rule->SetToValueOffset(
2470 							offset * context.DataAlignment());
2471 					}
2472 					break;
2473 				}
2474 				case DW_CFA_val_offset_sf:
2475 				{
2476 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2477 					int64 offset = dataReader.ReadSignedLEB128(0);
2478 
2479 					TRACE_CFI("    DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", "
2480 						"offset: %" B_PRId64 "\n", reg, offset);
2481 
2482 					if (CfaRule* rule = context.RegisterRule(reg)) {
2483 						rule->SetToValueOffset(
2484 							offset * (int32)context.DataAlignment());
2485 					}
2486 					break;
2487 				}
2488 				case DW_CFA_val_expression:
2489 				{
2490 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2491 					uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2492 					uint8* block = (uint8*)dataReader.Data();
2493 					dataReader.Skip(blockLength);
2494 
2495 					TRACE_CFI("    DW_CFA_val_expression: reg: %" B_PRIu32 ", "
2496 						"block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2497 
2498 					if (CfaRule* rule = context.RegisterRule(reg))
2499 						rule->SetToValueExpression(block, blockLength);
2500 					break;
2501 				}
2502 
2503 				// extensions
2504 				case DW_CFA_MIPS_advance_loc8:
2505 				{
2506 					uint64 delta = dataReader.Read<uint64>(0);
2507 
2508 					TRACE_CFI("    DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n",
2509 						delta);
2510 
2511 					target_addr_t location = context.Location()
2512 						+ delta * context.CodeAlignment();
2513 					if (location > context.TargetLocation())
2514 						return B_OK;
2515 					context.SetLocation(location);
2516 					break;
2517 				}
2518 				case DW_CFA_GNU_window_save:
2519 				{
2520 					// SPARC specific, no args
2521 					TRACE_CFI("    DW_CFA_GNU_window_save\n");
2522 
2523 					// TODO: Implement once we have SPARC support!
2524 					break;
2525 				}
2526 				case DW_CFA_GNU_args_size:
2527 				{
2528 					// Updates the total size of arguments on the stack.
2529 					TRACE_CFI_ONLY(uint64 size =)
2530 						dataReader.ReadUnsignedLEB128(0);
2531 
2532 					TRACE_CFI("    DW_CFA_GNU_args_size: %" B_PRIu64 "\n",
2533 						size);
2534 // TODO: Implement!
2535 					break;
2536 				}
2537 				case DW_CFA_GNU_negative_offset_extended:
2538 				{
2539 					// obsolete
2540 					uint32 reg = dataReader.ReadUnsignedLEB128(0);
2541 					int64 offset = dataReader.ReadSignedLEB128(0);
2542 
2543 					TRACE_CFI("    DW_CFA_GNU_negative_offset_extended: "
2544 						"reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg,
2545 						offset);
2546 
2547 					if (CfaRule* rule = context.RegisterRule(reg)) {
2548 						rule->SetToLocationOffset(
2549 							offset * (int32)context.DataAlignment());
2550 					}
2551 					break;
2552 				}
2553 
2554 				default:
2555 					TRACE_CFI("    unknown opcode %u!\n", opcode);
2556 					return B_BAD_DATA;
2557 			}
2558 		}
2559 	}
2560 
2561 	return B_OK;
2562 }
2563 
2564 
2565 status_t
2566 DwarfFile::_ParsePublicTypesInfo()
2567 {
2568 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n");
2569 	if (fDebugPublicTypesSection == NULL) {
2570 		TRACE_PUBTYPES("  -> no public types section\n");
2571 		return B_ENTRY_NOT_FOUND;
2572 	}
2573 
2574 	DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(),
2575 		fDebugPublicTypesSection->Size(), 4);
2576 		// address size doesn't matter at this point
2577 
2578 	while (dataReader.BytesRemaining() > 0) {
2579 		bool dwarf64;
2580 		uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
2581 
2582 		off_t unitLengthOffset = dataReader.Offset();
2583 			// the unitLength starts here
2584 
2585 		if (dataReader.HasOverflow())
2586 			return B_BAD_DATA;
2587 
2588 		if (unitLengthOffset + unitLength
2589 				> (uint64)fDebugPublicTypesSection->Size()) {
2590 			WARNING("Invalid public types set unit length.\n");
2591 			break;
2592 		}
2593 
2594 		DataReader unitDataReader(dataReader.Data(), unitLength, 4);
2595 			// address size doesn't matter
2596 		_ParsePublicTypesInfo(unitDataReader, dwarf64);
2597 
2598 		dataReader.SeekAbsolute(unitLengthOffset + unitLength);
2599 	}
2600 
2601 	return B_OK;
2602 }
2603 
2604 
2605 status_t
2606 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64)
2607 {
2608 	int version = dataReader.Read<uint16>(0);
2609 	if (version != 2) {
2610 		TRACE_PUBTYPES("  pubtypes version %d unsupported\n", version);
2611 		return B_UNSUPPORTED;
2612 	}
2613 
2614 	TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64
2615 		? dataReader.Read<uint64>(0)
2616 		: (uint64)dataReader.Read<uint32>(0);
2617 	TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64
2618 		? dataReader.Read<uint64>(0)
2619 		: (uint64)dataReader.Read<uint32>(0);
2620 
2621 	if (dataReader.HasOverflow())
2622 		return B_BAD_DATA;
2623 
2624 	TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
2625 		"info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset,
2626 		debugInfoSize);
2627 
2628 	while (dataReader.BytesRemaining() > 0) {
2629 		off_t entryOffset = dwarf64
2630 			? dataReader.Read<uint64>(0)
2631 			: (uint64)dataReader.Read<uint32>(0);
2632 		if (entryOffset == 0)
2633 			return B_OK;
2634 
2635 		TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString();
2636 
2637 		TRACE_PUBTYPES("  \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset);
2638 	}
2639 
2640 	return B_OK;
2641 }
2642 
2643 
2644 status_t
2645 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
2646 {
2647 	// check, whether we've already loaded it
2648 	for (AbbreviationTableList::Iterator it
2649 				= fAbbreviationTables.GetIterator();
2650 			AbbreviationTable* table = it.Next();) {
2651 		if (offset == table->Offset()) {
2652 			_table = table;
2653 			return B_OK;
2654 		}
2655 	}
2656 
2657 	// create a new table
2658 	AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset);
2659 	if (table == NULL)
2660 		return B_NO_MEMORY;
2661 
2662 	status_t error = table->Init(fDebugAbbrevSection->Data(),
2663 		fDebugAbbrevSection->Size());
2664 	if (error != B_OK) {
2665 		delete table;
2666 		return error;
2667 	}
2668 
2669 	fAbbreviationTables.Add(table);
2670 	_table = table;
2671 	return B_OK;
2672 }
2673 
2674 
2675 DebugInfoEntry*
2676 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
2677 	uint8 refType) const
2678 {
2679 	switch (refType) {
2680 		case dwarf_reference_type_local:
2681 			return unit->EntryForOffset(offset);
2682 			break;
2683 		case dwarf_reference_type_global:
2684 		{
2685 			CompilationUnit* unit = _GetContainingCompilationUnit(offset);
2686 			if (unit == NULL)
2687 				break;
2688 
2689 			offset -= unit->HeaderOffset();
2690 			DebugInfoEntry* entry = unit->EntryForOffset(offset);
2691 			if (entry != NULL)
2692 				return entry;
2693 			break;
2694 		}
2695 		case dwarf_reference_type_signature:
2696 		{
2697 			TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset);
2698 			TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
2699 			if (entry != NULL && entry->unit != NULL)
2700 				return entry->unit->TypeEntry();
2701 			break;
2702 		}
2703 	}
2704 
2705 	return NULL;
2706 }
2707 
2708 
2709 status_t
2710 DwarfFile::_GetLocationExpression(CompilationUnit* unit,
2711 	const LocationDescription* location, target_addr_t instructionPointer,
2712 	const void*& _expression, off_t& _length) const
2713 {
2714 	if (!location->IsValid())
2715 		return B_BAD_VALUE;
2716 
2717 	if (location->IsExpression()) {
2718 		_expression = location->expression.data;
2719 		_length = location->expression.length;
2720 		return B_OK;
2721 	}
2722 
2723 	if (location->IsLocationList() && instructionPointer != 0) {
2724 		return _FindLocationExpression(unit, location->listOffset,
2725 			instructionPointer, _expression, _length);
2726 	}
2727 
2728 	return B_BAD_VALUE;
2729 }
2730 
2731 
2732 status_t
2733 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset,
2734 	target_addr_t address, const void*& _expression, off_t& _length) const
2735 {
2736 	if (unit == NULL)
2737 		return B_BAD_VALUE;
2738 
2739 	if (fDebugLocationSection == NULL)
2740 		return B_ENTRY_NOT_FOUND;
2741 
2742 	if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size())
2743 		return B_BAD_DATA;
2744 
2745 	target_addr_t baseAddress = unit->AddressRangeBase();
2746 	target_addr_t maxAddress = unit->MaxAddress();
2747 
2748 	DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset,
2749 		fDebugLocationSection->Size() - offset, unit->AddressSize());
2750 	while (true) {
2751 		target_addr_t start = dataReader.ReadAddress(0);
2752 		target_addr_t end = dataReader.ReadAddress(0);
2753 		if (dataReader.HasOverflow())
2754 			return B_BAD_DATA;
2755 
2756 		if (start == 0 && end == 0)
2757 			return B_ENTRY_NOT_FOUND;
2758 
2759 		if (start == maxAddress) {
2760 			baseAddress = end;
2761 			continue;
2762 		}
2763 
2764 		uint16 expressionLength = dataReader.Read<uint16>(0);
2765 		const void* expression = dataReader.Data();
2766 		if (!dataReader.Skip(expressionLength))
2767 			return B_BAD_DATA;
2768 
2769 		if (start == end)
2770 			continue;
2771 
2772 		start += baseAddress;
2773 		end += baseAddress;
2774 
2775 		if (address >= start && address < end) {
2776 			_expression = expression;
2777 			_length = expressionLength;
2778 			return B_OK;
2779 		}
2780 	}
2781 }
2782 
2783 
2784 status_t
2785 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName,
2786 	const char* locatedFilePath)
2787 {
2788 	ElfFile* debugInfoFile = fElfFile;
2789 	ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink");
2790 	if (debugLinkSection != NULL) {
2791 		AutoSectionPutter putter(fElfFile, debugLinkSection);
2792 
2793 		// the file specifies a debug link, look at its target instead
2794 		// for debug information.
2795 		// Format: null-terminated filename, as many 0 padding bytes as
2796 		// needed to reach the next 32-bit address boundary, followed
2797 		// by a 32-bit CRC
2798 
2799 		BString debugPath;
2800 		if (locatedFilePath)
2801 			debugPath = locatedFilePath;
2802 		else {
2803 			status_t result = _GetDebugInfoPath(
2804 				(const char*)debugLinkSection->Data(),
2805 				_requiredExternalFileName);
2806 			if (result != B_OK)
2807 				return result;
2808 			debugPath = _requiredExternalFileName;
2809 		}
2810 
2811 		if (fAlternateName != NULL)
2812 			free(fAlternateName);
2813 
2814 		fAlternateName = strdup(debugPath.String());
2815 
2816 		if (fAlternateName == NULL)
2817 			return B_NO_MEMORY;
2818 
2819 /*
2820 		// TODO: validate CRC
2821 		int32 debugCRC = *(int32*)((char*)debugLinkSection->Data()
2822 			+ debugLinkSection->Size() - sizeof(int32));
2823 */
2824 		if (fAlternateElfFile == NULL) {
2825 			fAlternateElfFile = new(std::nothrow) ElfFile;
2826 			if (fAlternateElfFile == NULL)
2827 				return B_NO_MEMORY;
2828 		}
2829 
2830 		status_t result = fAlternateElfFile->Init(fAlternateName);
2831 		if (result != B_OK)
2832 			return result;
2833 
2834 		debugInfoFile = fAlternateElfFile;
2835 	}
2836 
2837 	// get the interesting sections
2838 	fDebugInfoSection = debugInfoFile->GetSection(".debug_info");
2839 	fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev");
2840 	if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
2841 		WARNING("DwarfManager::File::Load(\"%s\"): no "
2842 			".debug_info or .debug_abbrev.\n", fName);
2843 
2844 		// if we at least have an EH frame, use that for stack unwinding
2845 		// if nothing else.
2846 		fEHFrameSection = fElfFile->GetSection(".eh_frame");
2847 		if (fEHFrameSection == NULL)
2848 			return B_ERROR;
2849 	}
2850 
2851 	return B_OK;
2852 }
2853 
2854 
2855 status_t
2856 DwarfFile::_GetDebugInfoPath(const char* debugFileName,
2857 	BString& _infoPath) const
2858 {
2859 	// first, see if we have a relative match to our local directory
2860 	BPath basePath;
2861 	status_t result = basePath.SetTo(fName);
2862 	if (result != B_OK)
2863 		return result;
2864 	basePath.GetParent(&basePath);
2865 	if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(),
2866 			"add-ons") == 0) {
2867 		_infoPath.SetToFormat("%s/../debug/%s", basePath.Path(),
2868 			debugFileName);
2869 	} else
2870 		_infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName);
2871 
2872 	BEntry entry(_infoPath.String());
2873 	result = entry.InitCheck();
2874 	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
2875 		return result;
2876 	if (entry.Exists())
2877 		return B_OK;
2878 
2879 	// If the above search failed, check if our image is located in any
2880 	// of the system installation paths, and attempt to locate the debug info
2881 	// file in the corresponding well-known location
2882 	BString pathSuffix;
2883 	pathSuffix.SetToFormat("debug/%s", debugFileName);
2884 
2885 	BPathFinder finder(fName);
2886 	result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY,
2887 		pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath);
2888 	if (result == B_OK) {
2889 		_infoPath = basePath.Path();
2890 		return B_OK;
2891 	} else {
2892 		// if we failed to find a match, then it's up to the user to
2893 		// locate it. As such, return the external info file name
2894 		// for user interface purposes.
2895 		_infoPath.SetTo(debugFileName);
2896 	}
2897 
2898 	return B_ENTRY_NOT_FOUND;
2899 }
2900 
2901 
2902 TypeUnitTableEntry*
2903 DwarfFile::_GetTypeUnit(uint64 signature) const
2904 {
2905 	return fTypeUnits.Lookup(signature);
2906 }
2907 
2908 
2909 CompilationUnit*
2910 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
2911 {
2912 	if (fCompilationUnits.IsEmpty())
2913 		return NULL;
2914 
2915 	// binary search
2916 	int lower = 0;
2917 	int upper = fCompilationUnits.CountItems() - 1;
2918 	while (lower < upper) {
2919 		int mid = (lower + upper + 1) / 2;
2920 		if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr)
2921 			upper = mid - 1;
2922 		else
2923 			lower = mid;
2924 	}
2925 
2926 	CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
2927 	return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
2928 }
2929 
2930 
2931 DwarfFile::FDELookupInfo*
2932 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
2933 {
2934 	FDELookupInfo* info = NULL;
2935 	if (fDebugFrameSection != NULL) {
2936 		info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
2937 		if (info != NULL)
2938 			return info;
2939 	}
2940 
2941 	return _GetContainingFDEInfo(offset, fEHFrameInfos);
2942 }
2943 
2944 
2945 DwarfFile::FDELookupInfo*
2946 DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
2947 	const FDEInfoList& infoList) const
2948 {
2949 	// binary search
2950 	int lower = 0;
2951 	int upper = infoList.CountItems() - 1;
2952 	if (upper < 0)
2953 		return NULL;
2954 
2955 	while (lower < upper) {
2956 		int mid = (lower + upper + 1) / 2;
2957 		if (offset < infoList.ItemAt(mid)->start)
2958 			upper = mid - 1;
2959 		else
2960 			lower = mid;
2961 	}
2962 
2963 	FDELookupInfo* info = infoList.ItemAt(lower);
2964 	return info->ContainsAddress(offset) ? info : NULL;
2965 }
2966