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
This commit is contained in:
Alexey Samsonov 2013-10-28 23:01:48 +00:00
parent 730e3c6995
commit c5253237f8
7 changed files with 202 additions and 75 deletions

View File

@ -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<uint64_t> getAsReference(const DWARFUnit *U) const;
Optional<uint64_t> getAsUnsignedConstant() const;
Optional<const char *> getAsCString(const DWARFUnit *U) const;
Optional<uint64_t> getAsAddress(const DWARFUnit *U) const;
Optional<uint64_t> getAsSectionOffset() const;
bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr,
const DWARFUnit *u) const;

View File

@ -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.

View File

@ -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<DWARFUnit *>(U)->setBaseAddress(FormValue.getUnsigned());
if (Attr == DW_AT_low_pc || Attr == DW_AT_entry_pc) {
Optional<uint64_t> BaseAddr = FormValue.getAsAddress(U);
if (BaseAddr.hasValue())
const_cast<DWARFUnit *>(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<const char *> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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

View File

@ -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,

View File

@ -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<FormClass>(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<const char *> 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<const char *> 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<const char *> 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<uint64_t> 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<uint64_t> 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<uint64_t> DWARFFormValue::getAsSectionOffset() const {
if (!isFormClass(FC_SectionOffset))
return None;
return Value.uval;
}
Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
if (!isFormClass(FC_Constant) || Form == DW_FORM_sdata)
return None;
return Value.uval;
}

View File

@ -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();

View File

@ -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