[DebugInfo] [DWARFv5] Unique abbrevs for DIEs with different implicit_const values

Take DW_FORM_implicit_const attribute value into account when profiling
DIEAbbrevData.

Currently if we have two similar types with implicit_const attributes and
different values we end up with only one abbrev in .debug_abbrev section.
For example consider two structures: S1 with implicit_const attribute ATTR
and value VAL1 and S2 with implicit_const ATTR and value VAL2.
The .debug_abbrev section will contain only 1 related record:

[N] DW_TAG_structure_type       DW_CHILDREN_yes
        DW_AT_ATTR        DW_FORM_implicit_const  VAL1
        // ....

This is incorrect as struct S2 (with VAL2) will use abbrev record with VAL1.

With this patch we will have two different abbreviations here:

[N] DW_TAG_structure_type       DW_CHILDREN_yes
        DW_AT_ATTR        DW_FORM_implicit_const  VAL1
        // ....

[M] DW_TAG_structure_type       DW_CHILDREN_yes
        DW_AT_ATTR        DW_FORM_implicit_const  VAL2
        // ....

llvm-svn: 296691
This commit is contained in:
Victor Leschuk 2017-03-01 22:13:42 +00:00
parent 0e429606b0
commit d7bfa40ace
2 changed files with 125 additions and 2 deletions

View File

@ -42,6 +42,8 @@ void DIEAbbrevData::Profile(FoldingSetNodeID &ID) const {
// overloads. Otherwise MSVC 2010 thinks this call is ambiguous.
ID.AddInteger(unsigned(Attribute));
ID.AddInteger(unsigned(Form));
if (Form == dwarf::DW_FORM_implicit_const)
ID.AddInteger(Value);
}
//===----------------------------------------------------------------------===//
@ -107,8 +109,12 @@ void DIEAbbrev::print(raw_ostream &O) {
O << " "
<< dwarf::AttributeString(Data[i].getAttribute())
<< " "
<< dwarf::FormEncodingString(Data[i].getForm())
<< '\n';
<< dwarf::FormEncodingString(Data[i].getForm());
if (Data[i].getForm() == dwarf::DW_FORM_implicit_const)
O << " " << Data[i].getValue();
O << '\n';
}
}

View File

@ -1543,4 +1543,121 @@ TEST(DWARFDebugInfo, TestFindAttrs) {
EXPECT_EQ(DieMangled, toString(NameOpt, ""));
}
TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
uint16_t Version = 5;
const uint8_t AddrSize = sizeof(void *);
initLLVMIfNeeded();
Triple Triple = getHostTripleForAddrSize(AddrSize);
auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
if (HandleExpectedError(ExpectedDG))
return;
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
const dwarf::Attribute Attr = DW_AT_lo_user;
const int64_t Val1 = 42;
const int64_t Val2 = 43;
auto FirstVal1DIE = CUDie.addChild(DW_TAG_class_type);
FirstVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
auto SecondVal1DIE = CUDie.addChild(DW_TAG_class_type);
SecondVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
auto Val2DIE = CUDie.addChild(DW_TAG_class_type);
Val2DIE.addAttribute(Attr, DW_FORM_implicit_const, Val2);
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
DWARFContextInMemory DwarfContext(*Obj.get());
DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
EXPECT_TRUE((bool)U);
const auto *Abbrevs = U->getAbbreviations();
EXPECT_TRUE((bool)Abbrevs);
// Let's find implicit_const abbrevs and verify,
// that there are exactly two of them and both of them
// can be dumped correctly.
typedef decltype(Abbrevs->begin()) AbbrevIt;
AbbrevIt Val1Abbrev = Abbrevs->end();
AbbrevIt Val2Abbrev = Abbrevs->end();
for(auto it = Abbrevs->begin(); it != Abbrevs->end(); ++it) {
if (it->getNumAttributes() == 0)
continue; // root abbrev for DW_TAG_compile_unit
auto A = it->getAttrByIndex(0);
EXPECT_EQ(A, Attr);
auto FormValue = it->getAttributeValue(/* offset */ 0, A, *U);
EXPECT_TRUE((bool)FormValue);
EXPECT_EQ(FormValue->getForm(), dwarf::DW_FORM_implicit_const);
const auto V = FormValue->getAsSignedConstant();
EXPECT_TRUE((bool)V);
auto VerifyAbbrevDump = [&V](AbbrevIt it) {
std::string S;
llvm::raw_string_ostream OS(S);
it->dump(OS);
auto FormPos = OS.str().find("DW_FORM_implicit_const");
EXPECT_NE(FormPos, std::string::npos);
auto ValPos = S.find_first_of("-0123456789", FormPos);
EXPECT_NE(ValPos, std::string::npos);
int64_t Val = std::atoll(S.substr(ValPos).c_str());
EXPECT_EQ(Val, *V);
};
switch(*V) {
case Val1:
EXPECT_EQ(Val1Abbrev, Abbrevs->end());
Val1Abbrev = it;
VerifyAbbrevDump(it);
break;
case Val2:
EXPECT_EQ(Val2Abbrev, Abbrevs->end());
Val2Abbrev = it;
VerifyAbbrevDump(it);
break;
default:
FAIL() << "Unexpected attribute value: " << *V;
}
}
// Now let's make sure that two Val1-DIEs refer to the same abbrev,
// and Val2-DIE refers to another one.
auto DieDG = U->getUnitDIE(false);
auto it = DieDG.begin();
std::multimap<int64_t, decltype(it->getAbbreviationDeclarationPtr())> DIEs;
const DWARFAbbreviationDeclaration *AbbrevPtrVal1 = nullptr;
const DWARFAbbreviationDeclaration *AbbrevPtrVal2 = nullptr;
for (; it != DieDG.end(); ++it) {
const auto *AbbrevPtr = it->getAbbreviationDeclarationPtr();
EXPECT_TRUE((bool)AbbrevPtr);
auto FormValue = it->find(Attr);
EXPECT_TRUE((bool)FormValue);
const auto V = FormValue->getAsSignedConstant();
EXPECT_TRUE((bool)V);
switch(*V) {
case Val1:
AbbrevPtrVal1 = AbbrevPtr;
break;
case Val2:
AbbrevPtrVal2 = AbbrevPtr;
break;
default:
FAIL() << "Unexpected attribute value: " << *V;
}
DIEs.insert(std::make_pair(*V, AbbrevPtr));
}
EXPECT_EQ(DIEs.count(Val1), 2u);
EXPECT_EQ(DIEs.count(Val2), 1u);
auto Val1Range = DIEs.equal_range(Val1);
for (auto it = Val1Range.first; it != Val1Range.second; ++it)
EXPECT_EQ(it->second, AbbrevPtrVal1);
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
}
} // end anonymous namespace