headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / debugger / dwarf / DwarfFile.cpp
blobe382d6200ea7154127cba4570dca05e878e293a2
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 */
8 #include "DwarfFile.h"
10 #include <algorithm>
11 #include <new>
13 #include <AutoDeleter.h>
14 #include <Entry.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <PathFinder.h>
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"
34 // #pragma mark - AutoSectionPutter
37 class AutoSectionPutter {
38 public:
39 AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection)
41 fElfFile(elfFile),
42 fElfSection(elfSection)
46 ~AutoSectionPutter()
48 if (fElfSection != NULL)
49 fElfFile->PutSection(fElfSection);
52 private:
53 ElfFile* fElfFile;
54 ElfSection* fElfSection;
58 // #pragma mark - ExpressionEvaluationContext
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)
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)
85 virtual bool GetObjectAddress(target_addr_t& _address)
87 if (!fHasObjectPointer)
88 return false;
90 _address = fObjectPointer;
91 return true;
94 virtual bool GetFrameAddress(target_addr_t& _address)
96 if (fFramePointer == 0)
97 return false;
99 _address = fFramePointer;
100 return true;
103 virtual bool GetFrameBaseAddress(target_addr_t& _address)
105 if (fFrameBaseEvaluated) {
106 if (fFrameBasePointer == 0)
107 return false;
109 _address = fFrameBasePointer;
110 return true;
113 // set flag already to prevent recursion for a buggy expression
114 fFrameBaseEvaluated = true;
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;
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;
131 // evaluate the expression
132 DwarfExpressionEvaluator evaluator(this);
133 error = evaluator.Evaluate(expression, expressionLength,
134 fFrameBasePointer);
135 if (error != B_OK)
136 return false;
138 TRACE_EXPR(" -> frame base: %" B_PRIx64 "\n", fFrameBasePointer);
140 _address = fFrameBasePointer;
141 return true;
144 virtual bool GetTLSAddress(target_addr_t localAddress,
145 target_addr_t& _address)
147 // TODO:...
148 return false;
151 virtual status_t GetCallTarget(uint64 offset, uint8 refType,
152 const void*& _block, off_t& _size)
154 // resolve the entry
155 DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType);
156 if (entry == NULL)
157 return B_ENTRY_NOT_FOUND;
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;
167 // get the expression
168 return fFile->_GetLocationExpression(fUnit, location,
169 fInstructionPointer, _block, _size);
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;
185 // #pragma mark - FDEAugmentation
188 struct DwarfFile::FDEAugmentation {
189 // Currently we're ignoring all augmentation data.
193 // #pragma mark - CIEAugmentation
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,
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
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
233 struct DwarfFile::CIEAugmentation {
234 CIEAugmentation()
236 fString(NULL),
237 fFlags(0),
238 fAddressEncoding(CFI_ADDRESS_FORMAT_ABSOLUTE)
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'
245 void Init(DataReader& dataReader)
247 fFlags = 0;
248 fString = dataReader.ReadString();
251 status_t Read(DataReader& dataReader)
253 if (fString == NULL || *fString == '\0')
254 return B_OK;
256 if (*fString == 'z') {
257 // There are augmentation data.
258 fFlags |= CFI_AUGMENTATION_DATA;
259 const char* string = fString + 1;
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
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':
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;
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;
296 string++;
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;
308 return B_OK;
311 // nothing to do
312 if (strcmp(fString, "eh") == 0)
313 return B_OK;
315 // something we can't handle
316 return B_UNSUPPORTED;
319 status_t ReadFDEData(DataReader& dataReader,
320 FDEAugmentation& fdeAugmentation)
322 if (!HasData())
323 return B_OK;
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!
331 TRACE_CFI(" %" B_PRIu64 " bytes of augmentation data\n", length);
333 if (dataReader.HasOverflow())
334 return B_BAD_DATA;
336 return B_OK;
339 const char* String() const
341 return fString;
344 bool HasData() const
346 return (fFlags & CFI_AUGMENTATION_DATA) != 0;
349 bool HasFDEAddressFormat() const
351 return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0;
354 target_addr_t FDEAddressOffset(ElfFile* file,
355 ElfSection* debugFrameSection) const
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;
381 return 0;
384 uint8 FDEAddressType() const
386 return fAddressEncoding & 0x70;
389 target_addr_t ReadEncodedAddress(DataReader &reader,
390 ElfFile* file, ElfSection* debugFrameSection,
391 bool valueOnly = false) const
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;
434 return address;
438 private:
439 const char* fString;
440 uint32 fFlags;
441 int8 fAddressEncoding;
445 // #pragma mark - FDELookupInfo
448 struct DwarfFile::FDELookupInfo {
449 public:
450 FDELookupInfo(target_addr_t start, target_addr_t end,
451 uint64 fdeOffset, uint64 cieOffset, bool ehFrame)
453 start(start),
454 end(end),
455 fdeOffset(fdeOffset),
456 cieOffset(cieOffset),
457 ehFrame(ehFrame)
461 static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b)
463 if (a->start < b->start)
464 return -1;
465 else if (a->start > b->start)
466 return 1;
468 return 0;
471 inline bool ContainsAddress(target_addr_t address) const
473 return address >= start && address < end;
476 target_addr_t start;
477 target_addr_t end;
478 uint64 fdeOffset;
479 uint64 cieOffset;
480 bool ehFrame;
484 // #pragma mark - DwarfFile
487 DwarfFile::DwarfFile()
489 fName(NULL),
490 fAlternateName(NULL),
491 fElfFile(NULL),
492 fAlternateElfFile(NULL),
493 fDebugInfoSection(NULL),
494 fDebugAbbrevSection(NULL),
495 fDebugStringSection(NULL),
496 fDebugRangesSection(NULL),
497 fDebugLineSection(NULL),
498 fDebugFrameSection(NULL),
499 fEHFrameSection(NULL),
500 fDebugLocationSection(NULL),
501 fDebugPublicTypesSection(NULL),
502 fDebugTypesSection(NULL),
503 fCompilationUnits(20, true),
504 fTypeUnits(),
505 fDebugFrameInfos(100, true),
506 fEHFrameInfos(100, true),
507 fTypesSectionRequired(false),
508 fFinished(false),
509 fItaniumEHFrameFormat(false),
510 fFinishError(B_OK)
515 DwarfFile::~DwarfFile()
517 while (AbbreviationTable* table = fAbbreviationTables.RemoveHead())
518 delete table;
520 if (fElfFile != NULL) {
521 ElfFile* debugInfoFile = fAlternateElfFile != NULL
522 ? fAlternateElfFile : fElfFile;
524 debugInfoFile->PutSection(fDebugInfoSection);
525 debugInfoFile->PutSection(fDebugAbbrevSection);
526 debugInfoFile->PutSection(fDebugStringSection);
527 debugInfoFile->PutSection(fDebugRangesSection);
528 debugInfoFile->PutSection(fDebugLineSection);
529 debugInfoFile->PutSection(fDebugFrameSection);
530 fElfFile->PutSection(fEHFrameSection);
531 debugInfoFile->PutSection(fDebugLocationSection);
532 debugInfoFile->PutSection(fDebugPublicTypesSection);
533 delete fElfFile;
534 delete fAlternateElfFile;
537 TypeUnitTableEntry* entry = fTypeUnits.Clear(true);
538 while (entry != NULL) {
539 TypeUnitTableEntry* nextEntry = entry->next;
540 delete entry;
541 entry = nextEntry;
544 free(fName);
545 free(fAlternateName);
549 status_t
550 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
552 fName = strdup(fileName);
553 if (fName == NULL)
554 return B_NO_MEMORY;
556 status_t error = fTypeUnits.Init();
557 if (error != B_OK)
558 return error;
560 // load the ELF file
561 fElfFile = new(std::nothrow) ElfFile;
562 if (fElfFile == NULL)
563 return B_NO_MEMORY;
565 error = fElfFile->Init(fileName);
566 if (error != B_OK)
567 return error;
569 return _LocateDebugInfo(_requiredExternalFile);
573 status_t
574 DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath)
576 status_t error = B_OK;
577 if (fDebugInfoSection == NULL) {
578 BString path;
579 error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty()
580 ? NULL : externalInfoFilePath.String());
581 if (error != B_OK)
582 return error;
585 ElfFile* debugInfoFile = fAlternateElfFile != NULL
586 ? fAlternateElfFile : fElfFile;
588 // non mandatory sections
589 fDebugStringSection = debugInfoFile->GetSection(".debug_str");
590 fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
591 fDebugLineSection = debugInfoFile->GetSection(".debug_line");
592 fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
594 if (fDebugFrameSection != NULL) {
595 error = _ParseFrameSection(fDebugFrameSection, addressSize, false,
596 fDebugFrameInfos);
597 if (error != B_OK)
598 return error;
601 // .eh_frame doesn't appear to get copied into separate debug
602 // info files properly, therefore always use it off the main
603 // executable image
604 if (fEHFrameSection == NULL)
605 fEHFrameSection = fElfFile->GetSection(".eh_frame");
607 if (fEHFrameSection != NULL) {
608 error = _ParseFrameSection(fEHFrameSection, addressSize, true,
609 fEHFrameInfos);
610 if (error != B_OK)
611 return error;
614 fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
615 fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
617 if (fDebugInfoSection == NULL) {
618 fFinished = true;
619 return B_OK;
622 error = _ParseDebugInfoSection();
623 if (error != B_OK)
624 return error;
626 if (fTypesSectionRequired) {
627 fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
628 if (fDebugTypesSection == NULL) {
629 WARNING(".debug_types section required but missing.\n");
630 return B_BAD_DATA;
632 error = _ParseTypesSection();
633 if (error != B_OK)
634 return error;
637 return B_OK;
641 status_t
642 DwarfFile::FinishLoading()
644 if (fFinished)
645 return B_OK;
646 if (fFinishError != B_OK)
647 return fFinishError;
649 status_t error;
650 for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator();
651 TypeUnitTableEntry* entry = it.Next();) {
652 error = _FinishUnit(entry->unit);
653 if (error != B_OK)
654 return fFinishError = error;
657 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
658 i++) {
659 error = _FinishUnit(unit);
660 if (error != B_OK)
661 return fFinishError = error;
664 _ParsePublicTypesInfo();
666 fFinished = true;
667 return B_OK;
671 int32
672 DwarfFile::CountCompilationUnits() const
674 return fCompilationUnits.CountItems();
678 CompilationUnit*
679 DwarfFile::CompilationUnitAt(int32 index) const
681 return fCompilationUnits.ItemAt(index);
685 CompilationUnit*
686 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const
688 // find the root of the tree the entry lives in
689 while (entry != NULL && entry->Parent() != NULL)
690 entry = entry->Parent();
692 // that should be the compilation unit entry
693 const DIECompileUnitBase* unitEntry
694 = dynamic_cast<const DIECompileUnitBase*>(entry);
695 if (unitEntry == NULL)
696 return NULL;
698 // find the compilation unit
699 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
700 i++) {
701 if (unit->UnitEntry() == unitEntry)
702 return unit;
705 return NULL;
709 TargetAddressRangeList*
710 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
712 if (unit == NULL || fDebugRangesSection == NULL)
713 return NULL;
715 if (offset >= (uint64)fDebugRangesSection->Size())
716 return NULL;
718 TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList;
719 if (ranges == NULL) {
720 ERROR("Out of memory.\n");
721 return NULL;
723 BReference<TargetAddressRangeList> rangesReference(ranges, true);
725 target_addr_t baseAddress = unit->AddressRangeBase();
726 target_addr_t maxAddress = unit->MaxAddress();
728 DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset,
729 fDebugRangesSection->Size() - offset, unit->AddressSize());
730 while (true) {
731 target_addr_t start = dataReader.ReadAddress(0);
732 target_addr_t end = dataReader.ReadAddress(0);
733 if (dataReader.HasOverflow())
734 return NULL;
736 if (start == 0 && end == 0)
737 break;
738 if (start == maxAddress) {
739 baseAddress = end;
740 continue;
742 if (start == end)
743 continue;
745 if (!ranges->AddRange(baseAddress + start, end - start)) {
746 ERROR("Out of memory.\n");
747 return NULL;
751 return rangesReference.Detach();
755 status_t
756 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
757 DIESubprogram* subprogramEntry, target_addr_t location,
758 const DwarfTargetInterface* inputInterface,
759 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
761 FDELookupInfo* info = _GetContainingFDEInfo(location);
762 if (info == NULL)
763 return B_ENTRY_NOT_FOUND;
765 return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info,
766 inputInterface, outputInterface, _framePointer);
770 status_t
771 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize,
772 DIESubprogram* subprogramEntry, const void* expression,
773 off_t expressionLength, const DwarfTargetInterface* targetInterface,
774 target_addr_t instructionPointer, target_addr_t framePointer,
775 target_addr_t valueToPush, bool pushValue, target_addr_t& _result)
777 ExpressionEvaluationContext context(this, unit, addressSize,
778 subprogramEntry, targetInterface, instructionPointer, 0, false,
779 framePointer, 0);
780 DwarfExpressionEvaluator evaluator(&context);
782 if (pushValue && evaluator.Push(valueToPush) != B_OK)
783 return B_NO_MEMORY;
785 return evaluator.Evaluate(expression, expressionLength, _result);
789 status_t
790 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize,
791 DIESubprogram* subprogramEntry, const LocationDescription* location,
792 const DwarfTargetInterface* targetInterface,
793 target_addr_t instructionPointer, target_addr_t objectPointer,
794 bool hasObjectPointer, target_addr_t framePointer,
795 target_addr_t relocationDelta, ValueLocation& _result)
797 // get the expression
798 const void* expression;
799 off_t expressionLength;
800 status_t error = _GetLocationExpression(unit, location, instructionPointer,
801 expression, expressionLength);
802 if (error != B_OK)
803 return error;
805 // evaluate it
806 ExpressionEvaluationContext context(this, unit, addressSize,
807 subprogramEntry, targetInterface, instructionPointer, objectPointer,
808 hasObjectPointer, framePointer, relocationDelta);
809 DwarfExpressionEvaluator evaluator(&context);
810 return evaluator.EvaluateLocation(expression, expressionLength,
811 _result);
815 status_t
816 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize,
817 DIESubprogram* subprogramEntry, const ConstantAttributeValue* value,
818 const DwarfTargetInterface* targetInterface,
819 target_addr_t instructionPointer, target_addr_t framePointer,
820 BVariant& _result)
822 if (!value->IsValid())
823 return B_BAD_VALUE;
825 switch (value->attributeClass) {
826 case ATTRIBUTE_CLASS_CONSTANT:
827 _result.SetTo(value->constant);
828 return B_OK;
829 case ATTRIBUTE_CLASS_STRING:
830 _result.SetTo(value->string);
831 return B_OK;
832 case ATTRIBUTE_CLASS_BLOCK:
834 target_addr_t result;
835 status_t error = EvaluateExpression(unit, addressSize,
836 subprogramEntry, value->block.data, value->block.length,
837 targetInterface, instructionPointer, framePointer, 0, false,
838 result);
839 if (error != B_OK)
840 return error;
842 _result.SetTo(result);
843 return B_OK;
845 default:
846 return B_BAD_VALUE;
851 status_t
852 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize,
853 DIESubprogram* subprogramEntry, const DynamicAttributeValue* value,
854 const DwarfTargetInterface* targetInterface,
855 target_addr_t instructionPointer, target_addr_t framePointer,
856 BVariant& _result, DIEType** _type)
858 if (!value->IsValid())
859 return B_BAD_VALUE;
861 DIEType* dummyType;
862 if (_type == NULL)
863 _type = &dummyType;
865 switch (value->attributeClass) {
866 case ATTRIBUTE_CLASS_CONSTANT:
867 _result.SetTo(value->constant);
868 *_type = NULL;
869 return B_OK;
871 case ATTRIBUTE_CLASS_REFERENCE:
873 // TODO: The specs are a bit fuzzy on this one: "the value is a
874 // reference to another entity whose value is the value of the
875 // attribute". Supposedly that also means e.g. if the referenced
876 // entity is a variable, we should read the value of that variable.
877 // ATM we only check for the types that can have a DW_AT_const_value
878 // attribute and evaluate it, if present.
879 DebugInfoEntry* entry = value->reference;
880 if (entry == NULL)
881 return B_BAD_VALUE;
883 const ConstantAttributeValue* constantValue = NULL;
884 DIEType* type = NULL;
886 switch (entry->Tag()) {
887 case DW_TAG_constant:
889 DIEConstant* constantEntry
890 = dynamic_cast<DIEConstant*>(entry);
891 constantValue = constantEntry->ConstValue();
892 type = constantEntry->GetType();
893 break;
895 case DW_TAG_enumerator:
896 constantValue = dynamic_cast<DIEEnumerator*>(entry)
897 ->ConstValue();
898 if (DIEEnumerationType* enumerationType
899 = dynamic_cast<DIEEnumerationType*>(
900 entry->Parent())) {
901 type = enumerationType->GetType();
903 break;
904 case DW_TAG_formal_parameter:
906 DIEFormalParameter* parameterEntry
907 = dynamic_cast<DIEFormalParameter*>(entry);
908 constantValue = parameterEntry->ConstValue();
909 type = parameterEntry->GetType();
910 break;
912 case DW_TAG_template_value_parameter:
914 DIETemplateValueParameter* parameterEntry
915 = dynamic_cast<DIETemplateValueParameter*>(entry);
916 constantValue = parameterEntry->ConstValue();
917 type = parameterEntry->GetType();
918 break;
920 case DW_TAG_variable:
922 DIEVariable* variableEntry
923 = dynamic_cast<DIEVariable*>(entry);
924 constantValue = variableEntry->ConstValue();
925 type = variableEntry->GetType();
926 break;
928 default:
929 return B_BAD_VALUE;
932 if (constantValue == NULL || !constantValue->IsValid())
933 return B_BAD_VALUE;
935 status_t error = EvaluateConstantValue(unit, addressSize,
936 subprogramEntry, constantValue, targetInterface,
937 instructionPointer, framePointer, _result);
938 if (error != B_OK)
939 return error;
941 *_type = type;
942 return B_OK;
945 case ATTRIBUTE_CLASS_BLOCK:
947 target_addr_t result;
948 status_t error = EvaluateExpression(unit, addressSize,
949 subprogramEntry, value->block.data, value->block.length,
950 targetInterface, instructionPointer, framePointer, 0, false,
951 result);
952 if (error != B_OK)
953 return error;
955 _result.SetTo(result);
956 *_type = NULL;
957 return B_OK;
960 default:
961 return B_BAD_VALUE;
966 status_t
967 DwarfFile::_ParseDebugInfoSection()
969 // iterate through the debug info section
970 DataReader dataReader(fDebugInfoSection->Data(),
971 fDebugInfoSection->Size(), 4);
972 // address size doesn't matter here
973 while (dataReader.HasData()) {
974 off_t unitHeaderOffset = dataReader.Offset();
975 bool dwarf64;
976 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
978 off_t unitLengthOffset = dataReader.Offset();
979 // the unitLength starts here
981 if (unitLengthOffset + unitLength
982 > (uint64)fDebugInfoSection->Size()) {
983 WARNING("\"%s\": Invalid compilation unit length.\n", fName);
984 break;
987 int version = dataReader.Read<uint16>(0);
988 off_t abbrevOffset = dwarf64
989 ? dataReader.Read<uint64>(0)
990 : dataReader.Read<uint32>(0);
991 uint8 addressSize = dataReader.Read<uint8>(0);
993 if (dataReader.HasOverflow()) {
994 WARNING("\"%s\": Unexpected end of data in compilation unit "
995 "header.\n", fName);
996 break;
999 TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
1000 ", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
1001 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
1003 if (version < 2 || version > 4) {
1004 WARNING("\"%s\": Unsupported compilation unit version: %d\n",
1005 fName, version);
1006 break;
1009 if (addressSize != 4 && addressSize != 8) {
1010 WARNING("\"%s\": Unsupported address size: %d\n", fName,
1011 addressSize);
1012 break;
1014 dataReader.SetAddressSize(addressSize);
1016 off_t unitContentOffset = dataReader.Offset();
1018 // create a compilation unit object
1019 CompilationUnit* unit = new(std::nothrow) CompilationUnit(
1020 unitHeaderOffset, unitContentOffset,
1021 unitLength + (unitLengthOffset - unitHeaderOffset),
1022 abbrevOffset, addressSize, dwarf64);
1023 if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
1024 delete unit;
1025 return B_NO_MEMORY;
1028 // parse the debug info for the unit
1029 status_t error = _ParseCompilationUnit(unit);
1030 if (error != B_OK)
1031 return error;
1033 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1036 return B_OK;
1040 status_t
1041 DwarfFile::_ParseTypesSection()
1043 DataReader dataReader(fDebugTypesSection->Data(),
1044 fDebugTypesSection->Size(), 4);
1045 while (dataReader.HasData()) {
1046 off_t unitHeaderOffset = dataReader.Offset();
1047 bool dwarf64;
1048 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1050 off_t unitLengthOffset = dataReader.Offset();
1051 // the unitLength starts here
1053 if (unitLengthOffset + unitLength
1054 > (uint64)fDebugTypesSection->Size()) {
1055 WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n",
1056 unitHeaderOffset);
1057 break;
1060 int version = dataReader.Read<uint16>(0);
1061 off_t abbrevOffset = dwarf64
1062 ? dataReader.Read<uint64>(0)
1063 : dataReader.Read<uint32>(0);
1064 uint8 addressSize = dataReader.Read<uint8>(0);
1066 if (dataReader.HasOverflow()) {
1067 WARNING("Unexpected end of data in type unit header at %#"
1068 B_PRIx64 ".\n", unitHeaderOffset);
1069 break;
1072 dataReader.SetAddressSize(addressSize);
1074 uint64 signature = dataReader.Read<uint64>(0);
1076 off_t typeOffset = dwarf64
1077 ? dataReader.Read<uint64>(0)
1078 : dataReader.Read<uint32>(0);
1080 off_t unitContentOffset = dataReader.Offset();
1082 TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64
1083 ", abbrevOffset: %" B_PRIdOFF ", address size: %d, "
1084 "signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n",
1085 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize,
1086 signature, typeOffset);
1088 if (version > 4) {
1089 WARNING("\"%s\": Unsupported type unit version: %d\n",
1090 fName, version);
1091 break;
1094 if (addressSize != 4 && addressSize != 8) {
1095 WARNING("\"%s\": Unsupported address size: %d\n", fName,
1096 addressSize);
1097 break;
1100 // create a type unit object
1101 TypeUnit* unit = new(std::nothrow) TypeUnit(
1102 unitHeaderOffset, unitContentOffset,
1103 unitLength + (unitLengthOffset - unitHeaderOffset),
1104 abbrevOffset, typeOffset, addressSize, signature, dwarf64);
1105 if (unit == NULL)
1106 return B_NO_MEMORY;
1108 // parse the debug info for the unit
1109 status_t error = _ParseTypeUnit(unit);
1110 if (error != B_OK)
1111 return error;
1113 // TODO: it should theoretically never happen that we get a duplicate,
1114 // but it wouldn't hurt to check since that situation would potentially
1115 // be problematic.
1116 if (fTypeUnits.Lookup(signature) == NULL) {
1117 TypeUnitTableEntry* entry = new(std::nothrow)
1118 TypeUnitTableEntry(signature, unit);
1119 if (entry == NULL)
1120 return B_NO_MEMORY;
1122 fTypeUnits.Insert(entry);
1125 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1128 return B_OK;
1132 status_t
1133 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize,
1134 bool ehFrame, FDEInfoList& infos)
1136 if (ehFrame) {
1137 fItaniumEHFrameFormat = section->IsWritable();
1138 // Crude heuristic for recognizing GCC 4 (Itanium ABI) style
1139 // .eh_frame sections. The ones generated by GCC 2 are writable,
1140 // the ones generated by GCC 4 aren't.
1143 DataReader dataReader((uint8*)section->Data(),
1144 section->Size(), addressSize);
1146 while (dataReader.BytesRemaining() > 0) {
1147 // length
1148 bool dwarf64;
1149 off_t entryOffset = dataReader.Offset();
1150 uint64 length = dataReader.ReadInitialLength(dwarf64);
1152 TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF
1153 ", length: %" B_PRId64 "\n", entryOffset, length);
1155 if (length > (uint64)dataReader.BytesRemaining())
1156 return B_BAD_DATA;
1157 off_t lengthOffset = dataReader.Offset();
1159 // CIE ID/CIE pointer
1160 uint64 cieID = dwarf64
1161 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1163 // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
1164 if (ehFrame
1165 ? cieID == 0
1166 : (dwarf64
1167 ? cieID == 0xffffffffffffffffULL
1168 : cieID == 0xffffffff)) {
1169 // this is a CIE -- skip it
1170 } else {
1171 // this is a FDE
1172 uint64 initialLocationOffset = dataReader.Offset();
1173 // In .eh_frame the CIE offset is a relative back offset.
1174 if (ehFrame) {
1175 if (cieID > (uint64)lengthOffset) {
1176 TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
1177 "possible: %" B_PRIu64 "\n", cieID, lengthOffset);
1178 break;
1180 // convert to a section relative offset
1181 cieID = lengthOffset - cieID;
1185 CfaContext context;
1186 CIEAugmentation cieAugmentation;
1187 // when using .eh_frame format, we need to parse the CIE's
1188 // augmentation up front in order to know how the FDE's addresses
1189 // will be represented
1190 DataReader cieReader;
1191 off_t cieRemaining;
1192 status_t error = _ParseCIEHeader(section, ehFrame, NULL,
1193 addressSize, context, cieID, cieAugmentation, cieReader,
1194 cieRemaining);
1195 if (error != B_OK)
1196 return error;
1197 if (cieReader.HasOverflow())
1198 return B_BAD_DATA;
1199 if (cieRemaining < 0)
1200 return B_BAD_DATA;
1202 target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
1203 dataReader, fElfFile, section);
1204 target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
1205 dataReader, fElfFile, section, true);
1207 if (dataReader.HasOverflow())
1208 return B_BAD_DATA;
1210 if ((cieAugmentation.FDEAddressType()
1211 & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
1212 initialLocation += initialLocationOffset;
1215 // for unknown reasons, the debug frame sections generated by gcc
1216 // sometimes contain duplicates at different offsets within the
1217 // section. In such a case, simply skip the duplicates.
1218 FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
1219 infos);
1220 if (temp == NULL) {
1221 FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
1222 initialLocation, initialLocation + addressRange - 1,
1223 entryOffset, cieID, ehFrame);
1224 if (info == NULL)
1225 return B_NO_MEMORY;
1227 ObjectDeleter<FDELookupInfo> infoDeleter(info);
1228 if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
1229 return B_NO_MEMORY;
1231 infoDeleter.Detach();
1235 dataReader.SeekAbsolute(lengthOffset + length);
1238 return B_OK;
1242 status_t
1243 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
1245 AbbreviationTable* abbreviationTable;
1246 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1247 abbreviationTable);
1248 if (error != B_OK)
1249 return error;
1251 unit->SetAbbreviationTable(abbreviationTable);
1253 DataReader dataReader(
1254 (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(),
1255 unit->ContentSize(), unit->AddressSize());
1257 DebugInfoEntry* entry;
1258 bool endOfEntryList;
1259 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1260 endOfEntryList);
1261 if (error != B_OK)
1262 return error;
1264 DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry);
1265 if (unitEntry == NULL) {
1266 WARNING("No compilation unit entry in .debug_info section.\n");
1267 return B_BAD_DATA;
1270 unit->SetUnitEntry(unitEntry);
1272 TRACE_DIE_ONLY(
1273 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1274 dataReader.BytesRemaining());
1275 if (dataReader.HasData()) {
1276 TRACE_DIE(" ");
1277 while (dataReader.HasData())
1278 TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1279 TRACE_DIE("\n");
1282 return B_OK;
1286 status_t
1287 DwarfFile::_ParseTypeUnit(TypeUnit* unit)
1289 AbbreviationTable* abbreviationTable;
1290 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1291 abbreviationTable);
1292 if (error != B_OK)
1293 return error;
1295 unit->SetAbbreviationTable(abbreviationTable);
1297 DataReader dataReader(
1298 (const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
1299 unit->ContentSize(), unit->AddressSize());
1301 DebugInfoEntry* entry;
1302 bool endOfEntryList;
1303 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1304 endOfEntryList);
1305 if (error != B_OK)
1306 return error;
1308 DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
1309 if (unitEntry == NULL) {
1310 WARNING("No type unit entry in .debug_types section.\n");
1311 return B_BAD_DATA;
1314 unit->SetUnitEntry(unitEntry);
1315 DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset());
1316 if (typeEntry == NULL) {
1317 WARNING("No type found for type unit %p at specified offset %"
1318 B_PRId64 ".\n", unit, unit->TypeOffset());
1319 return B_BAD_DATA;
1321 unit->SetTypeEntry(typeEntry);
1323 TRACE_DIE_ONLY(
1324 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1325 dataReader.BytesRemaining());
1326 if (dataReader.HasData()) {
1327 TRACE_DIE(" ");
1328 while (dataReader.HasData())
1329 TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1330 TRACE_DIE("\n");
1333 return B_OK;
1337 status_t
1338 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
1339 BaseUnit* unit, AbbreviationTable* abbreviationTable,
1340 DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
1342 off_t entryOffset = dataReader.Offset()
1343 + unit->RelativeContentOffset();
1345 uint32 code = dataReader.ReadUnsignedLEB128(0);
1346 if (code == 0) {
1347 if (dataReader.HasOverflow()) {
1348 WARNING("Unexpected end of .debug_info section.\n");
1349 return B_BAD_DATA;
1351 _entry = NULL;
1352 _endOfEntryList = true;
1353 return B_OK;
1356 // get the corresponding abbreviation entry
1357 AbbreviationEntry abbreviationEntry;
1358 if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
1359 WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
1360 return B_BAD_DATA;
1363 DebugInfoEntry* entry;
1364 status_t error = fDebugInfoFactory.CreateDebugInfoEntry(
1365 abbreviationEntry.Tag(), entry);
1366 if (error != B_OK) {
1367 WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %"
1368 B_PRIu32 "\n", abbreviationEntry.Tag(), code);
1369 return error;
1372 ObjectDeleter<DebugInfoEntry> entryDeleter(entry);
1374 TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%"
1375 B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset,
1376 abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
1377 abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
1379 error = unit->AddDebugInfoEntry(entry, entryOffset);
1381 if (error != B_OK)
1382 return error;
1384 // parse the attributes (supply NULL entry to avoid adding them yet)
1385 error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
1386 if (error != B_OK)
1387 return error;
1389 // parse children, if the entry has any
1390 if (abbreviationEntry.HasChildren()) {
1391 while (true) {
1392 DebugInfoEntry* childEntry;
1393 bool endOfEntryList;
1394 status_t error = _ParseDebugInfoEntry(dataReader,
1395 unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
1396 if (error != B_OK)
1397 return error;
1399 // add the child to our entry
1400 if (childEntry != NULL) {
1401 if (entry != NULL) {
1402 error = entry->AddChild(childEntry);
1403 if (error == B_OK) {
1404 childEntry->SetParent(entry);
1405 } else if (error == ENTRY_NOT_HANDLED) {
1406 error = B_OK;
1407 TRACE_DIE("%*s -> child unhandled\n", level * 2, "");
1410 if (error != B_OK) {
1411 delete childEntry;
1412 return error;
1414 } else
1415 delete childEntry;
1418 if (endOfEntryList)
1419 break;
1423 entryDeleter.Detach();
1424 _entry = entry;
1425 _endOfEntryList = false;
1426 return B_OK;
1430 status_t
1431 DwarfFile::_FinishUnit(BaseUnit* unit)
1433 CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
1434 bool isTypeUnit = compilationUnit == NULL;
1435 TRACE_DIE("\nfinishing %s unit %p\n",
1436 isTypeUnit ? "type" : "compilation", unit);
1439 AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
1441 ElfSection* section = isTypeUnit
1442 ? fDebugTypesSection : fDebugInfoSection;
1443 DataReader dataReader(
1444 (const uint8*)section->Data() + unit->HeaderOffset(),
1445 unit->TotalSize(), unit->AddressSize());
1447 DebugInfoEntryInitInfo entryInitInfo;
1449 int entryCount = unit->CountEntries();
1450 for (int i = 0; i < entryCount; i++) {
1451 // get the entry
1452 DebugInfoEntry* entry;
1453 off_t offset;
1454 unit->GetEntryAt(i, entry, offset);
1456 TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset);
1458 // seek the reader to the entry
1459 dataReader.SeekAbsolute(offset);
1461 // read the entry code
1462 uint32 code = dataReader.ReadUnsignedLEB128(0);
1464 // get the respective abbreviation entry
1465 AbbreviationEntry abbreviationEntry;
1466 abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry);
1468 // initialization before setting the attributes
1469 status_t error = entry->InitAfterHierarchy(entryInitInfo);
1470 if (error != B_OK) {
1471 WARNING("Init after hierarchy failed!\n");
1472 return error;
1475 // parse the attributes -- this time pass the entry, so that the
1476 // attribute get set on it
1477 error = _ParseEntryAttributes(dataReader, unit, entry,
1478 abbreviationEntry);
1479 if (error != B_OK)
1480 return error;
1482 // initialization after setting the attributes
1483 error = entry->InitAfterAttributes(entryInitInfo);
1484 if (error != B_OK) {
1485 WARNING("Init after attributes failed!\n");
1486 return error;
1490 // set the compilation unit's source language
1491 unit->SetSourceLanguage(entryInitInfo.languageInfo);
1493 if (isTypeUnit)
1494 return B_OK;
1496 // resolve the compilation unit's address range list
1497 if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
1498 compilationUnit->UnitEntry()->AddressRangesOffset())) {
1499 compilationUnit->SetAddressRanges(ranges);
1500 ranges->ReleaseReference();
1503 // add compilation dir to directory list
1504 const char* compilationDir = compilationUnit->UnitEntry()
1505 ->CompilationDir();
1506 if (!compilationUnit->AddDirectory(compilationDir != NULL
1507 ? compilationDir : ".")) {
1508 return B_NO_MEMORY;
1511 // parse line info header
1512 if (fDebugLineSection != NULL)
1513 _ParseLineInfo(compilationUnit);
1515 return B_OK;
1519 status_t
1520 DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
1521 BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
1523 uint32 attributeName;
1524 uint32 attributeForm;
1525 while (abbreviationEntry.GetNextAttribute(attributeName,
1526 attributeForm)) {
1527 // resolve attribute form indirection
1528 if (attributeForm == DW_FORM_indirect)
1529 attributeForm = dataReader.ReadUnsignedLEB128(0);
1531 // prepare an AttributeValue
1532 AttributeValue attributeValue;
1533 attributeValue.attributeForm = attributeForm;
1534 bool isSigned = false;
1536 // Read the attribute value according to the attribute's form. For
1537 // the forms that don't map to a single attribute class only or
1538 // those that need additional processing, we read a temporary value
1539 // first.
1540 uint64 value = 0;
1541 off_t blockLength = 0;
1542 off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
1543 uint8 refType = dwarf_reference_type_local;
1545 switch (attributeForm) {
1546 case DW_FORM_addr:
1547 value = dataReader.ReadAddress(0);
1548 break;
1549 case DW_FORM_block2:
1550 blockLength = dataReader.Read<uint16>(0);
1551 break;
1552 case DW_FORM_block4:
1553 blockLength = dataReader.Read<uint32>(0);
1554 break;
1555 case DW_FORM_data2:
1556 value = dataReader.Read<uint16>(0);
1557 break;
1558 case DW_FORM_data4:
1559 value = dataReader.Read<uint32>(0);
1560 break;
1561 case DW_FORM_data8:
1562 value = dataReader.Read<uint64>(0);
1563 break;
1564 case DW_FORM_string:
1565 attributeValue.SetToString(dataReader.ReadString());
1566 break;
1567 case DW_FORM_block:
1568 case DW_FORM_exprloc:
1569 blockLength = dataReader.ReadUnsignedLEB128(0);
1570 break;
1571 case DW_FORM_block1:
1572 blockLength = dataReader.Read<uint8>(0);
1573 break;
1574 case DW_FORM_data1:
1575 value = dataReader.Read<uint8>(0);
1576 break;
1577 case DW_FORM_flag:
1578 attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0);
1579 break;
1580 case DW_FORM_sdata:
1581 value = dataReader.ReadSignedLEB128(0);
1582 isSigned = true;
1583 break;
1584 case DW_FORM_strp:
1586 if (fDebugStringSection != NULL) {
1587 uint64 offset = unit->IsDwarf64()
1588 ? dataReader.Read<uint64>(0)
1589 : dataReader.Read<uint32>(0);
1590 if (offset >= fDebugStringSection->Size()) {
1591 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1592 offset);
1593 return B_BAD_DATA;
1595 attributeValue.SetToString(
1596 (const char*)fDebugStringSection->Data() + offset);
1597 } else {
1598 WARNING("Invalid DW_FORM_strp: no string section!\n");
1599 return B_BAD_DATA;
1601 break;
1603 case DW_FORM_udata:
1604 value = dataReader.ReadUnsignedLEB128(0);
1605 break;
1606 case DW_FORM_ref_addr:
1607 value = unit->IsDwarf64()
1608 ? dataReader.Read<uint64>(0)
1609 : (uint64)dataReader.Read<uint32>(0);
1610 refType = dwarf_reference_type_global;
1611 break;
1612 case DW_FORM_ref1:
1613 value = dataReader.Read<uint8>(0);
1614 break;
1615 case DW_FORM_ref2:
1616 value = dataReader.Read<uint16>(0);
1617 break;
1618 case DW_FORM_ref4:
1619 value = dataReader.Read<uint32>(0);
1620 break;
1621 case DW_FORM_ref8:
1622 value = dataReader.Read<uint64>(0);
1623 break;
1624 case DW_FORM_ref_udata:
1625 value = dataReader.ReadUnsignedLEB128(0);
1626 break;
1627 case DW_FORM_flag_present:
1628 attributeValue.SetToFlag(true);
1629 break;
1630 case DW_FORM_ref_sig8:
1631 fTypesSectionRequired = true;
1632 value = dataReader.Read<uint64>(0);
1633 refType = dwarf_reference_type_signature;
1634 break;
1635 case DW_FORM_sec_offset:
1636 value = unit->IsDwarf64()
1637 ? dataReader.Read<uint64>(0)
1638 : (uint64)dataReader.Read<uint32>(0);
1639 break;
1640 case DW_FORM_indirect:
1641 default:
1642 WARNING("Unsupported attribute form: %" B_PRIu32 "\n",
1643 attributeForm);
1644 return B_BAD_DATA;
1647 // get the attribute class -- skip the attribute, if we can't handle
1648 // it
1649 uint8 attributeClass = get_attribute_class(attributeName,
1650 attributeForm);
1652 if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
1653 TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
1654 B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
1655 get_attribute_name_name(attributeName), attributeName,
1656 get_attribute_form_name(attributeForm), attributeForm);
1657 continue;
1660 // set the attribute value according to the attribute's class
1661 switch (attributeClass) {
1662 case ATTRIBUTE_CLASS_ADDRESS:
1663 attributeValue.SetToAddress(value);
1664 break;
1665 case ATTRIBUTE_CLASS_BLOCK:
1666 attributeValue.SetToBlock(dataReader.Data(), blockLength);
1667 dataReader.Skip(blockLength);
1668 break;
1669 case ATTRIBUTE_CLASS_CONSTANT:
1670 attributeValue.SetToConstant(value, isSigned);
1671 break;
1672 case ATTRIBUTE_CLASS_LINEPTR:
1673 attributeValue.SetToLinePointer(value);
1674 break;
1675 case ATTRIBUTE_CLASS_LOCLISTPTR:
1676 attributeValue.SetToLocationListPointer(value);
1677 break;
1678 case ATTRIBUTE_CLASS_MACPTR:
1679 attributeValue.SetToMacroPointer(value);
1680 break;
1681 case ATTRIBUTE_CLASS_RANGELISTPTR:
1682 attributeValue.SetToRangeListPointer(value);
1683 break;
1684 case ATTRIBUTE_CLASS_REFERENCE:
1685 if (entry != NULL) {
1686 attributeValue.SetToReference(_ResolveReference(
1687 unit, value, refType));
1688 if (attributeValue.reference == NULL) {
1689 // gcc 2 apparently somtimes produces DW_AT_sibling
1690 // attributes pointing to the end of the sibling list.
1691 // Just ignore those.
1692 if (attributeName == DW_AT_sibling)
1693 continue;
1695 WARNING("Failed to resolve reference on entry %p: "
1696 "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
1697 "(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
1698 entry,
1699 valueOffset,
1700 get_attribute_name_name(attributeName),
1701 attributeName,
1702 get_attribute_form_name(attributeForm),
1703 attributeForm, value);
1704 return B_ENTRY_NOT_FOUND;
1707 break;
1708 case ATTRIBUTE_CLASS_FLAG:
1709 case ATTRIBUTE_CLASS_STRING:
1710 // already set
1711 break;
1714 if (dataReader.HasOverflow()) {
1715 WARNING("Unexpected end of .debug_info section.\n");
1716 return B_BAD_DATA;
1719 TRACE_DIE_ONLY(
1720 char buffer[1024];
1721 TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
1722 valueOffset,
1723 get_attribute_name_name(attributeName),
1724 get_attribute_form_name(attributeForm), attributeClass,
1725 attributeValue.ToString(buffer, sizeof(buffer)));
1728 // add the attribute
1729 if (entry != NULL) {
1730 DebugInfoEntrySetter attributeSetter
1731 = get_attribute_name_setter(attributeName);
1732 if (attributeSetter != 0) {
1733 status_t error = (entry->*attributeSetter)(attributeName,
1734 attributeValue);
1736 if (error == ATTRIBUTE_NOT_HANDLED) {
1737 error = B_OK;
1738 TRACE_DIE(" -> unhandled\n");
1741 if (error != B_OK) {
1742 WARNING("Failed to set attribute: name: %s, form: %s: %s\n",
1743 get_attribute_name_name(attributeName),
1744 get_attribute_form_name(attributeForm),
1745 strerror(error));
1747 } else
1748 TRACE_DIE(" -> no attribute setter!\n");
1752 return B_OK;
1756 status_t
1757 DwarfFile::_ParseLineInfo(CompilationUnit* unit)
1759 off_t offset = unit->UnitEntry()->StatementListOffset();
1761 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit,
1762 offset);
1764 DataReader dataReader((uint8*)fDebugLineSection->Data() + offset,
1765 fDebugLineSection->Size() - offset, unit->AddressSize());
1767 // unit length
1768 bool dwarf64;
1769 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1770 if (unitLength > (uint64)dataReader.BytesRemaining())
1771 return B_BAD_DATA;
1772 off_t unitOffset = dataReader.Offset();
1774 // version (uhalf)
1775 uint16 version = dataReader.Read<uint16>(0);
1777 // header_length (4/8)
1778 uint64 headerLength = dwarf64
1779 ? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
1780 off_t headerOffset = dataReader.Offset();
1782 if ((uint64)dataReader.BytesRemaining() < headerLength)
1783 return B_BAD_DATA;
1785 // minimum instruction length
1786 uint8 minInstructionLength = dataReader.Read<uint8>(0);
1788 // default is statement
1789 bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
1791 // line_base (sbyte)
1792 int8 lineBase = (int8)dataReader.Read<uint8>(0);
1794 // line_range (ubyte)
1795 uint8 lineRange = dataReader.Read<uint8>(0);
1797 // opcode_base (ubyte)
1798 uint8 opcodeBase = dataReader.Read<uint8>(0);
1800 // standard_opcode_lengths (ubyte[])
1801 const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
1802 dataReader.Skip(opcodeBase - 1);
1804 if (dataReader.HasOverflow())
1805 return B_BAD_DATA;
1807 if (version != 2 && version != 3)
1808 return B_UNSUPPORTED;
1810 TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength);
1811 TRACE_LINES(" version: %u\n", version);
1812 TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength);
1813 TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength);
1814 TRACE_LINES(" defaultIsStatement: %d\n", defaultIsStatement);
1815 TRACE_LINES(" lineBase: %d\n", lineBase);
1816 TRACE_LINES(" lineRange: %u\n", lineRange);
1817 TRACE_LINES(" opcodeBase: %u\n", opcodeBase);
1819 // include directories
1820 TRACE_LINES(" include directories:\n");
1821 while (const char* directory = dataReader.ReadString()) {
1822 if (*directory == '\0')
1823 break;
1824 TRACE_LINES(" \"%s\"\n", directory);
1826 if (!unit->AddDirectory(directory))
1827 return B_NO_MEMORY;
1830 // file names
1831 TRACE_LINES(" files:\n");
1832 while (const char* file = dataReader.ReadString()) {
1833 if (*file == '\0')
1834 break;
1835 uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
1836 TRACE_LINES_ONLY(uint64 modificationTime =)
1837 dataReader.ReadUnsignedLEB128(0);
1838 TRACE_LINES_ONLY(uint64 fileLength =)
1839 dataReader.ReadUnsignedLEB128(0);
1841 if (dataReader.HasOverflow())
1842 return B_BAD_DATA;
1844 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
1845 ", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
1846 fileLength);
1848 if (!unit->AddFile(file, dirIndex))
1849 return B_NO_MEMORY;
1852 off_t readerOffset = dataReader.Offset();
1853 if ((uint64)readerOffset > readerOffset + headerLength)
1854 return B_BAD_DATA;
1855 off_t offsetToProgram = headerOffset + headerLength - readerOffset;
1857 const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
1858 size_t programSize = unitLength - (readerOffset - unitOffset);
1860 return unit->GetLineNumberProgram().Init(program, programSize,
1861 minInstructionLength, defaultIsStatement, lineBase, lineRange,
1862 opcodeBase, standardOpcodeLengths);
1866 status_t
1867 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
1868 DIESubprogram* subprogramEntry, target_addr_t location,
1869 const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
1870 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
1872 ElfSection* currentFrameSection = (info->ehFrame)
1873 ? fEHFrameSection : fDebugFrameSection;
1875 TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
1877 DataReader dataReader((uint8*)currentFrameSection->Data(),
1878 currentFrameSection->Size(), unit != NULL
1879 ? unit->AddressSize() : addressSize);
1880 dataReader.SeekAbsolute(info->fdeOffset);
1882 bool dwarf64;
1883 uint64 length = dataReader.ReadInitialLength(dwarf64);
1884 uint64 lengthOffset = dataReader.Offset();
1886 CfaContext context;
1887 CIEAugmentation cieAugmentation;
1888 // when using .eh_frame format, we need to parse the CIE's
1889 // augmentation up front in order to know how the FDE's addresses
1890 // will be represented
1891 DataReader cieReader;
1892 off_t cieRemaining;
1893 status_t error = _ParseCIEHeader(currentFrameSection,
1894 info->ehFrame, unit, addressSize, context, info->cieOffset,
1895 cieAugmentation, cieReader, cieRemaining);
1896 if (error != B_OK)
1897 return error;
1898 if (cieReader.HasOverflow())
1899 return B_BAD_DATA;
1900 if (cieRemaining < 0)
1901 return B_BAD_DATA;
1903 // skip CIE ID, initial offset and range, since we already know those
1904 // from FDELookupInfo.
1905 dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1906 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1907 currentFrameSection);
1908 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
1909 currentFrameSection, true);
1911 TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
1912 "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
1913 "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
1914 info->cieOffset, info->start, info->end - info->start);
1916 context.SetLocation(location, info->start);
1917 uint32 registerCount = outputInterface->CountRegisters();
1918 error = context.Init(registerCount);
1919 if (error != B_OK)
1920 return error;
1922 error = outputInterface->InitRegisterRules(context);
1923 if (error != B_OK)
1924 return error;
1926 // process the CIE's frame info instructions
1927 cieReader = cieReader.RestrictedReader(cieRemaining);
1928 error = _ParseFrameInfoInstructions(unit, context,
1929 cieReader, cieAugmentation);
1930 if (error != B_OK)
1931 return error;
1933 // read the FDE augmentation data (if any)
1934 FDEAugmentation fdeAugmentation;
1935 error = cieAugmentation.ReadFDEData(dataReader,
1936 fdeAugmentation);
1937 if (error != B_OK) {
1938 TRACE_CFI(" failed to read FDE augmentation data!\n");
1939 return error;
1942 error = context.SaveInitialRuleSet();
1943 if (error != B_OK)
1944 return error;
1946 uint64 remaining = lengthOffset + length - dataReader.Offset();
1947 if (remaining < 0)
1948 return B_BAD_DATA;
1950 DataReader restrictedReader =
1951 dataReader.RestrictedReader(remaining);
1952 error = _ParseFrameInfoInstructions(unit, context,
1953 restrictedReader, cieAugmentation);
1954 if (error != B_OK)
1955 return error;
1957 TRACE_CFI(" found row!\n");
1959 // apply the rules of the final row
1960 // get the frameAddress first
1961 target_addr_t frameAddress;
1962 CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
1963 switch (cfaCfaRule->Type()) {
1964 case CFA_CFA_RULE_REGISTER_OFFSET:
1966 BVariant value;
1967 if (!inputInterface->GetRegisterValue(
1968 cfaCfaRule->Register(), value)
1969 || !value.IsNumber()) {
1970 return B_UNSUPPORTED;
1972 frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
1973 break;
1975 case CFA_CFA_RULE_EXPRESSION:
1977 error = EvaluateExpression(unit, addressSize,
1978 subprogramEntry,
1979 cfaCfaRule->Expression().block,
1980 cfaCfaRule->Expression().size,
1981 inputInterface, location, 0, 0, false,
1982 frameAddress);
1983 if (error != B_OK)
1984 return error;
1985 break;
1987 case CFA_CFA_RULE_UNDEFINED:
1988 default:
1989 return B_BAD_VALUE;
1992 TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress);
1994 // apply the register rules
1995 for (uint32 i = 0; i < registerCount; i++) {
1996 TRACE_CFI(" reg %" B_PRIu32 "\n", i);
1998 uint32 valueType = outputInterface->RegisterValueType(i);
1999 if (valueType == 0)
2000 continue;
2002 CfaRule* rule = context.RegisterRule(i);
2003 if (rule == NULL)
2004 continue;
2006 // apply the rule
2007 switch (rule->Type()) {
2008 case CFA_RULE_SAME_VALUE:
2010 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
2012 BVariant value;
2013 if (inputInterface->GetRegisterValue(i, value))
2014 outputInterface->SetRegisterValue(i, value);
2015 break;
2017 case CFA_RULE_LOCATION_OFFSET:
2019 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %"
2020 B_PRId64 "\n", rule->Offset());
2022 BVariant value;
2023 if (inputInterface->ReadValueFromMemory(
2024 frameAddress + rule->Offset(), valueType,
2025 value)) {
2026 outputInterface->SetRegisterValue(i, value);
2028 break;
2030 case CFA_RULE_VALUE_OFFSET:
2031 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
2033 outputInterface->SetRegisterValue(i,
2034 frameAddress + rule->Offset());
2035 break;
2036 case CFA_RULE_REGISTER:
2038 TRACE_CFI(" -> CFA_RULE_REGISTER\n");
2040 BVariant value;
2041 if (inputInterface->GetRegisterValue(
2042 rule->Register(), value)) {
2043 outputInterface->SetRegisterValue(i, value);
2045 break;
2047 case CFA_RULE_LOCATION_EXPRESSION:
2049 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
2051 target_addr_t address;
2052 error = EvaluateExpression(unit, addressSize,
2053 subprogramEntry,
2054 rule->Expression().block,
2055 rule->Expression().size,
2056 inputInterface, location, frameAddress,
2057 frameAddress, true, address);
2058 BVariant value;
2059 if (error == B_OK
2060 && inputInterface->ReadValueFromMemory(address,
2061 valueType, value)) {
2062 outputInterface->SetRegisterValue(i, value);
2064 break;
2066 case CFA_RULE_VALUE_EXPRESSION:
2068 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
2070 target_addr_t value;
2071 error = EvaluateExpression(unit, addressSize,
2072 subprogramEntry,
2073 rule->Expression().block,
2074 rule->Expression().size,
2075 inputInterface, location, frameAddress,
2076 frameAddress, true, value);
2077 if (error == B_OK)
2078 outputInterface->SetRegisterValue(i, value);
2079 break;
2081 case CFA_RULE_UNDEFINED:
2082 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
2083 default:
2084 break;
2088 _framePointer = frameAddress;
2090 return B_OK;
2094 status_t
2095 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection,
2096 bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize,
2097 CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation,
2098 DataReader& dataReader, off_t& _cieRemaining)
2100 if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size())
2101 return B_BAD_DATA;
2103 dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset,
2104 debugFrameSection->Size() - cieOffset, unit != NULL
2105 ? unit->AddressSize() : addressSize);
2107 // length
2108 bool dwarf64;
2109 uint64 length = dataReader.ReadInitialLength(dwarf64);
2110 if (length > (uint64)dataReader.BytesRemaining())
2111 return B_BAD_DATA;
2113 off_t lengthOffset = dataReader.Offset();
2115 // CIE ID/CIE pointer
2116 uint64 cieID = dwarf64
2117 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2118 if (usingEHFrameSection) {
2119 if (cieID != 0)
2120 return B_BAD_DATA;
2121 } else {
2122 if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
2123 return B_BAD_DATA;
2126 uint8 version = dataReader.Read<uint8>(0);
2127 if (version != 1) {
2128 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", "
2129 "version: %u -- unsupported\n", length, (uint64)cieOffset, version);
2130 return B_UNSUPPORTED;
2133 // read the augmentation string
2134 cieAugmentation.Init(dataReader);
2136 // in the cause of augmentation string "eh",
2137 // the exception table pointer is located immediately before the
2138 // code/data alignment values. We have no use for it so simply skip.
2139 if (strcmp(cieAugmentation.String(), "eh") == 0)
2140 dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32));
2142 context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0));
2143 context.SetDataAlignment(dataReader.ReadSignedLEB128(0));
2144 context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0));
2146 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: "
2147 "%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %"
2148 B_PRId32 ", return address reg: %" B_PRIu32 "\n", length,
2149 (uint64)cieOffset, version, cieAugmentation.String(),
2150 context.CodeAlignment(), context.DataAlignment(),
2151 context.ReturnAddressRegister());
2153 status_t error = cieAugmentation.Read(dataReader);
2154 if (error != B_OK) {
2155 TRACE_CFI(" cie: length: %" B_PRIu64 ", version: %u, augmentation: "
2156 "\"%s\" -- unsupported\n", length, version,
2157 cieAugmentation.String());
2158 return error;
2161 if (dataReader.HasOverflow())
2162 return B_BAD_DATA;
2164 _cieRemaining = length -(dataReader.Offset() - lengthOffset);
2165 if (_cieRemaining < 0)
2166 return B_BAD_DATA;
2168 return B_OK;
2172 status_t
2173 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit,
2174 CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation)
2176 while (dataReader.BytesRemaining() > 0) {
2177 TRACE_CFI(" [%2" B_PRId64 "]", dataReader.BytesRemaining());
2179 uint8 opcode = dataReader.Read<uint8>(0);
2180 if ((opcode >> 6) != 0) {
2181 uint32 operand = opcode & 0x3f;
2183 switch (opcode >> 6) {
2184 case DW_CFA_advance_loc:
2186 TRACE_CFI(" DW_CFA_advance_loc: %#" B_PRIx32 "\n",
2187 operand);
2189 target_addr_t location = context.Location()
2190 + operand * context.CodeAlignment();
2191 if (location > context.TargetLocation())
2192 return B_OK;
2193 context.SetLocation(location);
2194 break;
2196 case DW_CFA_offset:
2198 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2199 TRACE_CFI(" DW_CFA_offset: reg: %" B_PRIu32 ", offset: "
2200 "%" B_PRIu64 "\n", operand, offset);
2202 if (CfaRule* rule = context.RegisterRule(operand)) {
2203 rule->SetToLocationOffset(
2204 offset * context.DataAlignment());
2206 break;
2208 case DW_CFA_restore:
2210 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32 "\n", operand);
2212 context.RestoreRegisterRule(operand);
2213 break;
2216 } else {
2217 switch (opcode) {
2218 case DW_CFA_nop:
2220 TRACE_CFI(" DW_CFA_nop\n");
2221 break;
2223 case DW_CFA_set_loc:
2225 target_addr_t location = augmentation.ReadEncodedAddress(
2226 dataReader, fElfFile, fDebugFrameSection);
2228 TRACE_CFI(" DW_CFA_set_loc: %#" B_PRIx64 "\n", location);
2230 if (location < context.Location())
2231 return B_BAD_VALUE;
2232 if (location > context.TargetLocation())
2233 return B_OK;
2234 context.SetLocation(location);
2235 break;
2237 case DW_CFA_advance_loc1:
2239 uint32 delta = dataReader.Read<uint8>(0);
2241 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32 "\n",
2242 delta);
2244 target_addr_t location = context.Location()
2245 + delta * context.CodeAlignment();
2246 if (location > context.TargetLocation())
2247 return B_OK;
2248 context.SetLocation(location);
2249 break;
2251 case DW_CFA_advance_loc2:
2253 uint32 delta = dataReader.Read<uint16>(0);
2255 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32 "\n",
2256 delta);
2258 target_addr_t location = context.Location()
2259 + delta * context.CodeAlignment();
2260 if (location > context.TargetLocation())
2261 return B_OK;
2262 context.SetLocation(location);
2263 break;
2265 case DW_CFA_advance_loc4:
2267 uint32 delta = dataReader.Read<uint32>(0);
2269 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32 "\n",
2270 delta);
2272 target_addr_t location = context.Location()
2273 + delta * context.CodeAlignment();
2274 if (location > context.TargetLocation())
2275 return B_OK;
2276 context.SetLocation(location);
2277 break;
2279 case DW_CFA_offset_extended:
2281 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2282 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2284 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2285 "offset: %" B_PRIu64 "\n", reg, offset);
2287 if (CfaRule* rule = context.RegisterRule(reg)) {
2288 rule->SetToLocationOffset(
2289 offset * context.DataAlignment());
2291 break;
2293 case DW_CFA_restore_extended:
2295 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2297 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32 "\n",
2298 reg);
2300 context.RestoreRegisterRule(reg);
2301 break;
2303 case DW_CFA_undefined:
2305 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2307 TRACE_CFI(" DW_CFA_undefined: %" B_PRIu32 "\n", reg);
2309 if (CfaRule* rule = context.RegisterRule(reg))
2310 rule->SetToUndefined();
2311 break;
2313 case DW_CFA_same_value:
2315 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2317 TRACE_CFI(" DW_CFA_same_value: %" B_PRIu32 "\n", reg);
2319 if (CfaRule* rule = context.RegisterRule(reg))
2320 rule->SetToSameValue();
2321 break;
2323 case DW_CFA_register:
2325 uint32 reg1 = dataReader.ReadUnsignedLEB128(0);
2326 uint32 reg2 = dataReader.ReadUnsignedLEB128(0);
2328 TRACE_CFI(" DW_CFA_register: reg1: %" B_PRIu32 ", reg2: "
2329 "%" B_PRIu32 "\n", reg1, reg2);
2331 if (CfaRule* rule = context.RegisterRule(reg1))
2332 rule->SetToValueOffset(reg2);
2333 break;
2335 case DW_CFA_remember_state:
2337 TRACE_CFI(" DW_CFA_remember_state\n");
2339 status_t error = context.PushRuleSet();
2340 if (error != B_OK)
2341 return error;
2342 break;
2344 case DW_CFA_restore_state:
2346 TRACE_CFI(" DW_CFA_restore_state\n");
2348 status_t error = context.PopRuleSet();
2349 if (error != B_OK)
2350 return error;
2351 break;
2353 case DW_CFA_def_cfa:
2355 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2356 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2358 TRACE_CFI(" DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: "
2359 "%" B_PRIu64 "\n", reg, offset);
2361 context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset);
2362 break;
2364 case DW_CFA_def_cfa_register:
2366 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2368 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32 "\n",
2369 reg);
2371 if (context.GetCfaCfaRule()->Type()
2372 != CFA_CFA_RULE_REGISTER_OFFSET) {
2373 return B_BAD_DATA;
2375 context.GetCfaCfaRule()->SetRegister(reg);
2376 break;
2378 case DW_CFA_def_cfa_offset:
2380 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2382 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64 "\n",
2383 offset);
2385 if (context.GetCfaCfaRule()->Type()
2386 != CFA_CFA_RULE_REGISTER_OFFSET) {
2387 return B_BAD_DATA;
2389 context.GetCfaCfaRule()->SetOffset(offset);
2390 break;
2392 case DW_CFA_def_cfa_expression:
2394 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2395 uint8* block = (uint8*)dataReader.Data();
2396 dataReader.Skip(blockLength);
2398 TRACE_CFI(" DW_CFA_def_cfa_expression: %p, %" B_PRIu64
2399 "\n", block, blockLength);
2401 context.GetCfaCfaRule()->SetToExpression(block,
2402 blockLength);
2403 break;
2405 case DW_CFA_expression:
2407 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2408 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2409 uint8* block = (uint8*)dataReader.Data();
2410 dataReader.Skip(blockLength);
2412 TRACE_CFI(" DW_CFA_expression: reg: %" B_PRIu32 ", "
2413 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2415 if (CfaRule* rule = context.RegisterRule(reg))
2416 rule->SetToLocationExpression(block, blockLength);
2417 break;
2419 case DW_CFA_offset_extended_sf:
2421 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2422 int64 offset = dataReader.ReadSignedLEB128(0);
2424 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2425 "offset: %" B_PRId64 "\n", reg, offset);
2427 if (CfaRule* rule = context.RegisterRule(reg)) {
2428 rule->SetToLocationOffset(
2429 offset * (int32)context.DataAlignment());
2431 break;
2433 case DW_CFA_def_cfa_sf:
2435 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2436 int64 offset = dataReader.ReadSignedLEB128(0);
2438 TRACE_CFI(" DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", "
2439 "offset: %" B_PRId64 "\n", reg, offset);
2441 context.GetCfaCfaRule()->SetToRegisterOffset(reg,
2442 offset * (int32)context.DataAlignment());
2443 break;
2445 case DW_CFA_def_cfa_offset_sf:
2447 int64 offset = dataReader.ReadSignedLEB128(0);
2449 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRId64 "\n",
2450 offset);
2452 if (context.GetCfaCfaRule()->Type()
2453 != CFA_CFA_RULE_REGISTER_OFFSET) {
2454 return B_BAD_DATA;
2456 context.GetCfaCfaRule()->SetOffset(
2457 offset * (int32)context.DataAlignment());
2458 break;
2460 case DW_CFA_val_offset:
2462 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2463 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2465 TRACE_CFI(" DW_CFA_val_offset: reg: %" B_PRIu32 ", "
2466 "offset: %" B_PRIu64 "\n", reg, offset);
2468 if (CfaRule* rule = context.RegisterRule(reg)) {
2469 rule->SetToValueOffset(
2470 offset * context.DataAlignment());
2472 break;
2474 case DW_CFA_val_offset_sf:
2476 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2477 int64 offset = dataReader.ReadSignedLEB128(0);
2479 TRACE_CFI(" DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", "
2480 "offset: %" B_PRId64 "\n", reg, offset);
2482 if (CfaRule* rule = context.RegisterRule(reg)) {
2483 rule->SetToValueOffset(
2484 offset * (int32)context.DataAlignment());
2486 break;
2488 case DW_CFA_val_expression:
2490 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2491 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2492 uint8* block = (uint8*)dataReader.Data();
2493 dataReader.Skip(blockLength);
2495 TRACE_CFI(" DW_CFA_val_expression: reg: %" B_PRIu32 ", "
2496 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2498 if (CfaRule* rule = context.RegisterRule(reg))
2499 rule->SetToValueExpression(block, blockLength);
2500 break;
2503 // extensions
2504 case DW_CFA_MIPS_advance_loc8:
2506 uint64 delta = dataReader.Read<uint64>(0);
2508 TRACE_CFI(" DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n",
2509 delta);
2511 target_addr_t location = context.Location()
2512 + delta * context.CodeAlignment();
2513 if (location > context.TargetLocation())
2514 return B_OK;
2515 context.SetLocation(location);
2516 break;
2518 case DW_CFA_GNU_window_save:
2520 // SPARC specific, no args
2521 TRACE_CFI(" DW_CFA_GNU_window_save\n");
2523 // TODO: Implement once we have SPARC support!
2524 break;
2526 case DW_CFA_GNU_args_size:
2528 // Updates the total size of arguments on the stack.
2529 TRACE_CFI_ONLY(uint64 size =)
2530 dataReader.ReadUnsignedLEB128(0);
2532 TRACE_CFI(" DW_CFA_GNU_args_size: %" B_PRIu64 "\n",
2533 size);
2534 // TODO: Implement!
2535 break;
2537 case DW_CFA_GNU_negative_offset_extended:
2539 // obsolete
2540 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2541 int64 offset = dataReader.ReadSignedLEB128(0);
2543 TRACE_CFI(" DW_CFA_GNU_negative_offset_extended: "
2544 "reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg,
2545 offset);
2547 if (CfaRule* rule = context.RegisterRule(reg)) {
2548 rule->SetToLocationOffset(
2549 offset * (int32)context.DataAlignment());
2551 break;
2554 default:
2555 TRACE_CFI(" unknown opcode %u!\n", opcode);
2556 return B_BAD_DATA;
2561 return B_OK;
2565 status_t
2566 DwarfFile::_ParsePublicTypesInfo()
2568 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n");
2569 if (fDebugPublicTypesSection == NULL) {
2570 TRACE_PUBTYPES(" -> no public types section\n");
2571 return B_ENTRY_NOT_FOUND;
2574 DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(),
2575 fDebugPublicTypesSection->Size(), 4);
2576 // address size doesn't matter at this point
2578 while (dataReader.BytesRemaining() > 0) {
2579 bool dwarf64;
2580 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
2582 off_t unitLengthOffset = dataReader.Offset();
2583 // the unitLength starts here
2585 if (dataReader.HasOverflow())
2586 return B_BAD_DATA;
2588 if (unitLengthOffset + unitLength
2589 > (uint64)fDebugPublicTypesSection->Size()) {
2590 WARNING("Invalid public types set unit length.\n");
2591 break;
2594 DataReader unitDataReader(dataReader.Data(), unitLength, 4);
2595 // address size doesn't matter
2596 _ParsePublicTypesInfo(unitDataReader, dwarf64);
2598 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
2601 return B_OK;
2605 status_t
2606 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64)
2608 int version = dataReader.Read<uint16>(0);
2609 if (version != 2) {
2610 TRACE_PUBTYPES(" pubtypes version %d unsupported\n", version);
2611 return B_UNSUPPORTED;
2614 TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64
2615 ? dataReader.Read<uint64>(0)
2616 : (uint64)dataReader.Read<uint32>(0);
2617 TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64
2618 ? dataReader.Read<uint64>(0)
2619 : (uint64)dataReader.Read<uint32>(0);
2621 if (dataReader.HasOverflow())
2622 return B_BAD_DATA;
2624 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
2625 "info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset,
2626 debugInfoSize);
2628 while (dataReader.BytesRemaining() > 0) {
2629 off_t entryOffset = dwarf64
2630 ? dataReader.Read<uint64>(0)
2631 : (uint64)dataReader.Read<uint32>(0);
2632 if (entryOffset == 0)
2633 return B_OK;
2635 TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString();
2637 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset);
2640 return B_OK;
2644 status_t
2645 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
2647 // check, whether we've already loaded it
2648 for (AbbreviationTableList::Iterator it
2649 = fAbbreviationTables.GetIterator();
2650 AbbreviationTable* table = it.Next();) {
2651 if (offset == table->Offset()) {
2652 _table = table;
2653 return B_OK;
2657 // create a new table
2658 AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset);
2659 if (table == NULL)
2660 return B_NO_MEMORY;
2662 status_t error = table->Init(fDebugAbbrevSection->Data(),
2663 fDebugAbbrevSection->Size());
2664 if (error != B_OK) {
2665 delete table;
2666 return error;
2669 fAbbreviationTables.Add(table);
2670 _table = table;
2671 return B_OK;
2675 DebugInfoEntry*
2676 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
2677 uint8 refType) const
2679 switch (refType) {
2680 case dwarf_reference_type_local:
2681 return unit->EntryForOffset(offset);
2682 break;
2683 case dwarf_reference_type_global:
2685 CompilationUnit* unit = _GetContainingCompilationUnit(offset);
2686 if (unit == NULL)
2687 break;
2689 offset -= unit->HeaderOffset();
2690 DebugInfoEntry* entry = unit->EntryForOffset(offset);
2691 if (entry != NULL)
2692 return entry;
2693 break;
2695 case dwarf_reference_type_signature:
2697 TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset);
2698 TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
2699 if (entry != NULL && entry->unit != NULL)
2700 return entry->unit->TypeEntry();
2701 break;
2705 return NULL;
2709 status_t
2710 DwarfFile::_GetLocationExpression(CompilationUnit* unit,
2711 const LocationDescription* location, target_addr_t instructionPointer,
2712 const void*& _expression, off_t& _length) const
2714 if (!location->IsValid())
2715 return B_BAD_VALUE;
2717 if (location->IsExpression()) {
2718 _expression = location->expression.data;
2719 _length = location->expression.length;
2720 return B_OK;
2723 if (location->IsLocationList() && instructionPointer != 0) {
2724 return _FindLocationExpression(unit, location->listOffset,
2725 instructionPointer, _expression, _length);
2728 return B_BAD_VALUE;
2732 status_t
2733 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset,
2734 target_addr_t address, const void*& _expression, off_t& _length) const
2736 if (unit == NULL)
2737 return B_BAD_VALUE;
2739 if (fDebugLocationSection == NULL)
2740 return B_ENTRY_NOT_FOUND;
2742 if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size())
2743 return B_BAD_DATA;
2745 target_addr_t baseAddress = unit->AddressRangeBase();
2746 target_addr_t maxAddress = unit->MaxAddress();
2748 DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset,
2749 fDebugLocationSection->Size() - offset, unit->AddressSize());
2750 while (true) {
2751 target_addr_t start = dataReader.ReadAddress(0);
2752 target_addr_t end = dataReader.ReadAddress(0);
2753 if (dataReader.HasOverflow())
2754 return B_BAD_DATA;
2756 if (start == 0 && end == 0)
2757 return B_ENTRY_NOT_FOUND;
2759 if (start == maxAddress) {
2760 baseAddress = end;
2761 continue;
2764 uint16 expressionLength = dataReader.Read<uint16>(0);
2765 const void* expression = dataReader.Data();
2766 if (!dataReader.Skip(expressionLength))
2767 return B_BAD_DATA;
2769 if (start == end)
2770 continue;
2772 start += baseAddress;
2773 end += baseAddress;
2775 if (address >= start && address < end) {
2776 _expression = expression;
2777 _length = expressionLength;
2778 return B_OK;
2784 status_t
2785 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName,
2786 const char* locatedFilePath)
2788 ElfFile* debugInfoFile = fElfFile;
2789 ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink");
2790 if (debugLinkSection != NULL) {
2791 AutoSectionPutter putter(fElfFile, debugLinkSection);
2793 // the file specifies a debug link, look at its target instead
2794 // for debug information.
2795 // Format: null-terminated filename, as many 0 padding bytes as
2796 // needed to reach the next 32-bit address boundary, followed
2797 // by a 32-bit CRC
2799 BString debugPath;
2800 if (locatedFilePath)
2801 debugPath = locatedFilePath;
2802 else {
2803 status_t result = _GetDebugInfoPath(
2804 (const char*)debugLinkSection->Data(),
2805 _requiredExternalFileName);
2806 if (result != B_OK)
2807 return result;
2808 debugPath = _requiredExternalFileName;
2811 if (fAlternateName != NULL)
2812 free(fAlternateName);
2814 fAlternateName = strdup(debugPath.String());
2816 if (fAlternateName == NULL)
2817 return B_NO_MEMORY;
2820 // TODO: validate CRC
2821 int32 debugCRC = *(int32*)((char*)debugLinkSection->Data()
2822 + debugLinkSection->Size() - sizeof(int32));
2824 if (fAlternateElfFile == NULL) {
2825 fAlternateElfFile = new(std::nothrow) ElfFile;
2826 if (fAlternateElfFile == NULL)
2827 return B_NO_MEMORY;
2830 status_t result = fAlternateElfFile->Init(fAlternateName);
2831 if (result != B_OK)
2832 return result;
2834 debugInfoFile = fAlternateElfFile;
2837 // get the interesting sections
2838 fDebugInfoSection = debugInfoFile->GetSection(".debug_info");
2839 fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev");
2840 if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
2841 WARNING("DwarfManager::File::Load(\"%s\"): no "
2842 ".debug_info or .debug_abbrev.\n", fName);
2844 // if we at least have an EH frame, use that for stack unwinding
2845 // if nothing else.
2846 fEHFrameSection = fElfFile->GetSection(".eh_frame");
2847 if (fEHFrameSection == NULL)
2848 return B_ERROR;
2851 return B_OK;
2855 status_t
2856 DwarfFile::_GetDebugInfoPath(const char* debugFileName,
2857 BString& _infoPath) const
2859 // first, see if we have a relative match to our local directory
2860 BPath basePath;
2861 status_t result = basePath.SetTo(fName);
2862 if (result != B_OK)
2863 return result;
2864 basePath.GetParent(&basePath);
2865 if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(),
2866 "add-ons") == 0) {
2867 _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(),
2868 debugFileName);
2869 } else
2870 _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName);
2872 BEntry entry(_infoPath.String());
2873 result = entry.InitCheck();
2874 if (result != B_OK && result != B_ENTRY_NOT_FOUND)
2875 return result;
2876 if (entry.Exists())
2877 return B_OK;
2879 // If the above search failed, check if our image is located in any
2880 // of the system installation paths, and attempt to locate the debug info
2881 // file in the corresponding well-known location
2882 BString pathSuffix;
2883 pathSuffix.SetToFormat("debug/%s", debugFileName);
2885 BPathFinder finder(fName);
2886 result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY,
2887 pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath);
2888 if (result == B_OK) {
2889 _infoPath = basePath.Path();
2890 return B_OK;
2891 } else {
2892 // if we failed to find a match, then it's up to the user to
2893 // locate it. As such, return the external info file name
2894 // for user interface purposes.
2895 _infoPath.SetTo(debugFileName);
2898 return B_ENTRY_NOT_FOUND;
2902 TypeUnitTableEntry*
2903 DwarfFile::_GetTypeUnit(uint64 signature) const
2905 return fTypeUnits.Lookup(signature);
2909 CompilationUnit*
2910 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
2912 if (fCompilationUnits.IsEmpty())
2913 return NULL;
2915 // binary search
2916 int lower = 0;
2917 int upper = fCompilationUnits.CountItems() - 1;
2918 while (lower < upper) {
2919 int mid = (lower + upper + 1) / 2;
2920 if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr)
2921 upper = mid - 1;
2922 else
2923 lower = mid;
2926 CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
2927 return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
2931 DwarfFile::FDELookupInfo*
2932 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
2934 FDELookupInfo* info = NULL;
2935 if (fDebugFrameSection != NULL) {
2936 info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
2937 if (info != NULL)
2938 return info;
2941 return _GetContainingFDEInfo(offset, fEHFrameInfos);
2945 DwarfFile::FDELookupInfo*
2946 DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
2947 const FDEInfoList& infoList) const
2949 // binary search
2950 int lower = 0;
2951 int upper = infoList.CountItems() - 1;
2952 if (upper < 0)
2953 return NULL;
2955 while (lower < upper) {
2956 int mid = (lower + upper + 1) / 2;
2957 if (offset < infoList.ItemAt(mid)->start)
2958 upper = mid - 1;
2959 else
2960 lower = mid;
2963 FDELookupInfo* info = infoList.ItemAt(lower);
2964 return info->ContainsAddress(offset) ? info : NULL;