summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/DWARF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/DebugInfo/DWARF
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF')
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp3
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFContext.cpp63
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp29
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp1
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp683
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp39
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDie.cpp147
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp23
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp43
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp110
10 files changed, 988 insertions, 153 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
index 2b08120ef4dc..6e30309ae94a 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -26,7 +26,8 @@ void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
if (!getAbbreviations())
OS << " (invalid)";
OS << ", addr_size = " << format("0x%02x", getAddressByteSize());
- if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile)
+ if (getVersion() >= 5 && (getUnitType() == dwarf::DW_UT_skeleton ||
+ getUnitType() == dwarf::DW_UT_split_compile))
OS << ", DWO_id = " << format("0x%016" PRIx64, *getDWOId());
OS << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset())
<< ")\n";
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 749d738af9c1..4e1cafeb2126 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -823,6 +823,8 @@ Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
if (DebugFrame)
return DebugFrame.get();
+ const DWARFSection &DS = DObj->getFrameSection();
+
// There's a "bug" in the DWARFv3 standard with respect to the target address
// size within debug frame sections. While DWARF is supposed to be independent
// of its container, FDEs have fields with size being "target address size",
@@ -832,10 +834,11 @@ Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
// provides this information). This problem is fixed in DWARFv4
// See this dwarf-discuss discussion for more details:
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
- DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(),
- isLittleEndian(), DObj->getAddressSize());
- auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false);
- if (Error E = DF->parse(debugFrameData))
+ DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
+ DObj->getAddressSize());
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false, DS.Address);
+ if (Error E = DF->parse(DebugFrameData))
return std::move(E);
DebugFrame.swap(DF);
@@ -846,11 +849,13 @@ Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
if (EHFrame)
return EHFrame.get();
- DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(),
- isLittleEndian(), DObj->getAddressSize());
+ const DWARFSection &DS = DObj->getEHFrameSection();
+ DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
+ DObj->getAddressSize());
- auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true);
- if (Error E = DF->parse(debugFrameData))
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true, DS.Address);
+ if (Error E = DF->parse(DebugFrameData))
return std::move(E);
DebugFrame.swap(DF);
return DebugFrame.get();
@@ -1022,8 +1027,7 @@ DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
break;
}
- for (auto Child : DIE)
- Worklist.push_back(Child);
+ append_range(Worklist, DIE);
}
return Result;
@@ -1031,13 +1035,11 @@ DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
/// TODO: change input parameter from "uint64_t Address"
/// into "SectionedAddress Address"
-static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
- uint64_t Address,
- FunctionNameKind Kind,
- DILineInfoSpecifier::FileLineInfoKind FileNameKind,
- std::string &FunctionName,
- std::string &StartFile,
- uint32_t &StartLine) {
+static bool getFunctionNameAndStartLineForAddress(
+ DWARFCompileUnit *CU, uint64_t Address, FunctionNameKind Kind,
+ DILineInfoSpecifier::FileLineInfoKind FileNameKind,
+ std::string &FunctionName, std::string &StartFile, uint32_t &StartLine,
+ Optional<uint64_t> &StartAddress) {
// The address may correspond to instruction in some inlined function,
// so we have to build the chain of inlined functions and take the
// name of the topmost function in it.
@@ -1062,7 +1064,8 @@ static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
StartLine = DeclLineResult;
FoundResult = true;
}
-
+ if (auto LowPcAddr = toSectionedAddress(DIE.find(DW_AT_low_pc)))
+ StartAddress = LowPcAddr->Address;
return FoundResult;
}
@@ -1229,9 +1232,9 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
if (!CU)
return Result;
- getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind, Spec.FLIKind,
- Result.FunctionName,
- Result.StartFileName, Result.StartLine);
+ getFunctionNameAndStartLineForAddress(
+ CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
+ Result.StartFileName, Result.StartLine, Result.StartAddress);
if (Spec.FLIKind != FileLineInfoKind::None) {
if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
LineTable->getFileLineInfoForAddress(
@@ -1244,7 +1247,7 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
DILineInfoTable DWARFContext::getLineInfoForAddressRange(
object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) {
- DILineInfoTable Lines;
+ DILineInfoTable Lines;
DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
if (!CU)
return Lines;
@@ -1252,8 +1255,10 @@ DILineInfoTable DWARFContext::getLineInfoForAddressRange(
uint32_t StartLine = 0;
std::string StartFileName;
std::string FunctionName(DILineInfo::BadString);
- getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind, Spec.FLIKind,
- FunctionName, StartFileName, StartLine);
+ Optional<uint64_t> StartAddress;
+ getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
+ Spec.FLIKind, FunctionName,
+ StartFileName, StartLine, StartAddress);
// If the Specifier says we don't need FileLineInfo, just
// return the top-most function at the starting address.
@@ -1262,6 +1267,7 @@ DILineInfoTable DWARFContext::getLineInfoForAddressRange(
Result.FunctionName = FunctionName;
Result.StartFileName = StartFileName;
Result.StartLine = StartLine;
+ Result.StartAddress = StartAddress;
Lines.push_back(std::make_pair(Address.Address, Result));
return Lines;
}
@@ -1286,6 +1292,7 @@ DILineInfoTable DWARFContext::getLineInfoForAddressRange(
Result.Column = Row.Column;
Result.StartFileName = StartFileName;
Result.StartLine = StartLine;
+ Result.StartAddress = StartAddress;
Lines.push_back(std::make_pair(Row.Address.Address, Result));
}
@@ -1328,6 +1335,8 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
if (auto DeclLineResult = FunctionDIE.getDeclLine())
Frame.StartLine = DeclLineResult;
Frame.StartFileName = FunctionDIE.getDeclFile(Spec.FLIKind);
+ if (auto LowPcAddr = toSectionedAddress(FunctionDIE.find(DW_AT_low_pc)))
+ Frame.StartAddress = LowPcAddr->Address;
if (Spec.FLIKind != FileLineInfoKind::None) {
if (i == 0) {
// For the topmost frame, initialize the line table of this
@@ -1678,7 +1687,8 @@ public:
// Try to obtain an already relocated version of this section.
// Else use the unrelocated section from the object file. We'll have to
// apply relocations ourselves later.
- section_iterator RelocatedSection = *SecOrErr;
+ section_iterator RelocatedSection =
+ Obj.isRelocatableObject() ? *SecOrErr : Obj.section_end();
if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) {
Expected<StringRef> E = Section.getContents();
if (E)
@@ -1708,6 +1718,9 @@ public:
if (Name == "debug_ranges") {
// FIXME: Use the other dwo range section when we emit it.
RangesDWOSection.Data = Data;
+ } else if (Name == "debug_frame" || Name == "eh_frame") {
+ if (DWARFSection *S = mapNameToDWARFSection(Name))
+ S->Address = Section.getAddress();
}
} else if (InfoSectionMap *Sections =
StringSwitch<InfoSectionMap *>(Name)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
index 4afac2f99503..d91a630256d6 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -67,6 +67,35 @@ DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
return &Decls[AbbrCode - FirstAbbrCode];
}
+std::string DWARFAbbreviationDeclarationSet::getCodeRange() const {
+ // Create a sorted list of all abbrev codes.
+ std::vector<uint32_t> Codes;
+ Codes.reserve(Decls.size());
+ for (const auto &Decl : Decls)
+ Codes.push_back(Decl.getCode());
+
+ std::string Buffer = "";
+ raw_string_ostream Stream(Buffer);
+ // Each iteration through this loop represents a single contiguous range in
+ // the set of codes.
+ for (auto Current = Codes.begin(), End = Codes.end(); Current != End;) {
+ uint32_t RangeStart = *Current;
+ // Add the current range start.
+ Stream << *Current;
+ uint32_t RangeEnd = RangeStart;
+ // Find the end of the current range.
+ while (++Current != End && *Current == RangeEnd + 1)
+ ++RangeEnd;
+ // If there is more than one value in the range, add the range end too.
+ if (RangeStart != RangeEnd)
+ Stream << "-" << RangeEnd;
+ // If there is at least one more range, add a separator.
+ if (Current != End)
+ Stream << ", ";
+ }
+ return Buffer;
+}
+
DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); }
void DWARFDebugAbbrev::clear() {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
index e0db469752cd..1a1b8ea0976f 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -15,7 +15,6 @@
#include <cassert>
#include <cstdint>
#include <set>
-#include <vector>
using namespace llvm;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index b74ecac681f3..92a461dbd941 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -24,8 +24,6 @@
#include <cassert>
#include <cinttypes>
#include <cstdint>
-#include <string>
-#include <vector>
using namespace llvm;
using namespace dwarf;
@@ -43,6 +41,211 @@ static void printRegister(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
OS << "reg" << RegNum;
}
+UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }
+
+UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
+
+UnwindLocation UnwindLocation::createSame() { return {Same}; }
+
+UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
+ return {Constant, InvalidRegisterNumber, Value, None, false};
+}
+
+UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, false};
+}
+
+UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, true};
+}
+
+UnwindLocation
+UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
+}
+
+UnwindLocation
+UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
+}
+
+UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
+ return {Expr, false};
+}
+
+UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {
+ return {Expr, true};
+}
+
+void UnwindLocation::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ if (Dereference)
+ OS << '[';
+ switch (Kind) {
+ case Unspecified:
+ OS << "unspecified";
+ break;
+ case Undefined:
+ OS << "undefined";
+ break;
+ case Same:
+ OS << "same";
+ break;
+ case CFAPlusOffset:
+ OS << "CFA";
+ if (Offset == 0)
+ break;
+ if (Offset > 0)
+ OS << "+";
+ OS << Offset;
+ break;
+ case RegPlusOffset:
+ printRegister(OS, MRI, IsEH, RegNum);
+ if (Offset == 0 && !AddrSpace)
+ break;
+ if (Offset >= 0)
+ OS << "+";
+ OS << Offset;
+ if (AddrSpace)
+ OS << " in addrspace" << *AddrSpace;
+ break;
+ case DWARFExpr:
+ Expr->print(OS, DIDumpOptions(), MRI, nullptr, IsEH);
+ break;
+ case Constant:
+ OS << Offset;
+ break;
+ }
+ if (Dereference)
+ OS << ']';
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const UnwindLocation &UL) {
+ UL.dump(OS, nullptr, false);
+ return OS;
+}
+
+bool UnwindLocation::operator==(const UnwindLocation &RHS) const {
+ if (Kind != RHS.Kind)
+ return false;
+ switch (Kind) {
+ case Unspecified:
+ case Undefined:
+ case Same:
+ return true;
+ case CFAPlusOffset:
+ return Offset == RHS.Offset && Dereference == RHS.Dereference;
+ case RegPlusOffset:
+ return RegNum == RHS.RegNum && Offset == RHS.Offset &&
+ Dereference == RHS.Dereference;
+ case DWARFExpr:
+ return *Expr == *RHS.Expr && Dereference == RHS.Dereference;
+ case Constant:
+ return Offset == RHS.Offset;
+ }
+ return false;
+}
+
+void RegisterLocations::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ bool First = true;
+ for (const auto &RegLocPair : Locations) {
+ if (First)
+ First = false;
+ else
+ OS << ", ";
+ printRegister(OS, MRI, IsEH, RegLocPair.first);
+ OS << '=';
+ RegLocPair.second.dump(OS, MRI, IsEH);
+ }
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const RegisterLocations &RL) {
+ RL.dump(OS, nullptr, false);
+ return OS;
+}
+
+void UnwindRow::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ OS.indent(2 * IndentLevel);
+ if (hasAddress())
+ OS << format("0x%" PRIx64 ": ", *Address);
+ OS << "CFA=";
+ CFAValue.dump(OS, MRI, IsEH);
+ if (RegLocs.hasLocations()) {
+ OS << ": ";
+ RegLocs.dump(OS, MRI, IsEH);
+ }
+ OS << "\n";
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
+ Row.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+void UnwindTable::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ for (const UnwindRow &Row : Rows)
+ Row.dump(OS, MRI, IsEH, IndentLevel);
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
+ Rows.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+Expected<UnwindTable> UnwindTable::create(const FDE *Fde) {
+ const CIE *Cie = Fde->getLinkedCIE();
+ if (Cie == nullptr)
+ return createStringError(errc::invalid_argument,
+ "unable to get CIE for FDE at offset 0x%" PRIx64,
+ Fde->getOffset());
+
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty() && Fde->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ Row.setAddress(Fde->getInitialLocation());
+ UT.EndAddress = Fde->getInitialLocation() + Fde->getAddressRange();
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // We need to save the initial locations of registers from the CIE parsing
+ // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
+ const RegisterLocations InitialLocs = Row.getRegisterLocations();
+ if (Error FdeError = UT.parseRows(Fde->cfis(), Row, &InitialLocs))
+ return std::move(FdeError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
+Expected<UnwindTable> UnwindTable::create(const CIE *Cie) {
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
// See DWARF standard v3, section 7.23
const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
@@ -115,6 +318,16 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
// Operands: SLEB128
addInstruction(Opcode, Data.getSLEB128(C));
break;
+ case DW_CFA_LLVM_def_aspace_cfa:
+ case DW_CFA_LLVM_def_aspace_cfa_sf: {
+ auto RegNum = Data.getULEB128(C);
+ auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa
+ ? Data.getULEB128(C)
+ : Data.getSLEB128(C);
+ auto AddressSpace = Data.getULEB128(C);
+ addInstruction(Opcode, RegNum, CfaOffset, AddressSpace);
+ break;
+ }
case DW_CFA_offset_extended:
case DW_CFA_register:
case DW_CFA_def_cfa:
@@ -175,24 +388,424 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
return C.takeError();
}
-namespace {
+StringRef CFIProgram::callFrameString(unsigned Opcode) const {
+ return dwarf::CallFrameString(Opcode, Arch);
+}
+
+const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) {
+#define ENUM_TO_CSTR(e) \
+ case e: \
+ return #e;
+ switch (OT) {
+ ENUM_TO_CSTR(OT_Unset);
+ ENUM_TO_CSTR(OT_None);
+ ENUM_TO_CSTR(OT_Address);
+ ENUM_TO_CSTR(OT_Offset);
+ ENUM_TO_CSTR(OT_FactoredCodeOffset);
+ ENUM_TO_CSTR(OT_SignedFactDataOffset);
+ ENUM_TO_CSTR(OT_UnsignedFactDataOffset);
+ ENUM_TO_CSTR(OT_Register);
+ ENUM_TO_CSTR(OT_AddressSpace);
+ ENUM_TO_CSTR(OT_Expression);
+ }
+ return "<unknown CFIProgram::OperandType>";
+}
+
+llvm::Expected<uint64_t>
+CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ case OT_SignedFactDataOffset:
+ case OT_UnsignedFactDataOffset:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed "
+ "result, call getOperandAsSigned instead",
+ OperandIdx);
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return Operand;
+
+ case OT_FactoredCodeOffset: {
+ const uint64_t CodeAlignmentFactor = CFIP.codeAlign();
+ if (CodeAlignmentFactor == 0)
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment "
+ "is zero",
+ OperandIdx);
+ return Operand * CodeAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+llvm::Expected<int64_t>
+CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, "
+ "call getOperandAsUnsigned instead",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ return (int64_t)Operand;
+
+ case OT_FactoredCodeOffset:
+ case OT_SignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s but data "
+ "alignment is zero",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+ return int64_t(Operand) * DataAlignmentFactor;
+ }
+
+ case OT_UnsignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32
+ "] has type OT_UnsignedFactDataOffset but data "
+ "alignment is zero",
+ OperandIdx);
+ return Operand * DataAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
+ const RegisterLocations *InitialLocs) {
+ std::vector<RegisterLocations> RegisterStates;
+ for (const CFIProgram::Instruction &Inst : CFIP) {
+ switch (Inst.Opcode) {
+ case dwarf::DW_CFA_set_loc: {
+ // The DW_CFA_set_loc instruction takes a single operand that
+ // represents a target address. The required action is to create a new
+ // table row using the specified address as the location. All other
+ // values in the new row are initially identical to the current row.
+ // The new location value is always greater than the current one. If
+ // the segment_size field of this FDE's CIE is non- zero, the initial
+ // location is preceded by a segment selector of the given length
+ llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!NewAddress)
+ return NewAddress.takeError();
+ if (*NewAddress <= Row.getAddress())
+ return createStringError(
+ errc::invalid_argument,
+ "%s with adrress 0x%" PRIx64 " which must be greater than the "
+ "current row address 0x%" PRIx64,
+ CFIP.callFrameString(Inst.Opcode).str().c_str(), *NewAddress,
+ Row.getAddress());
+ Rows.push_back(Row);
+ Row.setAddress(*NewAddress);
+ break;
+ }
+
+ case dwarf::DW_CFA_advance_loc:
+ case dwarf::DW_CFA_advance_loc1:
+ case dwarf::DW_CFA_advance_loc2:
+ case dwarf::DW_CFA_advance_loc4: {
+ // The DW_CFA_advance instruction takes a single operand that
+ // represents a constant delta. The required action is to create a new
+ // table row with a location value that is computed by taking the
+ // current entry’s location value and adding the value of delta *
+ // code_alignment_factor. All other values in the new row are initially
+ // identical to the current row.
+ Rows.push_back(Row);
+ llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ Row.slideAddress(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_restore:
+ case dwarf::DW_CFA_restore_extended: {
+ // The DW_CFA_restore instruction takes a single operand (encoded with
+ // the opcode) that represents a register number. The required action
+ // is to change the rule for the indicated register to the rule
+ // assigned it by the initial_instructions in the CIE.
+ if (InitialLocs == nullptr)
+ return createStringError(
+ errc::invalid_argument, "%s encountered while parsing a CIE",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Optional<UnwindLocation> O =
+ InitialLocs->getRegisterLocation(*RegNum))
+ Row.getRegisterLocations().setRegisterLocation(*RegNum, *O);
+ else
+ Row.getRegisterLocations().removeRegisterLocation(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_offset:
+ case dwarf::DW_CFA_offset_extended:
+ case dwarf::DW_CFA_offset_extended_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_nop:
+ break;
+
+ case dwarf::DW_CFA_remember_state:
+ RegisterStates.push_back(Row.getRegisterLocations());
+ break;
+
+ case dwarf::DW_CFA_restore_state:
+ if (RegisterStates.empty())
+ return createStringError(errc::invalid_argument,
+ "DW_CFA_restore_state without a matching "
+ "previous DW_CFA_remember_state");
+ Row.getRegisterLocations() = RegisterStates.back();
+ RegisterStates.pop_back();
+ break;
+
+ case dwarf::DW_CFA_GNU_window_save:
+ switch (CFIP.triple()) {
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ case Triple::aarch64_32: {
+ // DW_CFA_GNU_window_save is used for different things on different
+ // architectures. For aarch64 it is known as
+ // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the
+ // value of the return address state between 1 and 0. If there is
+ // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it
+ // should be initially set to 1.
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 1);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(1));
+ }
+ break;
+ }
+
+ case Triple::sparc:
+ case Triple::sparcv9:
+ case Triple::sparcel:
+ for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {
+ Row.getRegisterLocations().setRegisterLocation(
+ RegNum, UnwindLocation::createAtCFAPlusOffset((RegNum - 16) * 8));
+ }
+ break;
+ default: {
+ return createStringError(
+ errc::not_supported,
+ "DW_CFA opcode %#x is not supported for architecture %s",
+ Inst.Opcode, Triple::getArchTypeName(CFIP.triple()).str().c_str());
-} // end anonymous namespace
+ break;
+ }
+ }
+ break;
-ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
- static OperandType OpTypes[DW_CFA_restore+1][2];
+ case dwarf::DW_CFA_undefined: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createUndefined());
+ break;
+ }
+
+ case dwarf::DW_CFA_same_value: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createSame());
+ break;
+ }
+
+ case dwarf::DW_CFA_GNU_args_size:
+ break;
+
+ case dwarf::DW_CFA_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, 1);
+ if (!NewRegNum)
+ return NewRegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsRegisterPlusOffset(*NewRegNum, 0));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_offset:
+ case dwarf::DW_CFA_val_offset_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, 0);
+ else
+ Row.getCFAValue().setRegister(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_offset:
+ case dwarf::DW_CFA_def_cfa_offset_sf: {
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {
+ return createStringError(
+ errc::invalid_argument,
+ "%s found when CFA rule was not RegPlusOffset",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ Row.getCFAValue().setOffset(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa:
+ case dwarf::DW_CFA_def_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, *Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa:
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ llvm::Expected<uint32_t> CFAAddrSpace =
+ Inst.getOperandAsUnsigned(CFIP, 2);
+ if (!CFAAddrSpace)
+ return CFAAddrSpace.takeError();
+ Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
+ *RegNum, *Offset, *CFAAddrSpace);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_expression:
+ Row.getCFAValue() =
+ UnwindLocation::createIsDWARFExpression(*Inst.Expression);
+ break;
+ }
+ }
+ return Error::success();
+}
+
+ArrayRef<CFIProgram::OperandType[CFIProgram::MaxOperands]>
+CFIProgram::getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
static bool Initialized = false;
if (Initialized) {
- return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
}
Initialized = true;
-#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
- do { \
- OpTypes[OP][0] = OPTYPE0; \
- OpTypes[OP][1] = OPTYPE1; \
+#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \
+ do { \
+ OpTypes[OP][0] = OPTYPE0; \
+ OpTypes[OP][1] = OPTYPE1; \
+ OpTypes[OP][2] = OPTYPE2; \
} while (false)
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
+ DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None)
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
@@ -205,6 +818,10 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset,
+ OT_AddressSpace);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register,
+ OT_SignedFactDataOffset, OT_AddressSpace);
DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
@@ -230,7 +847,7 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
#undef DECLARE_OP1
#undef DECLARE_OP2
- return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
}
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
@@ -238,14 +855,14 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const MCRegisterInfo *MRI, bool IsEH,
const Instruction &Instr, unsigned OperandIdx,
uint64_t Operand) const {
- assert(OperandIdx < 2);
+ assert(OperandIdx < MaxOperands);
uint8_t Opcode = Instr.Opcode;
OperandType Type = getOperandTypes()[Opcode][OperandIdx];
switch (Type) {
case OT_Unset: {
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
- auto OpcodeName = CallFrameString(Opcode, Arch);
+ auto OpcodeName = callFrameString(Opcode);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
@@ -285,6 +902,9 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << ' ';
printRegister(OS, MRI, IsEH, Operand);
break;
+ case OT_AddressSpace:
+ OS << format(" in addrspace%" PRId64, Operand);
+ break;
case OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
@@ -298,10 +918,8 @@ void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned IndentLevel) const {
for (const auto &Instr : Instructions) {
uint8_t Opcode = Instr.Opcode;
- if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
- Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
OS.indent(2 * IndentLevel);
- OS << CallFrameString(Opcode, Arch) << ":";
+ OS << callFrameString(Opcode) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, DumpOpts, MRI, IsEH, Instr, i, Instr.Ops[i]);
OS << '\n';
@@ -333,8 +951,10 @@ void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
<< format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8,
getCIEId(IsDWARF64, IsEH))
<< " CIE\n"
- << " Format: " << FormatString(IsDWARF64) << "\n"
- << format(" Version: %d\n", Version)
+ << " Format: " << FormatString(IsDWARF64) << "\n";
+ if (IsEH && Version != 1)
+ OS << "WARNING: unsupported CIE version\n";
+ OS << format(" Version: %d\n", Version)
<< " Augmentation: \"" << Augmentation << "\"\n";
if (Version >= 4) {
OS << format(" Address size: %u\n", (uint32_t)AddressSize);
@@ -355,6 +975,16 @@ void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << "\n";
CFIs.dump(OS, DumpOpts, MRI, IsEH);
OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the CIE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
}
void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
@@ -374,6 +1004,16 @@ void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
CFIs.dump(OS, DumpOpts, MRI, IsEH);
OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the FDE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
}
DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
@@ -434,11 +1074,6 @@ Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint8_t Version = Data.getU8(&Offset);
const char *Augmentation = Data.getCStr(&Offset);
StringRef AugmentationString(Augmentation ? Augmentation : "");
- // TODO: we should provide a way to report a warning and continue dumping.
- if (IsEH && Version != 1)
- return createStringError(errc::not_supported,
- "unsupported CIE version: %" PRIu8, Version);
-
uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
Data.getU8(&Offset);
Data.setAddressSize(AddressSize);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
index 2b7d0c3363a1..7ebb0092c34a 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
@@ -8,6 +8,7 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
@@ -30,17 +31,42 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
uint64_t UEndOffset, uint32_t D) {
Offset = *OffsetPtr;
Depth = D;
- if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
+ if (Offset >= UEndOffset) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. "
+ "tries to read DIEs at offset 0x%8.8" PRIx64,
+ U.getOffset(), U.getNextUnitOffset(), *OffsetPtr));
return false;
+ }
+ assert(DebugInfoData.isValidOffset(UEndOffset - 1));
uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
if (0 == AbbrCode) {
// NULL debug tag entry.
AbbrevDecl = nullptr;
return true;
}
- if (const auto *AbbrevSet = U.getAbbreviations())
- AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode);
- if (nullptr == AbbrevDecl) {
+ const auto *AbbrevSet = U.getAbbreviations();
+ if (!AbbrevSet) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid abbreviation set offset 0x%" PRIx64,
+ U.getOffset(), U.getAbbreviationsOffset()));
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode);
+ if (!AbbrevDecl) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid abbreviation %" PRIu64 " at "
+ "offset 0x%8.8" PRIx64 ", valid abbreviations are %s",
+ U.getOffset(), AbbrCode, *OffsetPtr,
+ AbbrevSet->getCodeRange().c_str()));
// Restore the original offset.
*OffsetPtr = Offset;
return false;
@@ -62,6 +88,11 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
OffsetPtr, U.getFormParams())) {
// We failed to skip this attribute's value, restore the original offset
// and return the failure status.
+ U.getContext().getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid FORM_* 0x%" PRIx16 " at offset 0x%8.8" PRIx64,
+ U.getOffset(), AttrSpec.Form, *OffsetPtr));
*OffsetPtr = Offset;
return false;
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 427f6f4942c3..0501e3ee3f9b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -69,39 +69,43 @@ static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
}
}
-static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
- DWARFUnit *U, unsigned Indent,
- DIDumpOptions DumpOpts) {
+static void dumpLocationList(raw_ostream &OS, const DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ assert(FormValue.isFormClass(DWARFFormValue::FC_SectionOffset) &&
+ "bad FORM for location list");
DWARFContext &Ctx = U->getContext();
const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
- if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
- FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) {
- ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
- DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
- Ctx.isLittleEndian(), 0);
- DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format)
- .print(OS, DumpOpts, MRI, U);
- return;
- }
-
- if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
- uint64_t Offset = *FormValue.getAsSectionOffset();
+ uint64_t Offset = *FormValue.getAsSectionOffset();
- if (FormValue.getForm() == DW_FORM_loclistx) {
- FormValue.dump(OS, DumpOpts);
+ if (FormValue.getForm() == DW_FORM_loclistx) {
+ FormValue.dump(OS, DumpOpts);
- if (auto LoclistOffset = U->getLoclistOffset(Offset))
- Offset = *LoclistOffset;
- else
- return;
- }
- U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(),
- MRI, Ctx.getDWARFObj(), U, DumpOpts,
- Indent);
- return;
+ if (auto LoclistOffset = U->getLoclistOffset(Offset))
+ Offset = *LoclistOffset;
+ else
+ return;
}
+ U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(), MRI,
+ Ctx.getDWARFObj(), U, DumpOpts,
+ Indent);
+ return;
+}
- FormValue.dump(OS, DumpOpts);
+static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ assert((FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+ FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) &&
+ "bad FORM for location expression");
+ DWARFContext &Ctx = U->getContext();
+ const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+ ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+ DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+ Ctx.isLittleEndian(), 0);
+ DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format)
+ .print(OS, DumpOpts, MRI, U);
+ return;
}
/// Dump the name encoded in the type tag.
@@ -230,21 +234,22 @@ static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) {
}
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
- uint64_t *OffsetPtr, dwarf::Attribute Attr,
- dwarf::Form Form, unsigned Indent,
+ const DWARFAttribute &AttrValue, unsigned Indent,
DIDumpOptions DumpOpts) {
if (!Die.isValid())
return;
const char BaseIndent[] = " ";
OS << BaseIndent;
OS.indent(Indent + 2);
+ dwarf::Attribute Attr = AttrValue.Attr;
WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr);
+ dwarf::Form Form = AttrValue.Value.getForm();
if (DumpOpts.Verbose || DumpOpts.ShowForm)
OS << formatv(" [{0}]", Form);
DWARFUnit *U = Die.getDwarfUnit();
- DWARFFormValue FormValue = DWARFFormValue::createFromUnit(Form, U, OffsetPtr);
+ const DWARFFormValue &FormValue = AttrValue.Value;
OS << "\t(";
@@ -288,9 +293,15 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
else
FormValue.dump(OS, DumpOpts);
}
- } else if (Form == dwarf::Form::DW_FORM_exprloc ||
- DWARFAttribute::mayHaveLocationDescription(Attr))
- dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ } else if (DWARFAttribute::mayHaveLocationList(Attr) &&
+ FormValue.isFormClass(DWARFFormValue::FC_SectionOffset))
+ dumpLocationList(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4,
+ DumpOpts);
+ else if (FormValue.isFormClass(DWARFFormValue::FC_Exprloc) ||
+ (DWARFAttribute::mayHaveLocationExpr(Attr) &&
+ FormValue.isFormClass(DWARFFormValue::FC_Block)))
+ dumpLocationExpr(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4,
+ DumpOpts);
else
FormValue.dump(OS, DumpOpts);
@@ -570,11 +581,16 @@ uint64_t DWARFDie::getDeclLine() const {
std::string
DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const {
+ auto D = getAttributeValueAsReferencedDie(DW_AT_abstract_origin);
+ if (!D)
+ D = *this;
std::string FileName;
- if (auto DeclFile = toUnsigned(findRecursively(DW_AT_decl_file))) {
- if (const auto *LT = U->getContext().getLineTableForUnit(U)) {
- LT->getFileNameByIndex(*DeclFile, U->getCompilationDir(), Kind, FileName);
- }
+ if (auto DeclFile = toUnsigned(D.find(DW_AT_decl_file))) {
+ if (const auto *LineTable =
+ getDwarfUnit()->getContext().getLineTableForUnit(
+ D.getDwarfUnit()->getLinkedUnit()))
+ LineTable->getFileNameByIndex(
+ *DeclFile, D.getDwarfUnit()->getCompilationDir(), Kind, FileName);
}
return FileName;
}
@@ -631,25 +647,17 @@ void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
OS << '\n';
// Dump all data in the DIE for the attributes.
- for (const auto &AttrSpec : AbbrevDecl->attributes()) {
- if (AttrSpec.Form == DW_FORM_implicit_const) {
- // We are dumping .debug_info section ,
- // implicit_const attribute values are not really stored here,
- // but in .debug_abbrev section. So we just skip such attrs.
- continue;
- }
- dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form,
- Indent, DumpOpts);
- }
+ for (const DWARFAttribute &AttrValue : attributes())
+ dumpAttribute(OS, *this, AttrValue, Indent, DumpOpts);
- DWARFDie child = getFirstChild();
- if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0 && child) {
+ if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0) {
+ DWARFDie Child = getFirstChild();
DumpOpts.ChildRecurseDepth--;
DIDumpOptions ChildDumpOpts = DumpOpts;
ChildDumpOpts.ShowParents = false;
- while (child) {
- child.dump(OS, Indent + 2, ChildDumpOpts);
- child = child.getSibling();
+ while (Child) {
+ Child.dump(OS, Indent + 2, ChildDumpOpts);
+ Child = Child.getSibling();
}
}
} else {
@@ -723,10 +731,16 @@ void DWARFDie::attribute_iterator::updateForIndex(
// Add the previous byte size of any previous attribute value.
AttrValue.Offset += AttrValue.ByteSize;
uint64_t ParseOffset = AttrValue.Offset;
- auto U = Die.getDwarfUnit();
- assert(U && "Die must have valid DWARF unit");
- AttrValue.Value = DWARFFormValue::createFromUnit(
- AbbrDecl.getFormByIndex(Index), U, &ParseOffset);
+ if (AbbrDecl.getAttrIsImplicitConstByIndex(Index))
+ AttrValue.Value = DWARFFormValue::createFromSValue(
+ AbbrDecl.getFormByIndex(Index),
+ AbbrDecl.getAttrImplicitConstValueByIndex(Index));
+ else {
+ auto U = Die.getDwarfUnit();
+ assert(U && "Die must have valid DWARF unit");
+ AttrValue.Value = DWARFFormValue::createFromUnit(
+ AbbrDecl.getFormByIndex(Index), U, &ParseOffset);
+ }
AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
} else {
assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only");
@@ -740,11 +754,29 @@ DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
return *this;
}
-bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) {
+bool DWARFAttribute::mayHaveLocationList(dwarf::Attribute Attr) {
+ switch(Attr) {
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_static_link:
+ case DW_AT_segment:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) {
switch (Attr) {
// From the DWARF v5 specification.
case DW_AT_location:
case DW_AT_byte_size:
+ case DW_AT_bit_offset:
case DW_AT_bit_size:
case DW_AT_string_length:
case DW_AT_lower_bound:
@@ -760,6 +792,7 @@ bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) {
case DW_AT_vtable_elem_location:
case DW_AT_allocated:
case DW_AT_associated:
+ case DW_AT_data_location:
case DW_AT_byte_stride:
case DW_AT_rank:
case DW_AT_call_value:
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 811716111be5..4b9be85f6885 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -174,7 +174,10 @@ bool DWARFExpression::Operation::extract(DataExtractor Data,
case Operation::WasmLocationArg:
assert(Operand == 1);
switch (Operands[0]) {
- case 0: case 1: case 2:
+ case 0:
+ case 1:
+ case 2:
+ case 4:
Operands[Operand] = Data.getULEB128(&Offset);
break;
case 3: // global as uint32
@@ -294,8 +297,11 @@ bool DWARFExpression::Operation::print(raw_ostream &OS, DIDumpOptions DumpOpts,
} else if (Size == Operation::WasmLocationArg) {
assert(Operand == 1);
switch (Operands[0]) {
- case 0: case 1: case 2:
+ case 0:
+ case 1:
+ case 2:
case 3: // global as uint32
+ case 4:
OS << format(" 0x%" PRIx64, Operands[Operand]);
break;
default: assert(false);
@@ -319,6 +325,10 @@ void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts,
const MCRegisterInfo *RegInfo, DWARFUnit *U,
bool IsEH) const {
uint32_t EntryValExprSize = 0;
+ uint64_t EntryValStartOffset = 0;
+ if (Data.getData().empty())
+ OS << "<empty>";
+
for (auto &Op : *this) {
if (!Op.print(OS, DumpOpts, this, RegInfo, U, IsEH)) {
uint64_t FailOffset = Op.getEndOffset();
@@ -331,11 +341,12 @@ void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts,
Op.getCode() == DW_OP_GNU_entry_value) {
OS << "(";
EntryValExprSize = Op.getRawOperand(0);
+ EntryValStartOffset = Op.getEndOffset();
continue;
}
if (EntryValExprSize) {
- EntryValExprSize--;
+ EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;
if (EntryValExprSize == 0)
OS << ")";
}
@@ -501,4 +512,10 @@ bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) {
return printCompactDWARFExpr(OS, begin(), end(), MRI);
}
+bool DWARFExpression::operator==(const DWARFExpression &RHS) const {
+ if (AddressSize != RHS.AddressSize || Format != RHS.Format)
+ return false;
+ return Data.getData() == RHS.Data.getData();
+}
+
} // namespace llvm
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 7a84605211fb..2244a69bc121 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -74,7 +74,7 @@ static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2
DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3
DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4
-
+ DWARFFormValue::FC_Address, // 0x2001 DW_FORM_addrx_offset
};
DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) {
@@ -168,6 +168,7 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
case DW_FORM_line_strp:
case DW_FORM_GNU_ref_alt:
case DW_FORM_GNU_strp_alt:
+ case DW_FORM_implicit_const:
if (Optional<uint8_t> FixedSize =
dwarf::getFixedFormByteSize(Form, Params)) {
*OffsetPtr += *FixedSize;
@@ -191,6 +192,11 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
DebugInfoData.getULEB128(OffsetPtr);
return true;
+ case DW_FORM_LLVM_addrx_offset:
+ DebugInfoData.getULEB128(OffsetPtr);
+ *OffsetPtr += 4;
+ return true;
+
case DW_FORM_indirect:
Indirect = true;
Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr));
@@ -217,6 +223,8 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
case DW_FORM_GNU_str_index:
case DW_FORM_GNU_strp_alt:
return (FC == FC_String);
+ case DW_FORM_LLVM_addrx_offset:
+ return (FC == FC_Address);
default:
break;
}
@@ -322,6 +330,10 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
case DW_FORM_strx:
Value.uval = Data.getULEB128(OffsetPtr, &Err);
break;
+ case DW_FORM_LLVM_addrx_offset:
+ Value.uval = Data.getULEB128(OffsetPtr, &Err) << 32;
+ Value.uval = Data.getU32(OffsetPtr, &Err);
+ break;
case DW_FORM_string:
Value.cstr = Data.getCStr(OffsetPtr, &Err);
break;
@@ -345,6 +357,9 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
case DW_FORM_ref_sig8:
Value.uval = Data.getU64(OffsetPtr, &Err);
break;
+ case DW_FORM_implicit_const:
+ // Value has been already set by DWARFFormValue::createFromSValue.
+ break;
default:
// DWARFFormValue::skipValue() will have caught this and caused all
// DWARF DIEs to fail to be parsed, so this code is not be reachable.
@@ -417,6 +432,23 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
OS << "<unresolved>";
break;
}
+ case DW_FORM_LLVM_addrx_offset: {
+ if (U == nullptr) {
+ OS << "<invalid dwarf unit>";
+ break;
+ }
+ uint32_t Index = UValue >> 32;
+ uint32_t Offset = UValue & 0xffffffff;
+ Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(Index);
+ if (!A || DumpOpts.Verbose)
+ AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
+ if (A) {
+ A->Address += Offset;
+ dumpSectionedAddress(AddrOS, DumpOpts, *A);
+ } else
+ OS << "<unresolved>";
+ break;
+ }
case DW_FORM_flag_present:
OS << "true";
break;
@@ -482,6 +514,7 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
break;
case DW_FORM_sdata:
+ case DW_FORM_implicit_const:
OS << Value.sval;
break;
case DW_FORM_udata:
@@ -636,13 +669,17 @@ Optional<object::SectionedAddress>
DWARFFormValue::getAsSectionedAddress() const {
if (!isFormClass(FC_Address))
return None;
- if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) {
- uint32_t Index = Value.uval;
+ bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;
+ if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) {
+
+ uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval;
if (!U)
return None;
Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index);
if (!SA)
return None;
+ if (AddrOffset)
+ SA->Address += (Value.uval & 0xffffffff);
return SA;
}
return {{Value.uval, Value.SectionIndex}};
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 8493950a29b2..f17dacfce665 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -192,17 +192,18 @@ DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const {
Optional<object::SectionedAddress>
DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const {
- if (IsDWO) {
+ if (!AddrOffsetSectionBase) {
auto R = Context.info_section_units();
// Surprising if a DWO file has more than one skeleton unit in it - this
// probably shouldn't be valid, but if a use case is found, here's where to
// support it (probably have to linearly search for the matching skeleton CU
// here)
- if (hasSingleElement(R))
+ if (IsDWO && hasSingleElement(R))
return (*R.begin())->getAddrOffsetSectionItem(Index);
- }
- if (!AddrOffsetSectionBase)
+
return None;
+ }
+
uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize();
if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
return None;
@@ -258,26 +259,73 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
} else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
DWOId = debug_info.getU64(offset_ptr, &Err);
- if (errorToBool(std::move(Err)))
+ if (Err) {
+ Context.getWarningHandler()(joinErrors(
+ createStringError(
+ errc::invalid_argument,
+ "DWARF unit at 0x%8.8" PRIx64 " cannot be parsed:", Offset),
+ std::move(Err)));
return false;
+ }
// Header fields all parsed, capture the size of this unit header.
assert(*offset_ptr - Offset <= 255 && "unexpected header size");
Size = uint8_t(*offset_ptr - Offset);
+ uint64_t NextCUOffset = Offset + getUnitLengthFieldByteSize() + getLength();
+
+ if (!debug_info.isValidOffset(getNextUnitOffset() - 1)) {
+ Context.getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. "
+ "extends past section size 0x%8.8zx",
+ Offset, NextCUOffset, debug_info.size()));
+ return false;
+ }
+
+ if (!DWARFContext::isSupportedVersion(getVersion())) {
+ Context.getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "has unsupported version %" PRIu16 ", supported are 2-%u",
+ Offset, getVersion(), DWARFContext::getMaxSupportedVersion()));
+ return false;
+ }
// Type offset is unit-relative; should be after the header and before
// the end of the current unit.
- bool TypeOffsetOK =
- !isTypeUnit()
- ? true
- : TypeOffset >= Size &&
- TypeOffset < getLength() + getUnitLengthFieldByteSize();
- bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
- bool VersionOK = DWARFContext::isSupportedVersion(getVersion());
- bool AddrSizeOK = DWARFContext::isAddressSizeSupported(getAddressByteSize());
+ if (isTypeUnit() && TypeOffset < Size) {
+ Context.getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF type unit at offset "
+ "0x%8.8" PRIx64 " "
+ "has its relocated type_offset 0x%8.8" PRIx64 " "
+ "pointing inside the header",
+ Offset, Offset + TypeOffset));
+ return false;
+ }
+ if (isTypeUnit() &&
+ TypeOffset >= getUnitLengthFieldByteSize() + getLength()) {
+ Context.getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF type unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. has its "
+ "relocated type_offset 0x%8.8" PRIx64 " pointing past the unit end",
+ Offset, NextCUOffset, Offset + TypeOffset));
+ return false;
+ }
- if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK)
+ if (!DWARFContext::isAddressSizeSupported(getAddressByteSize())) {
+ SmallVector<std::string, 3> Sizes;
+ for (auto Size : DWARFContext::getSupportedAddressSizes())
+ Sizes.push_back(std::to_string(Size));
+ Context.getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "has unsupported address size %" PRIu8 ", supported are %s",
+ Offset, getAddressByteSize(), llvm::join(Sizes, ", ").c_str()));
return false;
+ }
// Keep track of the highest DWARF version we encounter across all units.
Context.setMaxVersionIfGreater(getVersion());
@@ -340,6 +388,7 @@ void DWARFUnit::clear() {
RangeSectionBase = 0;
LocSectionBase = 0;
AddrOffsetSectionBase = None;
+ SU = nullptr;
clearDIEs(false);
DWO.reset();
}
@@ -360,6 +409,8 @@ void DWARFUnit::extractDIEsToVector(
uint64_t NextCUOffset = getNextUnitOffset();
DWARFDebugInfoEntry DIE;
DWARFDataExtractor DebugInfoData = getDebugInfoExtractor();
+ // The end offset has been already checked by DWARFUnitHeader::extract.
+ assert(DebugInfoData.isValidOffset(NextCUOffset - 1));
uint32_t Depth = 0;
bool IsCUDie = true;
@@ -384,6 +435,8 @@ void DWARFUnit::extractDIEsToVector(
// Normal DIE
if (AbbrDecl->hasChildren())
++Depth;
+ else if (Depth == 0)
+ break; // This unit has a single DIE with no children.
} else {
// NULL DIE.
if (Depth > 0)
@@ -392,17 +445,6 @@ void DWARFUnit::extractDIEsToVector(
break; // We are done with this compile unit!
}
}
-
- // Give a little bit of info if we encounter corrupt DWARF (our offset
- // should always terminate at or before the start of the next compilation
- // unit header).
- if (DIEOffset > NextCUOffset)
- Context.getWarningHandler()(
- createStringError(errc::invalid_argument,
- "DWARF compile unit extends beyond its "
- "bounds cu 0x%8.8" PRIx64 " "
- "at 0x%8.8" PRIx64 "\n",
- getOffset(), DIEOffset));
}
void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
@@ -545,13 +587,11 @@ bool DWARFUnit::parseDWO() {
if (!DWOCU)
return false;
DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
+ DWO->setSkeletonUnit(this);
// Share .debug_addr and .debug_ranges section with compile unit in .dwo
if (AddrOffsetSectionBase)
DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase);
- if (getVersion() >= 5) {
- DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(),
- DWARFListTableHeader::getHeaderSize(getFormat()));
- } else {
+ if (getVersion() == 4) {
auto DWORangesBase = UnitDie.getRangesBaseAttribute();
DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
}
@@ -688,15 +728,15 @@ DWARFUnit::getInlinedChainForAddress(uint64_t Address,
DWARFDie SubroutineDIE =
(DWO ? *DWO : *this).getSubroutineForAddress(Address);
- if (!SubroutineDIE)
- return;
-
- while (!SubroutineDIE.isSubprogramDIE()) {
+ while (SubroutineDIE) {
+ if (SubroutineDIE.isSubprogramDIE()) {
+ InlinedChain.push_back(SubroutineDIE);
+ return;
+ }
if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine)
InlinedChain.push_back(SubroutineDIE);
SubroutineDIE = SubroutineDIE.getParent();
}
- InlinedChain.push_back(SubroutineDIE);
}
const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context,
@@ -793,7 +833,7 @@ DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) {
const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
if (!Abbrevs)
- Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(getAbbreviationsOffset());
return Abbrevs;
}