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