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