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.
13 #include <AutoDeleter.h>
15 #include <FindDirectory.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"
29 #include "TargetAddressRangeList.h"
34 // #pragma mark - AutoSectionPutter
37 class AutoSectionPutter
{
39 AutoSectionPutter(ElfFile
* elfFile
, ElfSection
* elfSection
)
42 fElfSection(elfSection
)
48 if (fElfSection
!= NULL
)
49 fElfFile
->PutSection(fElfSection
);
54 ElfSection
* fElfSection
;
58 // #pragma mark - ExpressionEvaluationContext
61 struct DwarfFile::ExpressionEvaluationContext
62 : DwarfExpressionEvaluationContext
{
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
,
75 fSubprogramEntry(subprogramEntry
),
76 fInstructionPointer(instructionPointer
),
77 fObjectPointer(objectPointer
),
78 fHasObjectPointer(hasObjectPointer
),
79 fFramePointer(framePointer
),
81 fFrameBaseEvaluated(false)
85 virtual bool GetObjectAddress(target_addr_t
& _address
)
87 if (!fHasObjectPointer
)
90 _address
= fObjectPointer
;
94 virtual bool GetFrameAddress(target_addr_t
& _address
)
96 if (fFramePointer
== 0)
99 _address
= fFramePointer
;
103 virtual bool GetFrameBaseAddress(target_addr_t
& _address
)
105 if (fFrameBaseEvaluated
) {
106 if (fFrameBasePointer
== 0)
109 _address
= fFrameBasePointer
;
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
)
119 const LocationDescription
* location
= fSubprogramEntry
->FrameBase();
120 if (!location
->IsValid())
123 // get the expression
124 const void* expression
;
125 off_t expressionLength
;
126 status_t error
= fFile
->_GetLocationExpression(fUnit
, location
,
127 fInstructionPointer
, expression
, expressionLength
);
131 // evaluate the expression
132 DwarfExpressionEvaluator
evaluator(this);
133 error
= evaluator
.Evaluate(expression
, expressionLength
,
138 TRACE_EXPR(" -> frame base: %" B_PRIx64
"\n", fFrameBasePointer
);
140 _address
= fFrameBasePointer
;
144 virtual bool GetTLSAddress(target_addr_t localAddress
,
145 target_addr_t
& _address
)
151 virtual status_t
GetCallTarget(uint64 offset
, uint8 refType
,
152 const void*& _block
, off_t
& _size
)
155 DebugInfoEntry
* entry
= fFile
->_ResolveReference(fUnit
, offset
, refType
);
157 return B_ENTRY_NOT_FOUND
;
159 // get the location description
160 LocationDescription
* location
= entry
->GetLocationDescription();
161 if (location
== NULL
|| !location
->IsValid()) {
167 // get the expression
168 return fFile
->_GetLocationExpression(fUnit
, location
,
169 fInstructionPointer
, _block
, _size
);
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
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
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
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
{
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
)
248 fString
= dataReader
.ReadString();
251 status_t
Read(DataReader
& dataReader
)
253 if (fString
== NULL
|| *fString
== '\0')
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') {
271 fFlags
|= CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA
;
272 dataReader
.Read
<char>(0);
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;
286 fFlags
|= CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT
;
287 fAddressEncoding
= dataReader
.Read
<char>(0);
291 WARNING("Encountered unsupported augmentation '%c' "
292 " while parsing CIE augmentation string %s\n",
294 return B_UNSUPPORTED
;
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
);
312 if (strcmp(fString
, "eh") == 0)
315 // something we can't handle
316 return B_UNSUPPORTED
;
319 status_t
ReadFDEData(DataReader
& dataReader
,
320 FDEAugmentation
& fdeAugmentation
)
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())
339 const char* String() 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, ");
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, ");
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, ");
377 // -- note: type indirect is currently not generated
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
,
395 switch (fAddressEncoding
& 0x0f) {
396 case CFI_ADDRESS_FORMAT_ABSOLUTE
:
397 address
+= reader
.ReadAddress(0);
398 TRACE_CFI(" target address: %" B_PRId64
"\n", address
);
400 case CFI_ADDRESS_FORMAT_UNSIGNED_LEB128
:
401 address
+= reader
.ReadUnsignedLEB128(0);
402 TRACE_CFI(" unsigned LEB128: %" B_PRId64
"\n", address
);
404 case CFI_ADDRESS_FORMAT_SIGNED_LEB128
:
405 address
+= reader
.ReadSignedLEB128(0);
406 TRACE_CFI(" signed LEB128: %" B_PRId64
"\n", address
);
408 case CFI_ADDRESS_FORMAT_UNSIGNED_16
:
409 address
+= reader
.Read
<uint16
>(0);
410 TRACE_CFI(" unsigned 16-bit: %" B_PRId64
"\n", address
);
412 case CFI_ADDRESS_FORMAT_SIGNED_16
:
413 address
+= reader
.Read
<int16
>(0);
414 TRACE_CFI(" signed 16-bit: %" B_PRId64
"\n", address
);
416 case CFI_ADDRESS_FORMAT_UNSIGNED_32
:
417 address
+= reader
.Read
<uint32
>(0);
418 TRACE_CFI(" unsigned 32-bit: %" B_PRId64
"\n", address
);
420 case CFI_ADDRESS_FORMAT_SIGNED_32
:
421 address
+= reader
.Read
<int32
>(0);
422 TRACE_CFI(" signed 32-bit: %" B_PRId64
"\n", address
);
424 case CFI_ADDRESS_FORMAT_UNSIGNED_64
:
425 address
+= reader
.Read
<uint64
>(0);
426 TRACE_CFI(" unsigned 64-bit: %" B_PRId64
"\n", address
);
428 case CFI_ADDRESS_FORMAT_SIGNED_64
:
429 address
+= reader
.Read
<int64
>(0);
430 TRACE_CFI(" signed 64-bit: %" B_PRId64
"\n", address
);
441 int8 fAddressEncoding
;
445 // #pragma mark - FDELookupInfo
448 struct DwarfFile::FDELookupInfo
{
450 FDELookupInfo(target_addr_t start
, target_addr_t end
,
451 uint64 fdeOffset
, uint64 cieOffset
, bool ehFrame
)
455 fdeOffset(fdeOffset
),
456 cieOffset(cieOffset
),
461 static int CompareFDEInfos(const FDELookupInfo
* a
, const FDELookupInfo
* b
)
463 if (a
->start
< b
->start
)
465 else if (a
->start
> b
->start
)
471 inline bool ContainsAddress(target_addr_t address
) const
473 return address
>= start
&& address
< end
;
484 // #pragma mark - DwarfFile
487 DwarfFile::DwarfFile()
490 fAlternateName(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),
505 fDebugFrameInfos(100, true),
506 fEHFrameInfos(100, true),
507 fTypesSectionRequired(false),
509 fItaniumEHFrameFormat(false),
515 DwarfFile::~DwarfFile()
517 while (AbbreviationTable
* table
= fAbbreviationTables
.RemoveHead())
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
);
534 delete fAlternateElfFile
;
537 TypeUnitTableEntry
* entry
= fTypeUnits
.Clear(true);
538 while (entry
!= NULL
) {
539 TypeUnitTableEntry
* nextEntry
= entry
->next
;
545 free(fAlternateName
);
550 DwarfFile::StartLoading(const char* fileName
, BString
& _requiredExternalFile
)
552 fName
= strdup(fileName
);
556 status_t error
= fTypeUnits
.Init();
561 fElfFile
= new(std::nothrow
) ElfFile
;
562 if (fElfFile
== NULL
)
565 error
= fElfFile
->Init(fileName
);
569 return _LocateDebugInfo(_requiredExternalFile
);
574 DwarfFile::Load(uint8 addressSize
, const BString
& externalInfoFilePath
)
576 status_t error
= B_OK
;
577 if (fDebugInfoSection
== NULL
) {
579 error
= _LocateDebugInfo(path
, externalInfoFilePath
.IsEmpty()
580 ? NULL
: externalInfoFilePath
.String());
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,
601 // .eh_frame doesn't appear to get copied into separate debug
602 // info files properly, therefore always use it off the main
604 if (fEHFrameSection
== NULL
)
605 fEHFrameSection
= fElfFile
->GetSection(".eh_frame");
607 if (fEHFrameSection
!= NULL
) {
608 error
= _ParseFrameSection(fEHFrameSection
, addressSize
, true,
614 fDebugLocationSection
= debugInfoFile
->GetSection(".debug_loc");
615 fDebugPublicTypesSection
= debugInfoFile
->GetSection(".debug_pubtypes");
617 if (fDebugInfoSection
== NULL
) {
622 error
= _ParseDebugInfoSection();
626 if (fTypesSectionRequired
) {
627 fDebugTypesSection
= debugInfoFile
->GetSection(".debug_types");
628 if (fDebugTypesSection
== NULL
) {
629 WARNING(".debug_types section required but missing.\n");
632 error
= _ParseTypesSection();
642 DwarfFile::FinishLoading()
646 if (fFinishError
!= B_OK
)
650 for (TypeUnitTable::Iterator it
= fTypeUnits
.GetIterator();
651 TypeUnitTableEntry
* entry
= it
.Next();) {
652 error
= _FinishUnit(entry
->unit
);
654 return fFinishError
= error
;
657 for (int32 i
= 0; CompilationUnit
* unit
= fCompilationUnits
.ItemAt(i
);
659 error
= _FinishUnit(unit
);
661 return fFinishError
= error
;
664 _ParsePublicTypesInfo();
672 DwarfFile::CountCompilationUnits() const
674 return fCompilationUnits
.CountItems();
679 DwarfFile::CompilationUnitAt(int32 index
) const
681 return fCompilationUnits
.ItemAt(index
);
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
)
698 // find the compilation unit
699 for (int32 i
= 0; CompilationUnit
* unit
= fCompilationUnits
.ItemAt(i
);
701 if (unit
->UnitEntry() == unitEntry
)
709 TargetAddressRangeList
*
710 DwarfFile::ResolveRangeList(CompilationUnit
* unit
, uint64 offset
) const
712 if (unit
== NULL
|| fDebugRangesSection
== NULL
)
715 if (offset
>= (uint64
)fDebugRangesSection
->Size())
718 TargetAddressRangeList
* ranges
= new(std::nothrow
) TargetAddressRangeList
;
719 if (ranges
== NULL
) {
720 ERROR("Out of memory.\n");
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());
731 target_addr_t start
= dataReader
.ReadAddress(0);
732 target_addr_t end
= dataReader
.ReadAddress(0);
733 if (dataReader
.HasOverflow())
736 if (start
== 0 && end
== 0)
738 if (start
== maxAddress
) {
745 if (!ranges
->AddRange(baseAddress
+ start
, end
- start
)) {
746 ERROR("Out of memory.\n");
751 return rangesReference
.Detach();
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
);
763 return B_ENTRY_NOT_FOUND
;
765 return _UnwindCallFrame(unit
, addressSize
, subprogramEntry
, location
, info
,
766 inputInterface
, outputInterface
, _framePointer
);
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,
780 DwarfExpressionEvaluator
evaluator(&context
);
782 if (pushValue
&& evaluator
.Push(valueToPush
) != B_OK
)
785 return evaluator
.Evaluate(expression
, expressionLength
, _result
);
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
);
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
,
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
,
822 if (!value
->IsValid())
825 switch (value
->attributeClass
) {
826 case ATTRIBUTE_CLASS_CONSTANT
:
827 _result
.SetTo(value
->constant
);
829 case ATTRIBUTE_CLASS_STRING
:
830 _result
.SetTo(value
->string
);
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,
842 _result
.SetTo(result
);
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())
865 switch (value
->attributeClass
) {
866 case ATTRIBUTE_CLASS_CONSTANT
:
867 _result
.SetTo(value
->constant
);
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
;
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();
895 case DW_TAG_enumerator
:
896 constantValue
= dynamic_cast<DIEEnumerator
*>(entry
)
898 if (DIEEnumerationType
* enumerationType
899 = dynamic_cast<DIEEnumerationType
*>(
901 type
= enumerationType
->GetType();
904 case DW_TAG_formal_parameter
:
906 DIEFormalParameter
* parameterEntry
907 = dynamic_cast<DIEFormalParameter
*>(entry
);
908 constantValue
= parameterEntry
->ConstValue();
909 type
= parameterEntry
->GetType();
912 case DW_TAG_template_value_parameter
:
914 DIETemplateValueParameter
* parameterEntry
915 = dynamic_cast<DIETemplateValueParameter
*>(entry
);
916 constantValue
= parameterEntry
->ConstValue();
917 type
= parameterEntry
->GetType();
920 case DW_TAG_variable
:
922 DIEVariable
* variableEntry
923 = dynamic_cast<DIEVariable
*>(entry
);
924 constantValue
= variableEntry
->ConstValue();
925 type
= variableEntry
->GetType();
932 if (constantValue
== NULL
|| !constantValue
->IsValid())
935 status_t error
= EvaluateConstantValue(unit
, addressSize
,
936 subprogramEntry
, constantValue
, targetInterface
,
937 instructionPointer
, framePointer
, _result
);
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,
955 _result
.SetTo(result
);
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();
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
);
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 "
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",
1009 if (addressSize
!= 4 && addressSize
!= 8) {
1010 WARNING("\"%s\": Unsupported address size: %d\n", fName
,
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
)) {
1028 // parse the debug info for the unit
1029 status_t error
= _ParseCompilationUnit(unit
);
1033 dataReader
.SeekAbsolute(unitLengthOffset
+ unitLength
);
1041 DwarfFile::_ParseTypesSection()
1043 DataReader
dataReader(fDebugTypesSection
->Data(),
1044 fDebugTypesSection
->Size(), 4);
1045 while (dataReader
.HasData()) {
1046 off_t unitHeaderOffset
= dataReader
.Offset();
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",
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
);
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
);
1089 WARNING("\"%s\": Unsupported type unit version: %d\n",
1094 if (addressSize
!= 4 && addressSize
!= 8) {
1095 WARNING("\"%s\": Unsupported address size: %d\n", fName
,
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
);
1108 // parse the debug info for the unit
1109 status_t error
= _ParseTypeUnit(unit
);
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
1116 if (fTypeUnits
.Lookup(signature
) == NULL
) {
1117 TypeUnitTableEntry
* entry
= new(std::nothrow
)
1118 TypeUnitTableEntry(signature
, unit
);
1122 fTypeUnits
.Insert(entry
);
1125 dataReader
.SeekAbsolute(unitLengthOffset
+ unitLength
);
1133 DwarfFile::_ParseFrameSection(ElfSection
* section
, uint8 addressSize
,
1134 bool ehFrame
, FDEInfoList
& infos
)
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) {
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())
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.
1167 ? cieID
== 0xffffffffffffffffULL
1168 : cieID
== 0xffffffff)) {
1169 // this is a CIE -- skip it
1172 uint64 initialLocationOffset
= dataReader
.Offset();
1173 // In .eh_frame the CIE offset is a relative back offset.
1175 if (cieID
> (uint64
)lengthOffset
) {
1176 TRACE_CFI("Invalid CIE offset: %" B_PRIu64
", max "
1177 "possible: %" B_PRIu64
"\n", cieID
, lengthOffset
);
1180 // convert to a section relative offset
1181 cieID
= lengthOffset
- cieID
;
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
;
1192 status_t error
= _ParseCIEHeader(section
, ehFrame
, NULL
,
1193 addressSize
, context
, cieID
, cieAugmentation
, cieReader
,
1197 if (cieReader
.HasOverflow())
1199 if (cieRemaining
< 0)
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())
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
,
1221 FDELookupInfo
* info
= new(std::nothrow
)FDELookupInfo(
1222 initialLocation
, initialLocation
+ addressRange
- 1,
1223 entryOffset
, cieID
, ehFrame
);
1227 ObjectDeleter
<FDELookupInfo
> infoDeleter(info
);
1228 if (!infos
.BinaryInsert(info
, FDELookupInfo::CompareFDEInfos
))
1231 infoDeleter
.Detach();
1235 dataReader
.SeekAbsolute(lengthOffset
+ length
);
1243 DwarfFile::_ParseCompilationUnit(CompilationUnit
* unit
)
1245 AbbreviationTable
* abbreviationTable
;
1246 status_t error
= _GetAbbreviationTable(unit
->AbbreviationOffset(),
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
,
1264 DIECompileUnitBase
* unitEntry
= dynamic_cast<DIECompileUnitBase
*>(entry
);
1265 if (unitEntry
== NULL
) {
1266 WARNING("No compilation unit entry in .debug_info section.\n");
1270 unit
->SetUnitEntry(unitEntry
);
1273 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF
"\n",
1274 dataReader
.BytesRemaining());
1275 if (dataReader
.HasData()) {
1277 while (dataReader
.HasData())
1278 TRACE_DIE("%02x", dataReader
.Read
<uint8
>(0));
1287 DwarfFile::_ParseTypeUnit(TypeUnit
* unit
)
1289 AbbreviationTable
* abbreviationTable
;
1290 status_t error
= _GetAbbreviationTable(unit
->AbbreviationOffset(),
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
,
1308 DIETypeUnit
* unitEntry
= dynamic_cast<DIETypeUnit
*>(entry
);
1309 if (unitEntry
== NULL
) {
1310 WARNING("No type unit entry in .debug_types section.\n");
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());
1321 unit
->SetTypeEntry(typeEntry
);
1324 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF
"\n",
1325 dataReader
.BytesRemaining());
1326 if (dataReader
.HasData()) {
1328 while (dataReader
.HasData())
1329 TRACE_DIE("%02x", dataReader
.Read
<uint8
>(0));
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);
1347 if (dataReader
.HasOverflow()) {
1348 WARNING("Unexpected end of .debug_info section.\n");
1352 _endOfEntryList
= true;
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
);
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
);
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
);
1384 // parse the attributes (supply NULL entry to avoid adding them yet)
1385 error
= _ParseEntryAttributes(dataReader
, unit
, NULL
, abbreviationEntry
);
1389 // parse children, if the entry has any
1390 if (abbreviationEntry
.HasChildren()) {
1392 DebugInfoEntry
* childEntry
;
1393 bool endOfEntryList
;
1394 status_t error
= _ParseDebugInfoEntry(dataReader
,
1395 unit
, abbreviationTable
, childEntry
, endOfEntryList
, level
+ 1);
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
) {
1407 TRACE_DIE("%*s -> child unhandled\n", level
* 2, "");
1410 if (error
!= B_OK
) {
1423 entryDeleter
.Detach();
1425 _endOfEntryList
= false;
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
++) {
1452 DebugInfoEntry
* entry
;
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");
1475 // parse the attributes -- this time pass the entry, so that the
1476 // attribute get set on it
1477 error
= _ParseEntryAttributes(dataReader
, unit
, entry
,
1482 // initialization after setting the attributes
1483 error
= entry
->InitAfterAttributes(entryInitInfo
);
1484 if (error
!= B_OK
) {
1485 WARNING("Init after attributes failed!\n");
1490 // set the compilation unit's source language
1491 unit
->SetSourceLanguage(entryInitInfo
.languageInfo
);
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()
1506 if (!compilationUnit
->AddDirectory(compilationDir
!= NULL
1507 ? compilationDir
: ".")) {
1511 // parse line info header
1512 if (fDebugLineSection
!= NULL
)
1513 _ParseLineInfo(compilationUnit
);
1520 DwarfFile::_ParseEntryAttributes(DataReader
& dataReader
,
1521 BaseUnit
* unit
, DebugInfoEntry
* entry
, AbbreviationEntry
& abbreviationEntry
)
1523 uint32 attributeName
;
1524 uint32 attributeForm
;
1525 while (abbreviationEntry
.GetNextAttribute(attributeName
,
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
1541 off_t blockLength
= 0;
1542 off_t valueOffset
= dataReader
.Offset() + unit
->ContentOffset();
1543 uint8 refType
= dwarf_reference_type_local
;
1545 switch (attributeForm
) {
1547 value
= dataReader
.ReadAddress(0);
1549 case DW_FORM_block2
:
1550 blockLength
= dataReader
.Read
<uint16
>(0);
1552 case DW_FORM_block4
:
1553 blockLength
= dataReader
.Read
<uint32
>(0);
1556 value
= dataReader
.Read
<uint16
>(0);
1559 value
= dataReader
.Read
<uint32
>(0);
1562 value
= dataReader
.Read
<uint64
>(0);
1564 case DW_FORM_string
:
1565 attributeValue
.SetToString(dataReader
.ReadString());
1568 case DW_FORM_exprloc
:
1569 blockLength
= dataReader
.ReadUnsignedLEB128(0);
1571 case DW_FORM_block1
:
1572 blockLength
= dataReader
.Read
<uint8
>(0);
1575 value
= dataReader
.Read
<uint8
>(0);
1578 attributeValue
.SetToFlag(dataReader
.Read
<uint8
>(0) != 0);
1581 value
= dataReader
.ReadSignedLEB128(0);
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",
1595 attributeValue
.SetToString(
1596 (const char*)fDebugStringSection
->Data() + offset
);
1598 WARNING("Invalid DW_FORM_strp: no string section!\n");
1604 value
= dataReader
.ReadUnsignedLEB128(0);
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
;
1613 value
= dataReader
.Read
<uint8
>(0);
1616 value
= dataReader
.Read
<uint16
>(0);
1619 value
= dataReader
.Read
<uint32
>(0);
1622 value
= dataReader
.Read
<uint64
>(0);
1624 case DW_FORM_ref_udata
:
1625 value
= dataReader
.ReadUnsignedLEB128(0);
1627 case DW_FORM_flag_present
:
1628 attributeValue
.SetToFlag(true);
1630 case DW_FORM_ref_sig8
:
1631 fTypesSectionRequired
= true;
1632 value
= dataReader
.Read
<uint64
>(0);
1633 refType
= dwarf_reference_type_signature
;
1635 case DW_FORM_sec_offset
:
1636 value
= unit
->IsDwarf64()
1637 ? dataReader
.Read
<uint64
>(0)
1638 : (uint64
)dataReader
.Read
<uint32
>(0);
1640 case DW_FORM_indirect
:
1642 WARNING("Unsupported attribute form: %" B_PRIu32
"\n",
1647 // get the attribute class -- skip the attribute, if we can't handle
1649 uint8 attributeClass
= get_attribute_class(attributeName
,
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
);
1660 // set the attribute value according to the attribute's class
1661 switch (attributeClass
) {
1662 case ATTRIBUTE_CLASS_ADDRESS
:
1663 attributeValue
.SetToAddress(value
);
1665 case ATTRIBUTE_CLASS_BLOCK
:
1666 attributeValue
.SetToBlock(dataReader
.Data(), blockLength
);
1667 dataReader
.Skip(blockLength
);
1669 case ATTRIBUTE_CLASS_CONSTANT
:
1670 attributeValue
.SetToConstant(value
, isSigned
);
1672 case ATTRIBUTE_CLASS_LINEPTR
:
1673 attributeValue
.SetToLinePointer(value
);
1675 case ATTRIBUTE_CLASS_LOCLISTPTR
:
1676 attributeValue
.SetToLocationListPointer(value
);
1678 case ATTRIBUTE_CLASS_MACPTR
:
1679 attributeValue
.SetToMacroPointer(value
);
1681 case ATTRIBUTE_CLASS_RANGELISTPTR
:
1682 attributeValue
.SetToRangeListPointer(value
);
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
)
1695 WARNING("Failed to resolve reference on entry %p: "
1696 "(%#" B_PRIx64
") %s (%#" B_PRIx32
") %s "
1697 "(%#" B_PRIx32
"): value: %#" B_PRIx64
"\n",
1700 get_attribute_name_name(attributeName
),
1702 get_attribute_form_name(attributeForm
),
1703 attributeForm
, value
);
1704 return B_ENTRY_NOT_FOUND
;
1708 case ATTRIBUTE_CLASS_FLAG
:
1709 case ATTRIBUTE_CLASS_STRING
:
1714 if (dataReader
.HasOverflow()) {
1715 WARNING("Unexpected end of .debug_info section.\n");
1721 TRACE_DIE(" attr (%#" B_PRIx64
") %s %s (%d): %s\n",
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
,
1736 if (error
== ATTRIBUTE_NOT_HANDLED
) {
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
),
1748 TRACE_DIE(" -> no attribute setter!\n");
1757 DwarfFile::_ParseLineInfo(CompilationUnit
* unit
)
1759 off_t offset
= unit
->UnitEntry()->StatementListOffset();
1761 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF
"\n", unit
,
1764 DataReader
dataReader((uint8
*)fDebugLineSection
->Data() + offset
,
1765 fDebugLineSection
->Size() - offset
, unit
->AddressSize());
1769 uint64 unitLength
= dataReader
.ReadInitialLength(dwarf64
);
1770 if (unitLength
> (uint64
)dataReader
.BytesRemaining())
1772 off_t unitOffset
= dataReader
.Offset();
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
)
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())
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')
1824 TRACE_LINES(" \"%s\"\n", directory
);
1826 if (!unit
->AddDirectory(directory
))
1831 TRACE_LINES(" files:\n");
1832 while (const char* file
= dataReader
.ReadString()) {
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())
1844 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64
", mtime: %" B_PRIu64
1845 ", length: %" B_PRIu64
"\n", file
, dirIndex
, modificationTime
,
1848 if (!unit
->AddFile(file
, dirIndex
))
1852 off_t readerOffset
= dataReader
.Offset();
1853 if ((uint64
)readerOffset
> readerOffset
+ headerLength
)
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
);
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
);
1883 uint64 length
= dataReader
.ReadInitialLength(dwarf64
);
1884 uint64 lengthOffset
= dataReader
.Offset();
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
;
1893 status_t error
= _ParseCIEHeader(currentFrameSection
,
1894 info
->ehFrame
, unit
, addressSize
, context
, info
->cieOffset
,
1895 cieAugmentation
, cieReader
, cieRemaining
);
1898 if (cieReader
.HasOverflow())
1900 if (cieRemaining
< 0)
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
);
1922 error
= outputInterface
->InitRegisterRules(context
);
1926 // process the CIE's frame info instructions
1927 cieReader
= cieReader
.RestrictedReader(cieRemaining
);
1928 error
= _ParseFrameInfoInstructions(unit
, context
,
1929 cieReader
, cieAugmentation
);
1933 // read the FDE augmentation data (if any)
1934 FDEAugmentation fdeAugmentation
;
1935 error
= cieAugmentation
.ReadFDEData(dataReader
,
1937 if (error
!= B_OK
) {
1938 TRACE_CFI(" failed to read FDE augmentation data!\n");
1942 error
= context
.SaveInitialRuleSet();
1946 uint64 remaining
= lengthOffset
+ length
- dataReader
.Offset();
1950 DataReader restrictedReader
=
1951 dataReader
.RestrictedReader(remaining
);
1952 error
= _ParseFrameInfoInstructions(unit
, context
,
1953 restrictedReader
, cieAugmentation
);
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
:
1967 if (!inputInterface
->GetRegisterValue(
1968 cfaCfaRule
->Register(), value
)
1969 || !value
.IsNumber()) {
1970 return B_UNSUPPORTED
;
1972 frameAddress
= value
.ToUInt64() + cfaCfaRule
->Offset();
1975 case CFA_CFA_RULE_EXPRESSION
:
1977 error
= EvaluateExpression(unit
, addressSize
,
1979 cfaCfaRule
->Expression().block
,
1980 cfaCfaRule
->Expression().size
,
1981 inputInterface
, location
, 0, 0, false,
1987 case CFA_CFA_RULE_UNDEFINED
:
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
);
2002 CfaRule
* rule
= context
.RegisterRule(i
);
2007 switch (rule
->Type()) {
2008 case CFA_RULE_SAME_VALUE
:
2010 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
2013 if (inputInterface
->GetRegisterValue(i
, value
))
2014 outputInterface
->SetRegisterValue(i
, value
);
2017 case CFA_RULE_LOCATION_OFFSET
:
2019 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %"
2020 B_PRId64
"\n", rule
->Offset());
2023 if (inputInterface
->ReadValueFromMemory(
2024 frameAddress
+ rule
->Offset(), valueType
,
2026 outputInterface
->SetRegisterValue(i
, value
);
2030 case CFA_RULE_VALUE_OFFSET
:
2031 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
2033 outputInterface
->SetRegisterValue(i
,
2034 frameAddress
+ rule
->Offset());
2036 case CFA_RULE_REGISTER
:
2038 TRACE_CFI(" -> CFA_RULE_REGISTER\n");
2041 if (inputInterface
->GetRegisterValue(
2042 rule
->Register(), value
)) {
2043 outputInterface
->SetRegisterValue(i
, value
);
2047 case CFA_RULE_LOCATION_EXPRESSION
:
2049 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
2051 target_addr_t address
;
2052 error
= EvaluateExpression(unit
, addressSize
,
2054 rule
->Expression().block
,
2055 rule
->Expression().size
,
2056 inputInterface
, location
, frameAddress
,
2057 frameAddress
, true, address
);
2060 && inputInterface
->ReadValueFromMemory(address
,
2061 valueType
, value
)) {
2062 outputInterface
->SetRegisterValue(i
, value
);
2066 case CFA_RULE_VALUE_EXPRESSION
:
2068 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
2070 target_addr_t value
;
2071 error
= EvaluateExpression(unit
, addressSize
,
2073 rule
->Expression().block
,
2074 rule
->Expression().size
,
2075 inputInterface
, location
, frameAddress
,
2076 frameAddress
, true, value
);
2078 outputInterface
->SetRegisterValue(i
, value
);
2081 case CFA_RULE_UNDEFINED
:
2082 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
2088 _framePointer
= frameAddress
;
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())
2103 dataReader
.SetTo((uint8
*)debugFrameSection
->Data() + cieOffset
,
2104 debugFrameSection
->Size() - cieOffset
, unit
!= NULL
2105 ? unit
->AddressSize() : addressSize
);
2109 uint64 length
= dataReader
.ReadInitialLength(dwarf64
);
2110 if (length
> (uint64
)dataReader
.BytesRemaining())
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
) {
2122 if (dwarf64
? cieID
!= 0xffffffffffffffffULL
: cieID
!= 0xffffffff)
2126 uint8 version
= dataReader
.Read
<uint8
>(0);
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());
2161 if (dataReader
.HasOverflow())
2164 _cieRemaining
= length
-(dataReader
.Offset() - lengthOffset
);
2165 if (_cieRemaining
< 0)
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",
2189 target_addr_t location
= context
.Location()
2190 + operand
* context
.CodeAlignment();
2191 if (location
> context
.TargetLocation())
2193 context
.SetLocation(location
);
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());
2208 case DW_CFA_restore
:
2210 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32
"\n", operand
);
2212 context
.RestoreRegisterRule(operand
);
2220 TRACE_CFI(" DW_CFA_nop\n");
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())
2232 if (location
> context
.TargetLocation())
2234 context
.SetLocation(location
);
2237 case DW_CFA_advance_loc1
:
2239 uint32 delta
= dataReader
.Read
<uint8
>(0);
2241 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32
"\n",
2244 target_addr_t location
= context
.Location()
2245 + delta
* context
.CodeAlignment();
2246 if (location
> context
.TargetLocation())
2248 context
.SetLocation(location
);
2251 case DW_CFA_advance_loc2
:
2253 uint32 delta
= dataReader
.Read
<uint16
>(0);
2255 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32
"\n",
2258 target_addr_t location
= context
.Location()
2259 + delta
* context
.CodeAlignment();
2260 if (location
> context
.TargetLocation())
2262 context
.SetLocation(location
);
2265 case DW_CFA_advance_loc4
:
2267 uint32 delta
= dataReader
.Read
<uint32
>(0);
2269 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32
"\n",
2272 target_addr_t location
= context
.Location()
2273 + delta
* context
.CodeAlignment();
2274 if (location
> context
.TargetLocation())
2276 context
.SetLocation(location
);
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());
2293 case DW_CFA_restore_extended
:
2295 uint32 reg
= dataReader
.ReadUnsignedLEB128(0);
2297 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32
"\n",
2300 context
.RestoreRegisterRule(reg
);
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();
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();
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
);
2335 case DW_CFA_remember_state
:
2337 TRACE_CFI(" DW_CFA_remember_state\n");
2339 status_t error
= context
.PushRuleSet();
2344 case DW_CFA_restore_state
:
2346 TRACE_CFI(" DW_CFA_restore_state\n");
2348 status_t error
= context
.PopRuleSet();
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
);
2364 case DW_CFA_def_cfa_register
:
2366 uint32 reg
= dataReader
.ReadUnsignedLEB128(0);
2368 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32
"\n",
2371 if (context
.GetCfaCfaRule()->Type()
2372 != CFA_CFA_RULE_REGISTER_OFFSET
) {
2375 context
.GetCfaCfaRule()->SetRegister(reg
);
2378 case DW_CFA_def_cfa_offset
:
2380 uint64 offset
= dataReader
.ReadUnsignedLEB128(0);
2382 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64
"\n",
2385 if (context
.GetCfaCfaRule()->Type()
2386 != CFA_CFA_RULE_REGISTER_OFFSET
) {
2389 context
.GetCfaCfaRule()->SetOffset(offset
);
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
,
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
);
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());
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());
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",
2452 if (context
.GetCfaCfaRule()->Type()
2453 != CFA_CFA_RULE_REGISTER_OFFSET
) {
2456 context
.GetCfaCfaRule()->SetOffset(
2457 offset
* (int32
)context
.DataAlignment());
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());
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());
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
);
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",
2511 target_addr_t location
= context
.Location()
2512 + delta
* context
.CodeAlignment();
2513 if (location
> context
.TargetLocation())
2515 context
.SetLocation(location
);
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!
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",
2537 case DW_CFA_GNU_negative_offset_extended
:
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
,
2547 if (CfaRule
* rule
= context
.RegisterRule(reg
)) {
2548 rule
->SetToLocationOffset(
2549 offset
* (int32
)context
.DataAlignment());
2555 TRACE_CFI(" unknown opcode %u!\n", opcode
);
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) {
2580 uint64 unitLength
= dataReader
.ReadInitialLength(dwarf64
);
2582 off_t unitLengthOffset
= dataReader
.Offset();
2583 // the unitLength starts here
2585 if (dataReader
.HasOverflow())
2588 if (unitLengthOffset
+ unitLength
2589 > (uint64
)fDebugPublicTypesSection
->Size()) {
2590 WARNING("Invalid public types set unit length.\n");
2594 DataReader
unitDataReader(dataReader
.Data(), unitLength
, 4);
2595 // address size doesn't matter
2596 _ParsePublicTypesInfo(unitDataReader
, dwarf64
);
2598 dataReader
.SeekAbsolute(unitLengthOffset
+ unitLength
);
2606 DwarfFile::_ParsePublicTypesInfo(DataReader
& dataReader
, bool dwarf64
)
2608 int version
= dataReader
.Read
<uint16
>(0);
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())
2624 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
2625 "info: (%" B_PRIdOFF
", %" B_PRIdOFF
")\n", debugInfoOffset
,
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)
2635 TRACE_PUBTYPES_ONLY(const char* name
=) dataReader
.ReadString();
2637 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF
"\n", name
, entryOffset
);
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()) {
2657 // create a new table
2658 AbbreviationTable
* table
= new(std::nothrow
) AbbreviationTable(offset
);
2662 status_t error
= table
->Init(fDebugAbbrevSection
->Data(),
2663 fDebugAbbrevSection
->Size());
2664 if (error
!= B_OK
) {
2669 fAbbreviationTables
.Add(table
);
2676 DwarfFile::_ResolveReference(BaseUnit
* unit
, uint64 offset
,
2677 uint8 refType
) const
2680 case dwarf_reference_type_local
:
2681 return unit
->EntryForOffset(offset
);
2683 case dwarf_reference_type_global
:
2685 CompilationUnit
* unit
= _GetContainingCompilationUnit(offset
);
2689 offset
-= unit
->HeaderOffset();
2690 DebugInfoEntry
* entry
= unit
->EntryForOffset(offset
);
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();
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())
2717 if (location
->IsExpression()) {
2718 _expression
= location
->expression
.data
;
2719 _length
= location
->expression
.length
;
2723 if (location
->IsLocationList() && instructionPointer
!= 0) {
2724 return _FindLocationExpression(unit
, location
->listOffset
,
2725 instructionPointer
, _expression
, _length
);
2733 DwarfFile::_FindLocationExpression(CompilationUnit
* unit
, uint64 offset
,
2734 target_addr_t address
, const void*& _expression
, off_t
& _length
) const
2739 if (fDebugLocationSection
== NULL
)
2740 return B_ENTRY_NOT_FOUND
;
2742 if (offset
< 0 || offset
>= (uint64
)fDebugLocationSection
->Size())
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());
2751 target_addr_t start
= dataReader
.ReadAddress(0);
2752 target_addr_t end
= dataReader
.ReadAddress(0);
2753 if (dataReader
.HasOverflow())
2756 if (start
== 0 && end
== 0)
2757 return B_ENTRY_NOT_FOUND
;
2759 if (start
== maxAddress
) {
2764 uint16 expressionLength
= dataReader
.Read
<uint16
>(0);
2765 const void* expression
= dataReader
.Data();
2766 if (!dataReader
.Skip(expressionLength
))
2772 start
+= baseAddress
;
2775 if (address
>= start
&& address
< end
) {
2776 _expression
= expression
;
2777 _length
= expressionLength
;
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
2800 if (locatedFilePath
)
2801 debugPath
= locatedFilePath
;
2803 status_t result
= _GetDebugInfoPath(
2804 (const char*)debugLinkSection
->Data(),
2805 _requiredExternalFileName
);
2808 debugPath
= _requiredExternalFileName
;
2811 if (fAlternateName
!= NULL
)
2812 free(fAlternateName
);
2814 fAlternateName
= strdup(debugPath
.String());
2816 if (fAlternateName
== NULL
)
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
)
2830 status_t result
= fAlternateElfFile
->Init(fAlternateName
);
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
2846 fEHFrameSection
= fElfFile
->GetSection(".eh_frame");
2847 if (fEHFrameSection
== NULL
)
2856 DwarfFile::_GetDebugInfoPath(const char* debugFileName
,
2857 BString
& _infoPath
) const
2859 // first, see if we have a relative match to our local directory
2861 status_t result
= basePath
.SetTo(fName
);
2864 basePath
.GetParent(&basePath
);
2865 if (strcmp(basePath
.Leaf(), "lib") == 0 || strcmp(basePath
.Leaf(),
2867 _infoPath
.SetToFormat("%s/../debug/%s", basePath
.Path(),
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
)
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
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();
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
;
2903 DwarfFile::_GetTypeUnit(uint64 signature
) const
2905 return fTypeUnits
.Lookup(signature
);
2910 DwarfFile::_GetContainingCompilationUnit(off_t refAddr
) const
2912 if (fCompilationUnits
.IsEmpty())
2917 int upper
= fCompilationUnits
.CountItems() - 1;
2918 while (lower
< upper
) {
2919 int mid
= (lower
+ upper
+ 1) / 2;
2920 if (fCompilationUnits
.ItemAt(mid
)->HeaderOffset() > refAddr
)
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
);
2941 return _GetContainingFDEInfo(offset
, fEHFrameInfos
);
2945 DwarfFile::FDELookupInfo
*
2946 DwarfFile::_GetContainingFDEInfo(target_addr_t offset
,
2947 const FDEInfoList
& infoList
) const
2951 int upper
= infoList
.CountItems() - 1;
2955 while (lower
< upper
) {
2956 int mid
= (lower
+ upper
+ 1) / 2;
2957 if (offset
< infoList
.ItemAt(mid
)->start
)
2963 FDELookupInfo
* info
= infoList
.ItemAt(lower
);
2964 return info
->ContainsAddress(offset
) ? info
: NULL
;