From c5253237f8b3b4eb888f7f85f39acd7d4d0f57cf Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Mon, 28 Oct 2013 23:01:48 +0000 Subject: DebugInfo: Introduce the notion of "form classes" Summary: Use DWARF4 table of form classes to fetch attributes from DIE in a more consistent way. This shouldn't change the functionality and serves as a refactoring for upcoming change: DW_AT_high_pc has different semantics depending on its form class. Reviewers: dblaikie, echristo Reviewed By: echristo CC: echristo, llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1961 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193553 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/DebugInfo/DWARFFormValue.h | 33 +++++-- lib/DebugInfo/DWARFContext.cpp | 8 +- lib/DebugInfo/DWARFDebugInfoEntry.cpp | 55 ++++++++---- lib/DebugInfo/DWARFDebugInfoEntry.h | 9 +- lib/DebugInfo/DWARFFormValue.cpp | 137 ++++++++++++++++++++++------- lib/DebugInfo/DWARFUnit.cpp | 16 ++-- unittests/DebugInfo/DWARFFormValueTest.cpp | 17 ++++ 7 files changed, 201 insertions(+), 74 deletions(-) diff --git a/include/llvm/DebugInfo/DWARFFormValue.h b/include/llvm/DebugInfo/DWARFFormValue.h index c8d6008..a9d1ec0 100644 --- a/include/llvm/DebugInfo/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARFFormValue.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H #define LLVM_DEBUGINFO_DWARFFORMVALUE_H +#include "llvm/ADT/Optional.h" #include "llvm/Support/DataExtractor.h" namespace llvm { @@ -18,6 +19,21 @@ class DWARFUnit; class raw_ostream; class DWARFFormValue { +public: + enum FormClass { + FC_Unknown, + FC_Address, + FC_Block, + FC_Constant, + FC_String, + FC_Flag, + FC_Reference, + FC_Indirect, + FC_SectionOffset, + FC_Exprloc + }; + +private: struct ValueType { ValueType() : data(NULL) { uval = 0; @@ -35,9 +51,10 @@ class DWARFFormValue { ValueType Value; // Contains all data for the form. public: - DWARFFormValue(uint16_t form = 0) : Form(form) {} + DWARFFormValue(uint16_t Form = 0) : Form(Form) {} uint16_t getForm() const { return Form; } - const ValueType& value() const { return Value; } + bool isFormClass(FormClass FC) const; + void dump(raw_ostream &OS, const DWARFUnit *U) const; bool extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFUnit *u); @@ -45,11 +62,13 @@ public: return Value.data != NULL && Value.data == (const uint8_t*)Value.cstr; } - uint64_t getReference(const DWARFUnit *U) const; - uint64_t getUnsigned() const { return Value.uval; } - int64_t getSigned() const { return Value.sval; } - const char *getAsCString(const DWARFUnit *U) const; - uint64_t getAsAddress(const DWARFUnit *U) const; + /// getAsFoo functions below return the extracted value as Foo if only + /// DWARFFormValue has form class is suitable for representing Foo. + Optional getAsReference(const DWARFUnit *U) const; + Optional getAsUnsignedConstant() const; + Optional getAsCString(const DWARFUnit *U) const; + Optional getAsAddress(const DWARFUnit *U) const; + Optional getAsSectionOffset() const; bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *u) const; diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index 9dc8f14..6056de7 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -102,8 +102,8 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { DWARFCompileUnit *cu = getCompileUnitAtIndex(i); savedAddressByteSize = cu->getAddressByteSize(); unsigned stmtOffset = - cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, - -1U); + cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( + cu, DW_AT_stmt_list, -1U); if (stmtOffset != -1U) { DataExtractor lineData(getLineSection().Data, isLittleEndian(), savedAddressByteSize); @@ -262,8 +262,8 @@ DWARFContext::getLineTableForCompileUnit(DWARFCompileUnit *cu) { Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); unsigned stmtOffset = - cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, - -1U); + cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( + cu, DW_AT_stmt_list, -1U); if (stmtOffset == -1U) return 0; // No line table for this compile unit. diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARFDebugInfoEntry.cpp index 9bb49df..e8b8748 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -160,8 +160,11 @@ bool DWARFDebugInfoEntryMinimal::extract(const DWARFUnit *U, ((Attr == DW_AT_entry_pc) || (Attr == DW_AT_low_pc))) { DWARFFormValue FormValue(Form); if (FormValue.extractValue(DebugInfoData, OffsetPtr, U)) { - if (Attr == DW_AT_low_pc || Attr == DW_AT_entry_pc) - const_cast(U)->setBaseAddress(FormValue.getUnsigned()); + if (Attr == DW_AT_low_pc || Attr == DW_AT_entry_pc) { + Optional BaseAddr = FormValue.getAsAddress(U); + if (BaseAddr.hasValue()) + const_cast(U)->setBaseAddress(BaseAddr.getValue()); + } } } else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) { // Restore the original offset. @@ -210,33 +213,46 @@ bool DWARFDebugInfoEntryMinimal::getAttributeValue( const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(U, Attr, FormValue)) - return FormValue.getAsCString(U); - return FailValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsCString(U); + return Result.hasValue() ? Result.getValue() : FailValue; } uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress( const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(U, Attr, FormValue)) - return FormValue.getAsAddress(U); - return FailValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsAddress(U); + return Result.hasValue() ? Result.getValue() : FailValue; } -uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned( +uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant( const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(U, Attr, FormValue)) - return FormValue.getUnsigned(); - return FailValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsUnsignedConstant(); + return Result.hasValue() ? Result.getValue() : FailValue; } uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; - if (getAttributeValue(U, Attr, FormValue)) - return FormValue.getReference(U); - return FailValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsReference(U); + return Result.hasValue() ? Result.getValue() : FailValue; +} + +uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSectionOffset( + const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsSectionOffset(); + return Result.hasValue() ? Result.getValue() : FailValue; } bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U, @@ -277,7 +293,8 @@ bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress( if (getLowAndHighPC(U, LowPC, HighPC)) return (LowPC <= Address && Address <= HighPC); // Try to get address ranges from .debug_ranges section. - uint32_t RangesOffset = getAttributeValueAsReference(U, DW_AT_ranges, -1U); + uint32_t RangesOffset = + getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U); if (RangesOffset != -1U) { DWARFDebugRangeList RangeList; if (U->extractRangeList(RangesOffset, RangeList)) @@ -325,9 +342,9 @@ void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFUnit *U, uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsigned(U, DW_AT_call_file, 0); - CallLine = getAttributeValueAsUnsigned(U, DW_AT_call_line, 0); - CallColumn = getAttributeValueAsUnsigned(U, DW_AT_call_column, 0); + CallFile = getAttributeValueAsUnsignedConstant(U, DW_AT_call_file, 0); + CallLine = getAttributeValueAsUnsignedConstant(U, DW_AT_call_line, 0); + CallColumn = getAttributeValueAsUnsignedConstant(U, DW_AT_call_column, 0); } DWARFDebugInfoEntryInlinedChain diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.h b/lib/DebugInfo/DWARFDebugInfoEntry.h index e1d88ee..e073d87 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.h +++ b/lib/DebugInfo/DWARFDebugInfoEntry.h @@ -129,12 +129,17 @@ public: uint64_t getAttributeValueAsAddress(const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const; - uint64_t getAttributeValueAsUnsigned(const DWARFUnit *U, const uint16_t Attr, - uint64_t FailValue) const; + uint64_t getAttributeValueAsUnsignedConstant(const DWARFUnit *U, + const uint16_t Attr, + uint64_t FailValue) const; uint64_t getAttributeValueAsReference(const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const; + uint64_t getAttributeValueAsSectionOffset(const DWARFUnit *U, + const uint16_t Attr, + uint64_t FailValue) const; + /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU. /// Returns true if both attributes are present. bool getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC, diff --git a/lib/DebugInfo/DWARFFormValue.cpp b/lib/DebugInfo/DWARFFormValue.cpp index 0dddb7e..1a59dd8 100644 --- a/lib/DebugInfo/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARFFormValue.cpp @@ -10,6 +10,8 @@ #include "llvm/DebugInfo/DWARFFormValue.h" #include "DWARFCompileUnit.h" #include "DWARFContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" @@ -74,6 +76,57 @@ DWARFFormValue::getFixedFormSizes(uint8_t AddrSize, uint16_t Version) { return 0; } +static const DWARFFormValue::FormClass DWARF4FormClasses[] = { + DWARFFormValue::FC_Unknown, // 0x0 + DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr + DWARFFormValue::FC_Unknown, // 0x02 unused + DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 + DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 + DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 + // --- These can be FC_SectionOffset in DWARF3 and below: + DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 + DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 + // --- + DWARFFormValue::FC_String, // 0x08 DW_FORM_string + DWARFFormValue::FC_Block, // 0x09 DW_FORM_block + DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 + DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 + DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag + DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata + DWARFFormValue::FC_String, // 0x0e DW_FORM_strp + DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata + DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr + DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 + DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 + DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 + DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 + DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata + DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect + DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset + DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc + DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present + DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8 +}; + +bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { + // First, check DWARF4 form classes. + if (Form < ArrayRef(DWARF4FormClasses).size() && + DWARF4FormClasses[Form] == FC) + return true; + // Check for some DWARF5 forms. + if (Form == DW_FORM_GNU_addr_index) + return (FC == FC_Address); + if (Form == DW_FORM_GNU_str_index) + return (FC == FC_String); + // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset. + // Don't check for DWARF version here, as some producers may still do this + // by mistake. + if ((Form == DW_FORM_data4 || Form == DW_FORM_data8) && + FC == FC_SectionOffset) + return true; + return false; +} + bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFUnit *cu) { bool indirect = false; @@ -155,10 +208,6 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, break; case DW_FORM_string: Value.cstr = data.getCStr(offset_ptr); - // Set the string value to also be the data for inlined cstr form - // values only so we can tell the differnence between DW_FORM_string - // and DW_FORM_strp form values - Value.data = (const uint8_t*)Value.cstr; break; case DW_FORM_indirect: Form = data.getULEB128(offset_ptr); @@ -313,7 +362,7 @@ void DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { DataExtractor debug_str_data(cu->getStringSection(), true, 0); DataExtractor debug_str_offset_data(cu->getStringOffsetSection(), true, 0); - uint64_t uvalue = getUnsigned(); + uint64_t uvalue = Value.uval; bool cu_relative_offset = false; switch (Form) { @@ -336,7 +385,7 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { case DW_FORM_data8: OS << format("0x%016" PRIx64, uvalue); break; case DW_FORM_string: OS << '"'; - OS.write_escaped(getAsCString(NULL)); + OS.write_escaped(Value.cstr); OS << '"'; break; case DW_FORM_exprloc: @@ -368,24 +417,24 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { } break; - case DW_FORM_sdata: OS << getSigned(); break; - case DW_FORM_udata: OS << getUnsigned(); break; + case DW_FORM_sdata: OS << Value.sval; break; + case DW_FORM_udata: OS << Value.uval; break; case DW_FORM_strp: { OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); - const char* dbg_str = getAsCString(cu); - if (dbg_str) { + Optional DbgStr = getAsCString(cu); + if (DbgStr.hasValue()) { OS << '"'; - OS.write_escaped(dbg_str); + OS.write_escaped(DbgStr.getValue()); OS << '"'; } break; } case DW_FORM_GNU_str_index: { OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); - const char *dbg_str = getAsCString(cu); - if (dbg_str) { + Optional DbgStr = getAsCString(cu); + if (DbgStr.hasValue()) { OS << '"'; - OS.write_escaped(dbg_str); + OS.write_escaped(DbgStr.getValue()); OS << '"'; } break; @@ -434,47 +483,67 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { OS << format(" => {0x%8.8" PRIx64 "}", uvalue + (cu ? cu->getOffset() : 0)); } -const char *DWARFFormValue::getAsCString(const DWARFUnit *CU) const { - if (isInlinedCStr()) +Optional DWARFFormValue::getAsCString(const DWARFUnit *U) const { + if (!isFormClass(FC_String)) + return None; + if (Form == DW_FORM_string) return Value.cstr; - if (!CU) - return NULL; + if (U == 0) + return None; uint32_t Offset = Value.uval; if (Form == DW_FORM_GNU_str_index) { uint32_t StrOffset; - if (!CU->getStringOffsetSectionItem(Offset, StrOffset)) - return NULL; + if (!U->getStringOffsetSectionItem(Offset, StrOffset)) + return None; Offset = StrOffset; } - return CU->getStringExtractor().getCStr(&Offset); + if (const char *Str = U->getStringExtractor().getCStr(&Offset)) { + return Str; + } + return None; } -uint64_t DWARFFormValue::getAsAddress(const DWARFUnit *CU) const { - if (!CU) - return 0; +Optional DWARFFormValue::getAsAddress(const DWARFUnit *U) const { + if (!isFormClass(FC_Address)) + return None; if (Form == DW_FORM_GNU_addr_index) { uint32_t Index = Value.uval; - uint64_t Address; - if (!CU->getAddrOffsetSectionItem(Index, Address)) - return 0; - return Address; + uint64_t Result; + if (U == 0 || !U->getAddrOffsetSectionItem(Index, Result)) + return None; + return Result; } return Value.uval; } -uint64_t DWARFFormValue::getReference(const DWARFUnit *cu) const { - uint64_t die_offset = Value.uval; +Optional DWARFFormValue::getAsReference(const DWARFUnit *U) const { + if (!isFormClass(FC_Reference)) + return None; switch (Form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: - die_offset += (cu ? cu->getOffset() : 0); - break; + if (U == 0) + return None; + return Value.uval + U->getOffset(); + case DW_FORM_ref_addr: + return Value.uval; + // FIXME: Add proper support for DW_FORM_ref_sig8 default: - break; + return Value.uval; } +} - return die_offset; +Optional DWARFFormValue::getAsSectionOffset() const { + if (!isFormClass(FC_SectionOffset)) + return None; + return Value.uval; +} + +Optional DWARFFormValue::getAsUnsignedConstant() const { + if (!isFormClass(FC_Constant) || Form == DW_FORM_sdata) + return None; + return Value.uval; } diff --git a/lib/DebugInfo/DWARFUnit.cpp b/lib/DebugInfo/DWARFUnit.cpp index 770c65b..25062cd 100644 --- a/lib/DebugInfo/DWARFUnit.cpp +++ b/lib/DebugInfo/DWARFUnit.cpp @@ -144,7 +144,7 @@ uint64_t DWARFUnit::getDWOId() { if (DieArray.empty()) return FailValue; return DieArray[0] - .getAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, FailValue); + .getAttributeValueAsUnsignedConstant(this, DW_AT_GNU_dwo_id, FailValue); } void DWARFUnit::setDIERelations() { @@ -251,14 +251,14 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { uint64_t BaseAddr = - DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); - if (BaseAddr == -1U) - BaseAddr = DieArray[0].getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); + DieArray[0].getAttributeValueAsAddress(this, DW_AT_low_pc, -1ULL); + if (BaseAddr == -1ULL) + BaseAddr = DieArray[0].getAttributeValueAsAddress(this, DW_AT_entry_pc, 0); setBaseAddress(BaseAddr); - AddrOffsetSectionBase = - DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_addr_base, 0); - RangeSectionBase = - DieArray[0].getAttributeValueAsReference(this, DW_AT_GNU_ranges_base, 0); + AddrOffsetSectionBase = DieArray[0].getAttributeValueAsSectionOffset( + this, DW_AT_GNU_addr_base, 0); + RangeSectionBase = DieArray[0].getAttributeValueAsSectionOffset( + this, DW_AT_GNU_ranges_base, 0); } setDIERelations(); diff --git a/unittests/DebugInfo/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARFFormValueTest.cpp index 04b859b..e7216b3 100644 --- a/unittests/DebugInfo/DWARFFormValueTest.cpp +++ b/unittests/DebugInfo/DWARFFormValueTest.cpp @@ -28,4 +28,21 @@ TEST(DWARFFormValue, FixedFormSizes) { EXPECT_EQ(0, DWARFFormValue::getFixedFormSizes(16, 2)); } +bool isFormClass(uint16_t Form, DWARFFormValue::FormClass FC) { + return DWARFFormValue(Form).isFormClass(FC); +} + +TEST(DWARFFormValue, FormClass) { + EXPECT_TRUE(isFormClass(DW_FORM_addr, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Constant)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE( + isFormClass(DW_FORM_sec_offset, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_str_index, DWARFFormValue::FC_String)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_addr_index, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Reference)); +} + } // end anonymous namespace -- cgit v1.1