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
37class AutoSectionPutter {
38public:
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
52private:
53	ElfFile*			fElfFile;
54	ElfSection*			fElfSection;
55};
56
57
58// #pragma mark - ExpressionEvaluationContext
59
60
61struct DwarfFile::ExpressionEvaluationContext
62	: DwarfExpressionEvaluationContext {
63public:
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
172private:
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
188struct DwarfFile::FDEAugmentation {
189	// Currently we're ignoring all augmentation data.
190};
191
192
193// #pragma mark - CIEAugmentation
194
195
196enum {
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
205enum {
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
223enum {
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
233struct 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
438private:
439	const char*	fString;
440	uint32		fFlags;
441	int8		fAddressEncoding;
442};
443
444
445// #pragma mark - FDELookupInfo
446
447
448struct DwarfFile::FDELookupInfo {
449public:
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
487DwarfFile::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
515DwarfFile::~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
549status_t
550DwarfFile::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
573status_t
574DwarfFile::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
641status_t
642DwarfFile::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
671int32
672DwarfFile::CountCompilationUnits() const
673{
674	return fCompilationUnits.CountItems();
675}
676
677
678CompilationUnit*
679DwarfFile::CompilationUnitAt(int32 index) const
680{
681	return fCompilationUnits.ItemAt(index);
682}
683
684
685CompilationUnit*
686DwarfFile::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
709TargetAddressRangeList*
710DwarfFile::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
755status_t
756DwarfFile::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
770status_t
771DwarfFile::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
789status_t
790DwarfFile::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
815status_t
816DwarfFile::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
851status_t
852DwarfFile::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
966status_t
967DwarfFile::_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
1040status_t
1041DwarfFile::_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
1132status_t
1133DwarfFile::_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
1242status_t
1243DwarfFile::_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
1286status_t
1287DwarfFile::_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
1337status_t
1338DwarfFile::_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
1430status_t
1431DwarfFile::_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
1519status_t
1520DwarfFile::_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
1756status_t
1757DwarfFile::_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
1866status_t
1867DwarfFile::_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
2094status_t
2095DwarfFile::_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
2172status_t
2173DwarfFile::_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
2565status_t
2566DwarfFile::_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
2605status_t
2606DwarfFile::_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
2644status_t
2645DwarfFile::_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
2675DebugInfoEntry*
2676DwarfFile::_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
2709status_t
2710DwarfFile::_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
2732status_t
2733DwarfFile::_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
2784status_t
2785DwarfFile::_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
2855status_t
2856DwarfFile::_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
2902TypeUnitTableEntry*
2903DwarfFile::_GetTypeUnit(uint64 signature) const
2904{
2905	return fTypeUnits.Lookup(signature);
2906}
2907
2908
2909CompilationUnit*
2910DwarfFile::_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
2931DwarfFile::FDELookupInfo*
2932DwarfFile::_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
2945DwarfFile::FDELookupInfo*
2946DwarfFile::_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