Importing rustc-1.56.0
Change-Id: I98941481270706fa55f8fb2cb91686ae3bd30f38
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
index 13baa5f..48cbad0 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -45,5 +45,4 @@
LINK_COMPONENTS
Support
- DebugInfoMSF
)
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
index 69390c7..d12f6c7 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -9,6 +9,7 @@
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include <string>
using namespace llvm;
using namespace llvm::codeview;
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
index c272985..1af59ff 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -188,14 +188,17 @@
Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) {
if (isStreaming()) {
+ // FIXME: We also need to handle big values here, but it's
+ // not clear how we can excercise this code path yet.
if (Value.isSigned())
emitEncodedSignedInteger(Value.getSExtValue(), Comment);
else
emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);
} else if (isWriting()) {
if (Value.isSigned())
- return writeEncodedSignedInteger(Value.getSExtValue());
- return writeEncodedUnsignedInteger(Value.getZExtValue());
+ return writeEncodedSignedInteger(
+ Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN);
+ return writeEncodedUnsignedInteger(Value.getLimitedValue());
} else
return consume(*Reader, Value);
return Error::success();
@@ -273,6 +276,9 @@
void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
const Twine &Comment) {
+ // FIXME: There are no test cases covering this function.
+ // This may be because we always consider enumerators to be unsigned.
+ // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum.
if (Value >= std::numeric_limits<int8_t>::min()) {
Streamer->emitIntValue(LF_CHAR, 2);
emitComment(Comment);
@@ -291,8 +297,8 @@
} else {
Streamer->emitIntValue(LF_QUADWORD, 2);
emitComment(Comment);
- Streamer->emitIntValue(Value, 4);
- incrStreamedLen(6);
+ Streamer->emitIntValue(Value, 4); // FIXME: Why not 8 (size of quadword)?
+ incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
}
}
@@ -313,10 +319,11 @@
Streamer->emitIntValue(Value, 4);
incrStreamedLen(6);
} else {
+ // FIXME: There are no test cases covering this block.
Streamer->emitIntValue(LF_UQUADWORD, 2);
emitComment(Comment);
Streamer->emitIntValue(Value, 8);
- incrStreamedLen(6);
+ incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
}
}
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/src/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
index 949707b..b4a2a00 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -189,7 +189,6 @@
CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
CV_ENUM_CLASS_ENT(CPUType, ARM7),
- CV_ENUM_CLASS_ENT(CPUType, ARM64),
CV_ENUM_CLASS_ENT(CPUType, Omni),
CV_ENUM_CLASS_ENT(CPUType, Ia64),
CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
@@ -201,6 +200,10 @@
CV_ENUM_CLASS_ENT(CPUType, EBC),
CV_ENUM_CLASS_ENT(CPUType, Thumb),
CV_ENUM_CLASS_ENT(CPUType, ARMNT),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64),
+ CV_ENUM_CLASS_ENT(CPUType, HybridX86ARM64),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64EC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64X),
CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
};
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp b/src/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp
index a7a8c7f..f1f51bc 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp
@@ -23,21 +23,33 @@
GuidAdapter::GuidAdapter(ArrayRef<uint8_t> Guid)
: FormatAdapter(std::move(Guid)) {}
+// From https://docs.microsoft.com/en-us/windows/win32/msi/guid documentation:
+// The GUID data type is a text string representing a Class identifier (ID).
+// All GUIDs must be authored in uppercase.
+// The valid format for a GUID is {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} where
+// X is a hex digit (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F).
+//
+// The individual string components must be padded to comply with the specific
+// lengths of {8-4-4-4-12} characters.
+// The llvm-yaml2obj tool checks that a GUID follow that format:
+// - the total length to be 38 (including the curly braces.
+// - there is a dash at the positions: 8, 13, 18 and 23.
void GuidAdapter::format(raw_ostream &Stream, StringRef Style) {
- static const char *Lookup = "0123456789ABCDEF";
-
assert(Item.size() == 16 && "Expected 16-byte GUID");
- Stream << "{";
- for (int i = 0; i < 16;) {
- uint8_t Byte = Item[i];
- uint8_t HighNibble = (Byte >> 4) & 0xF;
- uint8_t LowNibble = Byte & 0xF;
- Stream << Lookup[HighNibble] << Lookup[LowNibble];
- ++i;
- if (i >= 4 && i <= 10 && i % 2 == 0)
- Stream << "-";
- }
- Stream << "}";
+ struct MSGuid {
+ support::ulittle32_t Data1;
+ support::ulittle16_t Data2;
+ support::ulittle16_t Data3;
+ support::ubig64_t Data4;
+ };
+ const MSGuid *G = reinterpret_cast<const MSGuid *>(Item.data());
+ Stream
+ << '{' << format_hex_no_prefix(G->Data1, 8, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data2, 4, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data3, 4, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data4 >> 48, 4, /*Upper=*/true) << '-'
+ << format_hex_no_prefix(G->Data4 & ((1ULL << 48) - 1), 12, /*Upper=*/true)
+ << '}';
}
raw_ostream &llvm::codeview::operator<<(raw_ostream &OS, const GUID &Guid) {
diff --git a/src/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/src/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index 7ac3761..d272999 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -8,7 +8,9 @@
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/MD5.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -144,28 +146,51 @@
};
} // namespace
+// Computes a string representation of a hash of the specified name, suitable
+// for use when emitting CodeView type names.
+static void computeHashString(StringRef Name,
+ SmallString<32> &StringifiedHash) {
+ llvm::MD5 Hash;
+ llvm::MD5::MD5Result Result;
+ Hash.update(Name);
+ Hash.final(Result);
+ Hash.stringifyResult(Result, StringifiedHash);
+}
+
static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
StringRef &UniqueName, bool HasUniqueName) {
if (IO.isWriting()) {
// Try to be smart about what we write here. We can't write anything too
- // large, so if we're going to go over the limit, truncate both the name
- // and unique name by the same amount.
+ // large, so if we're going to go over the limit, replace lengthy names with
+ // a stringified hash value.
size_t BytesLeft = IO.maxFieldLength();
if (HasUniqueName) {
size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
- StringRef N = Name;
- StringRef U = UniqueName;
if (BytesNeeded > BytesLeft) {
- size_t BytesToDrop = (BytesNeeded - BytesLeft);
- size_t DropN = std::min(N.size(), BytesToDrop / 2);
- size_t DropU = std::min(U.size(), BytesToDrop - DropN);
+ // The minimum space required for emitting hashes of both names.
+ assert(BytesLeft >= 70);
- N = N.drop_back(DropN);
- U = U.drop_back(DropU);
+ // Replace the entire unique name with a hash of the unique name.
+ SmallString<32> Hash;
+ computeHashString(UniqueName, Hash);
+ std::string UniqueB = Twine("??@" + Hash + "@").str();
+ assert(UniqueB.size() == 36);
+
+ // Truncate the name if necessary and append a hash of the name.
+ // The name length, hash included, is limited to 4096 bytes.
+ const size_t MaxTakeN = 4096;
+ size_t TakeN = std::min(MaxTakeN, BytesLeft - UniqueB.size() - 2) - 32;
+ computeHashString(Name, Hash);
+ std::string NameB = (Name.take_front(TakeN) + Hash).str();
+
+ StringRef N = NameB;
+ StringRef U = UniqueB;
+ error(IO.mapStringZ(N));
+ error(IO.mapStringZ(U));
+ } else {
+ error(IO.mapStringZ(Name));
+ error(IO.mapStringZ(UniqueName));
}
-
- error(IO.mapStringZ(N));
- error(IO.mapStringZ(U));
} else {
// Cap the length of the string at however many bytes we have available,
// plus one for the required null terminator.
diff --git a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
index 2b08120..6e30309 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -26,7 +26,8 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 749d738..4e1cafe 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -823,6 +823,8 @@
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 @@
// 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 @@
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 @@
break;
}
- for (auto Child : DIE)
- Worklist.push_back(Child);
+ append_range(Worklist, DIE);
}
return Result;
@@ -1031,13 +1035,11 @@
/// 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 @@
StartLine = DeclLineResult;
FoundResult = true;
}
-
+ if (auto LowPcAddr = toSectionedAddress(DIE.find(DW_AT_low_pc)))
+ StartAddress = LowPcAddr->Address;
return FoundResult;
}
@@ -1229,9 +1232,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
index 4afac2f..d91a630 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -67,6 +67,35 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
index e0db469..1a1b8ea 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -15,7 +15,6 @@
#include <cassert>
#include <cstdint>
#include <set>
-#include <vector>
using namespace llvm;
diff --git a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index b74ecac..92a461d 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/src/llvm-project/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 @@
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 @@
// 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 @@
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>";
+}
-} // end anonymous namespace
+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));
-ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
- static OperandType OpTypes[DW_CFA_restore+1][2];
+ 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());
+
+ break;
+ }
+ }
+ break;
+
+ 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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
<< 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 @@
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 @@
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 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
index 2b7d0c3..7ebb009 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
+++ b/src/llvm-project/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 @@
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 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 5a55f3a..0501e3e 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -69,39 +69,43 @@
}
}
-static void dumpLocation(raw_ostream &OS, const 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;
+ uint64_t Offset = *FormValue.getAsSectionOffset();
+
+ 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 (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
- uint64_t Offset = *FormValue.getAsSectionOffset();
-
- 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;
- }
-
- 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.
@@ -289,9 +293,15 @@
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);
@@ -571,11 +581,16 @@
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;
}
@@ -635,14 +650,14 @@
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 {
@@ -739,11 +754,29 @@
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:
@@ -759,6 +792,7 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index 8117161..4b9be85 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -174,7 +174,10 @@
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 @@
} 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 @@
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 @@
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 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 2559765..2244a69 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -74,7 +74,7 @@
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) {
@@ -192,6 +192,11 @@
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));
@@ -218,6 +223,8 @@
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;
}
@@ -323,6 +330,10 @@
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;
@@ -421,6 +432,23 @@
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;
@@ -641,13 +669,17 @@
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/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 8493950..f17dacf 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -192,17 +192,18 @@
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 @@
} 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 (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK)
+ 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 (!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 @@
RangeSectionBase = 0;
LocSectionBase = 0;
AddrOffsetSectionBase = None;
+ SU = nullptr;
clearDIEs(false);
DWO.reset();
}
@@ -360,6 +409,8 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
if (!Abbrevs)
- Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(getAbbreviationsOffset());
return Abbrevs;
}
diff --git a/src/llvm-project/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/src/llvm-project/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 1e527ab..cdea0e3 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -310,8 +310,10 @@
// so break out after printing a warning.
auto FirstLE = FI.OptLineTable->first();
if (FirstLE && *FirstLE == LE) {
- Log << "warning: duplicate line table detected for DIE:\n";
- Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ if (!Gsym.isQuiet()) {
+ Log << "warning: duplicate line table detected for DIE:\n";
+ Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ }
} else {
// Print out (ignore if os == nulls as this is expensive)
Log << "error: line table has addresses that do not "
@@ -390,11 +392,14 @@
// and the debug info wasn't able to be stripped from the DWARF. If
// the LowPC isn't zero or -1, then we should emit an error.
if (Range.LowPC != 0) {
- // Unexpected invalid address, emit an error
- Log << "warning: DIE has an address range whose start address is "
- "not in any executable sections (" <<
- *Gsym.GetValidTextRanges() << ") and will not be processed:\n";
- Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ if (!Gsym.isQuiet()) {
+ // Unexpected invalid address, emit a warning
+ Log << "warning: DIE has an address range whose start address is "
+ "not in any executable sections ("
+ << *Gsym.GetValidTextRanges()
+ << ") and will not be processed:\n";
+ Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ }
}
break;
}
diff --git a/src/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/src/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 2001478..1c20a59 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -20,13 +20,12 @@
using namespace llvm;
using namespace gsym;
-
-GsymCreator::GsymCreator() : StrTab(StringTableBuilder::ELF) {
+GsymCreator::GsymCreator(bool Quiet)
+ : StrTab(StringTableBuilder::ELF), Quiet(Quiet) {
insertFile(StringRef());
}
-uint32_t GsymCreator::insertFile(StringRef Path,
- llvm::sys::path::Style Style) {
+uint32_t GsymCreator::insertFile(StringRef Path, llvm::sys::path::Style Style) {
llvm::StringRef directory = llvm::sys::path::parent_path(Path, Style);
llvm::StringRef filename = llvm::sys::path::filename(Path, Style);
// We must insert the strings first, then call the FileEntry constructor.
@@ -37,7 +36,7 @@
const uint32_t Base = insertString(filename);
FileEntry FE(Dir, Base);
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
const auto NextIndex = Files.size();
// Find FE in hash map and insert if not present.
auto R = FileEntryToIndex.insert(std::make_pair(FE, NextIndex));
@@ -57,7 +56,7 @@
}
llvm::Error GsymCreator::encode(FileWriter &O) const {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
if (Funcs.empty())
return createStringError(std::errc::invalid_argument,
"no functions to encode");
@@ -69,7 +68,8 @@
return createStringError(std::errc::invalid_argument,
"too many FunctionInfos");
- const uint64_t MinAddr = BaseAddress ? *BaseAddress : Funcs.front().startAddress();
+ const uint64_t MinAddr =
+ BaseAddress ? *BaseAddress : Funcs.front().startAddress();
const uint64_t MaxAddr = Funcs.back().startAddress();
const uint64_t AddrDelta = MaxAddr - MinAddr;
Header Hdr;
@@ -80,7 +80,7 @@
Hdr.BaseAddress = MinAddr;
Hdr.NumAddresses = static_cast<uint32_t>(Funcs.size());
Hdr.StrtabOffset = 0; // We will fix this up later.
- Hdr.StrtabSize = 0; // We will fix this up later.
+ Hdr.StrtabSize = 0; // We will fix this up later.
memset(Hdr.UUID, 0, sizeof(Hdr.UUID));
if (UUID.size() > sizeof(Hdr.UUID))
return createStringError(std::errc::invalid_argument,
@@ -106,11 +106,19 @@
O.alignTo(Hdr.AddrOffSize);
for (const auto &FuncInfo : Funcs) {
uint64_t AddrOffset = FuncInfo.startAddress() - Hdr.BaseAddress;
- switch(Hdr.AddrOffSize) {
- case 1: O.writeU8(static_cast<uint8_t>(AddrOffset)); break;
- case 2: O.writeU16(static_cast<uint16_t>(AddrOffset)); break;
- case 4: O.writeU32(static_cast<uint32_t>(AddrOffset)); break;
- case 8: O.writeU64(AddrOffset); break;
+ switch (Hdr.AddrOffSize) {
+ case 1:
+ O.writeU8(static_cast<uint8_t>(AddrOffset));
+ break;
+ case 2:
+ O.writeU16(static_cast<uint16_t>(AddrOffset));
+ break;
+ case 4:
+ O.writeU32(static_cast<uint32_t>(AddrOffset));
+ break;
+ case 8:
+ O.writeU64(AddrOffset);
+ break;
}
}
@@ -127,12 +135,11 @@
assert(Files[0].Base == 0);
size_t NumFiles = Files.size();
if (NumFiles > UINT32_MAX)
- return createStringError(std::errc::invalid_argument,
- "too many files");
+ return createStringError(std::errc::invalid_argument, "too many files");
O.writeU32(static_cast<uint32_t>(NumFiles));
- for (auto File: Files) {
- O.writeU32(File.Dir);
- O.writeU32(File.Base);
+ for (auto File : Files) {
+ O.writeU32(File.Dir);
+ O.writeU32(File.Base);
}
// Write out the sting table.
@@ -144,9 +151,9 @@
// Write out the address infos for each function info.
for (const auto &FuncInfo : Funcs) {
if (Expected<uint64_t> OffsetOrErr = FuncInfo.encode(O))
- AddrInfoOffsets.push_back(OffsetOrErr.get());
+ AddrInfoOffsets.push_back(OffsetOrErr.get());
else
- return OffsetOrErr.takeError();
+ return OffsetOrErr.takeError();
}
// Fixup the string table offset and size in the header
O.fixup32((uint32_t)StrtabOffset, offsetof(Header, StrtabOffset));
@@ -154,18 +161,37 @@
// Fixup all address info offsets
uint64_t Offset = 0;
- for (auto AddrInfoOffset: AddrInfoOffsets) {
+ for (auto AddrInfoOffset : AddrInfoOffsets) {
O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset + Offset);
Offset += 4;
}
return ErrorSuccess();
}
+// Similar to std::remove_if, but the predicate is binary and it is passed both
+// the previous and the current element.
+template <class ForwardIt, class BinaryPredicate>
+static ForwardIt removeIfBinary(ForwardIt FirstIt, ForwardIt LastIt,
+ BinaryPredicate Pred) {
+ if (FirstIt != LastIt) {
+ auto PrevIt = FirstIt++;
+ FirstIt = std::find_if(FirstIt, LastIt, [&](const auto &Curr) {
+ return Pred(*PrevIt++, Curr);
+ });
+ if (FirstIt != LastIt)
+ for (ForwardIt CurrIt = FirstIt; ++CurrIt != LastIt;)
+ if (!Pred(*PrevIt, *CurrIt)) {
+ PrevIt = FirstIt;
+ *FirstIt++ = std::move(*CurrIt);
+ }
+ }
+ return FirstIt;
+}
+
llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
if (Finalized)
- return createStringError(std::errc::invalid_argument,
- "already finalized");
+ return createStringError(std::errc::invalid_argument, "already finalized");
Finalized = true;
// Sort function infos so we can emit sorted functions.
@@ -195,55 +221,68 @@
// we wouldn't find any function for range (end of Y, end of X)
// with binary search
auto NumBefore = Funcs.size();
- auto Curr = Funcs.begin();
- auto Prev = Funcs.end();
- while (Curr != Funcs.end()) {
- // Can't check for overlaps or same address ranges if we don't have a
- // previous entry
- if (Prev != Funcs.end()) {
- if (Prev->Range.intersects(Curr->Range)) {
- // Overlapping address ranges.
- if (Prev->Range == Curr->Range) {
- // Same address range. Check if one is from debug info and the other
- // is from a symbol table. If so, then keep the one with debug info.
- // Our sorting guarantees that entries with matching address ranges
- // that have debug info are last in the sort.
- if (*Prev == *Curr) {
- // FunctionInfo entries match exactly (range, lines, inlines)
- OS << "warning: duplicate function info entries for range: "
- << Curr->Range << '\n';
- Curr = Funcs.erase(Prev);
- } else {
- if (!Prev->hasRichInfo() && Curr->hasRichInfo()) {
- // Same address range, one with no debug info (symbol) and the
- // next with debug info. Keep the latter.
- Curr = Funcs.erase(Prev);
- } else {
- OS << "warning: same address range contains different debug "
- << "info. Removing:\n"
- << *Prev << "\nIn favor of this one:\n"
- << *Curr << "\n";
- Curr = Funcs.erase(Prev);
- }
- }
- } else {
- // print warnings about overlaps
- OS << "warning: function ranges overlap:\n"
- << *Prev << "\n"
- << *Curr << "\n";
- }
- } else if (Prev->Range.size() == 0 &&
- Curr->Range.contains(Prev->Range.Start)) {
- OS << "warning: removing symbol:\n"
- << *Prev << "\nKeeping:\n"
- << *Curr << "\n";
- Curr = Funcs.erase(Prev);
- }
- }
- if (Curr == Funcs.end())
- break;
- Prev = Curr++;
- }
+ Funcs.erase(
+ removeIfBinary(Funcs.begin(), Funcs.end(),
+ [&](const auto &Prev, const auto &Curr) {
+ // Empty ranges won't intersect, but we still need to
+ // catch the case where we have multiple symbols at the
+ // same address and coalesce them.
+ const bool ranges_equal = Prev.Range == Curr.Range;
+ if (ranges_equal || Prev.Range.intersects(Curr.Range)) {
+ // Overlapping ranges or empty identical ranges.
+ if (ranges_equal) {
+ // Same address range. Check if one is from debug
+ // info and the other is from a symbol table. If
+ // so, then keep the one with debug info. Our
+ // sorting guarantees that entries with matching
+ // address ranges that have debug info are last in
+ // the sort.
+ if (Prev == Curr) {
+ // FunctionInfo entries match exactly (range,
+ // lines, inlines)
+
+ // We used to output a warning here, but this was
+ // so frequent on some binaries, in particular
+ // when those were built with GCC, that it slowed
+ // down processing extremely.
+ return true;
+ } else {
+ if (!Prev.hasRichInfo() && Curr.hasRichInfo()) {
+ // Same address range, one with no debug info
+ // (symbol) and the next with debug info. Keep
+ // the latter.
+ return true;
+ } else {
+ if (!Quiet) {
+ OS << "warning: same address range contains "
+ "different debug "
+ << "info. Removing:\n"
+ << Prev << "\nIn favor of this one:\n"
+ << Curr << "\n";
+ }
+ return true;
+ }
+ }
+ } else {
+ if (!Quiet) { // print warnings about overlaps
+ OS << "warning: function ranges overlap:\n"
+ << Prev << "\n"
+ << Curr << "\n";
+ }
+ }
+ } else if (Prev.Range.size() == 0 &&
+ Curr.Range.contains(Prev.Range.Start)) {
+ if (!Quiet) {
+ OS << "warning: removing symbol:\n"
+ << Prev << "\nKeeping:\n"
+ << Curr << "\n";
+ }
+ return true;
+ }
+
+ return false;
+ }),
+ Funcs.end());
// If our last function info entry doesn't have a size and if we have valid
// text ranges, we should set the size of the last entry since any search for
@@ -251,8 +290,8 @@
// help ensure we don't cause lookups to always return the last symbol that
// has no size when doing lookups.
if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
- if (auto Range = ValidTextRanges->getRangeThatContains(
- Funcs.back().Range.Start)) {
+ if (auto Range =
+ ValidTextRanges->getRangeThatContains(Funcs.back().Range.Start)) {
Funcs.back().Range.End = Range->End;
}
}
@@ -264,7 +303,10 @@
uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
if (S.empty())
return 0;
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+
+ // The hash can be calculated outside the lock.
+ CachedHashStringRef CHStr(S);
+ std::lock_guard<std::mutex> Guard(Mutex);
if (Copy) {
// We need to provide backing storage for the string if requested
// since StringTableBuilder stores references to strings. Any string
@@ -272,22 +314,22 @@
// copied, but any string created by code will need to be copied.
// This allows GsymCreator to be really fast when parsing DWARF and
// other object files as most strings don't need to be copied.
- CachedHashStringRef CHStr(S);
if (!StrTab.contains(CHStr))
- S = StringStorage.insert(S).first->getKey();
+ CHStr = CachedHashStringRef{StringStorage.insert(S).first->getKey(),
+ CHStr.hash()};
}
- return StrTab.add(S);
+ return StrTab.add(CHStr);
}
void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
Ranges.insert(FI.Range);
- Funcs.emplace_back(FI);
+ Funcs.emplace_back(std::move(FI));
}
void GsymCreator::forEachFunctionInfo(
std::function<bool(FunctionInfo &)> const &Callback) {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
for (auto &FI : Funcs) {
if (!Callback(FI))
break;
@@ -296,15 +338,15 @@
void GsymCreator::forEachFunctionInfo(
std::function<bool(const FunctionInfo &)> const &Callback) const {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
for (const auto &FI : Funcs) {
if (!Callback(FI))
break;
}
}
-size_t GsymCreator::getNumFunctionInfos() const{
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+size_t GsymCreator::getNumFunctionInfos() const {
+ std::lock_guard<std::mutex> Guard(Mutex);
return Funcs.size();
}
@@ -315,6 +357,6 @@
}
bool GsymCreator::hasFunctionInfoForAddress(uint64_t Addr) const {
- std::lock_guard<std::recursive_mutex> Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
return Ranges.contains(Addr);
}
diff --git a/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp b/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
index f946dd4..1a92e2c 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
@@ -15,6 +15,7 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FormatVariadic.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -341,7 +342,18 @@
Layout = std::move(*L);
- uint64_t FileSize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
+ uint64_t FileSize = uint64_t(Layout.SB->BlockSize) * Layout.SB->NumBlocks;
+ if (FileSize > UINT32_MAX) {
+ // FIXME: Changing the BinaryStream classes to use 64-bit numbers lets
+ // us create PDBs larger than 4 GiB successfully. The file format is
+ // block-based and as long as each stream is small enough, PDBs larger than
+ // 4 GiB might work. Check if tools can handle these large PDBs, and if so
+ // add support for writing them.
+ return make_error<MSFError>(
+ msf_error_code::size_overflow,
+ formatv("File size would have been {0,1:N}", FileSize));
+ }
+
auto OutFileOrError = FileOutputBuffer::create(Path, FileSize);
if (auto EC = OutFileOrError.takeError())
return std::move(EC);
diff --git a/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFError.cpp b/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFError.cpp
index b368b80..e42157e 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFError.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/MSF/MSFError.cpp
@@ -9,6 +9,7 @@
#include "llvm/DebugInfo/MSF/MSFError.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include <string>
using namespace llvm;
using namespace llvm::msf;
@@ -27,6 +28,8 @@
case msf_error_code::insufficient_buffer:
return "The buffer is not large enough to read the requested number of "
"bytes.";
+ case msf_error_code::size_overflow:
+ return "Output data is larger than 4 GiB.";
case msf_error_code::not_writable:
return "The specified stream is not writable.";
case msf_error_code::no_stream:
diff --git a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
index 52df26b..9084e68 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
@@ -156,14 +156,14 @@
size_t RS = S2.size();
// Shorter strings always compare less than longer strings.
if (LS != RS)
- return LS - RS;
+ return (LS > RS) - (LS < RS);
// If either string contains non ascii characters, memcmp them.
if (LLVM_UNLIKELY(!isAsciiString(S1) || !isAsciiString(S2)))
return memcmp(S1.data(), S2.data(), LS);
// Both strings are ascii, perform a case-insensitive comparison.
- return S1.compare_lower(S2.data());
+ return S1.compare_insensitive(S2.data());
}
void GSIStreamBuilder::finalizePublicBuckets() {
diff --git a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
index 5d7946c..7212a0e 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -83,7 +83,7 @@
static Expected<std::unique_ptr<PDBFile>>
loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
- MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
+ MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
/*RequiresNullTerminator=*/false);
if (!ErrorOrBuffer)
return make_error<RawError>(ErrorOrBuffer.getError());
diff --git a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
index deb0f20..a508f16 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
diff --git a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index 01dc31d..555d29f 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -30,127 +30,368 @@
namespace llvm {
namespace symbolize {
-// Prints source code around in the FileName the Line.
-void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
- if (PrintSourceContext <= 0)
- return;
+class SourceCode {
+ std::unique_ptr<MemoryBuffer> MemBuf;
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(FileName);
- if (!BufOrErr)
- return;
+ const Optional<StringRef> load(StringRef FileName,
+ const Optional<StringRef> &EmbeddedSource) {
+ if (Lines <= 0)
+ return None;
- std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
- int64_t FirstLine =
- std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2);
- int64_t LastLine = FirstLine + PrintSourceContext;
- size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
+ if (EmbeddedSource)
+ return EmbeddedSource;
+ else {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(FileName);
+ if (!BufOrErr)
+ return None;
+ MemBuf = std::move(*BufOrErr);
+ return MemBuf->getBuffer();
+ }
+ }
- for (line_iterator I = line_iterator(*Buf, false);
- !I.is_at_eof() && I.line_number() <= LastLine; ++I) {
- int64_t L = I.line_number();
- if (L >= FirstLine && L <= LastLine) {
+ const Optional<StringRef> pruneSource(const Optional<StringRef> &Source) {
+ if (!Source)
+ return None;
+ size_t FirstLinePos = StringRef::npos, Pos = 0;
+ for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {
+ if (L == FirstLine)
+ FirstLinePos = Pos;
+ Pos = Source->find('\n', Pos);
+ if (Pos == StringRef::npos)
+ break;
+ }
+ if (FirstLinePos == StringRef::npos)
+ return None;
+ return Source->substr(FirstLinePos, (Pos == StringRef::npos)
+ ? StringRef::npos
+ : Pos - FirstLinePos);
+ }
+
+public:
+ const int64_t Line;
+ const int Lines;
+ const int64_t FirstLine;
+ const int64_t LastLine;
+ const Optional<StringRef> PrunedSource;
+
+ SourceCode(
+ StringRef FileName, int64_t Line, int Lines,
+ const Optional<StringRef> &EmbeddedSource = Optional<StringRef>(None))
+ : Line(Line), Lines(Lines),
+ FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),
+ LastLine(FirstLine + Lines - 1),
+ PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}
+
+ void format(raw_ostream &OS) {
+ if (!PrunedSource)
+ return;
+ size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
+ int64_t L = FirstLine;
+ for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {
+ size_t PosEnd = PrunedSource->find('\n', Pos);
+ StringRef String = PrunedSource->substr(
+ Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
+ if (String.endswith("\r"))
+ String = String.drop_back(1);
OS << format_decimal(L, MaxLineNumberWidth);
if (L == Line)
OS << " >: ";
else
OS << " : ";
- OS << *I << "\n";
+ OS << String << '\n';
+ if (PosEnd == StringRef::npos)
+ break;
+ Pos = PosEnd + 1;
}
}
+};
+
+void PlainPrinterBase::printHeader(uint64_t Address) {
+ if (Config.PrintAddress) {
+ OS << "0x";
+ OS.write_hex(Address);
+ StringRef Delimiter = Config.Pretty ? ": " : "\n";
+ OS << Delimiter;
+ }
}
-void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
- if (PrintFunctionNames) {
- std::string FunctionName = Info.FunctionName;
+// Prints source code around in the FileName the Line.
+void PlainPrinterBase::printContext(SourceCode SourceCode) {
+ SourceCode.format(OS);
+}
+
+void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
+ if (Config.PrintFunctions) {
if (FunctionName == DILineInfo::BadString)
FunctionName = DILineInfo::Addr2LineBadString;
-
- StringRef Delimiter = PrintPretty ? " at " : "\n";
- StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : "";
+ StringRef Delimiter = Config.Pretty ? " at " : "\n";
+ StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
OS << Prefix << FunctionName << Delimiter;
}
- std::string Filename = Info.FileName;
+}
+
+void LLVMPrinter::printSimpleLocation(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
+ printContext(
+ SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
+}
+
+void GNUPrinter::printSimpleLocation(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << Filename << ':' << Info.Line;
+ if (Info.Discriminator)
+ OS << " (discriminator " << Info.Discriminator << ')';
+ OS << '\n';
+ printContext(
+ SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
+}
+
+void PlainPrinterBase::printVerbose(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << " Filename: " << Filename << '\n';
+ if (Info.StartLine) {
+ OS << " Function start filename: " << Info.StartFileName << '\n';
+ OS << " Function start line: " << Info.StartLine << '\n';
+ }
+ printStartAddress(Info);
+ OS << " Line: " << Info.Line << '\n';
+ OS << " Column: " << Info.Column << '\n';
+ if (Info.Discriminator)
+ OS << " Discriminator: " << Info.Discriminator << '\n';
+}
+
+void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
+ if (Info.StartAddress) {
+ OS << " Function start address: 0x";
+ OS.write_hex(*Info.StartAddress);
+ OS << '\n';
+ }
+}
+
+void LLVMPrinter::printFooter() { OS << '\n'; }
+
+void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
+ printFunctionName(Info.FunctionName, Inlined);
+ StringRef Filename = Info.FileName;
if (Filename == DILineInfo::BadString)
Filename = DILineInfo::Addr2LineBadString;
- if (!Verbose) {
- OS << Filename << ":" << Info.Line;
- if (Style == OutputStyle::LLVM)
- OS << ":" << Info.Column;
- else if (Style == OutputStyle::GNU && Info.Discriminator != 0)
- OS << " (discriminator " << Info.Discriminator << ")";
- OS << "\n";
- printContext(Filename, Info.Line);
- return;
- }
- OS << " Filename: " << Filename << "\n";
- if (Info.StartLine) {
- OS << " Function start filename: " << Info.StartFileName << "\n";
- OS << " Function start line: " << Info.StartLine << "\n";
- }
- OS << " Line: " << Info.Line << "\n";
- OS << " Column: " << Info.Column << "\n";
- if (Info.Discriminator)
- OS << " Discriminator: " << Info.Discriminator << "\n";
+ if (Config.Verbose)
+ printVerbose(Filename, Info);
+ else
+ printSimpleLocation(Filename, Info);
}
-DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
+void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
+ printHeader(*Request.Address);
print(Info, false);
- return *this;
+ printFooter();
}
-DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
+void PlainPrinterBase::print(const Request &Request,
+ const DIInliningInfo &Info) {
+ printHeader(*Request.Address);
uint32_t FramesNum = Info.getNumberOfFrames();
- if (FramesNum == 0) {
+ if (FramesNum == 0)
print(DILineInfo(), false);
- return *this;
- }
- for (uint32_t i = 0; i < FramesNum; i++)
- print(Info.getFrame(i), i > 0);
- return *this;
+ else
+ for (uint32_t I = 0; I < FramesNum; ++I)
+ print(Info.getFrame(I), I > 0);
+ printFooter();
}
-DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
- std::string Name = Global.Name;
+void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
+ printHeader(*Request.Address);
+ StringRef Name = Global.Name;
if (Name == DILineInfo::BadString)
Name = DILineInfo::Addr2LineBadString;
OS << Name << "\n";
OS << Global.Start << " " << Global.Size << "\n";
- return *this;
+ printFooter();
}
-DIPrinter &DIPrinter::operator<<(const DILocal &Local) {
- if (Local.FunctionName.empty())
- OS << "??\n";
+void PlainPrinterBase::print(const Request &Request,
+ const std::vector<DILocal> &Locals) {
+ printHeader(*Request.Address);
+ if (Locals.empty())
+ OS << DILineInfo::Addr2LineBadString << '\n';
else
- OS << Local.FunctionName << '\n';
+ for (const DILocal &L : Locals) {
+ if (L.FunctionName.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.FunctionName;
+ OS << '\n';
- if (Local.Name.empty())
- OS << "??\n";
- else
- OS << Local.Name << '\n';
+ if (L.Name.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.Name;
+ OS << '\n';
- if (Local.DeclFile.empty())
- OS << "??";
- else
- OS << Local.DeclFile;
- OS << ':' << Local.DeclLine << '\n';
+ if (L.DeclFile.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.DeclFile;
- if (Local.FrameOffset)
- OS << *Local.FrameOffset << ' ';
- else
- OS << "?? ";
+ OS << ':' << L.DeclLine << '\n';
- if (Local.Size)
- OS << *Local.Size << ' ';
- else
- OS << "?? ";
+ if (L.FrameOffset)
+ OS << *L.FrameOffset;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << ' ';
- if (Local.TagOffset)
- OS << *Local.TagOffset << '\n';
+ if (L.Size)
+ OS << *L.Size;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << ' ';
+
+ if (L.TagOffset)
+ OS << *L.TagOffset;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << '\n';
+ }
+ printFooter();
+}
+
+void PlainPrinterBase::printInvalidCommand(const Request &Request,
+ StringRef Command) {
+ OS << Command << '\n';
+}
+
+bool PlainPrinterBase::printError(const Request &Request,
+ const ErrorInfoBase &ErrorInfo,
+ StringRef ErrorBanner) {
+ ES << ErrorBanner;
+ ErrorInfo.log(ES);
+ ES << '\n';
+ // Print an empty struct too.
+ return true;
+}
+
+static std::string toHex(uint64_t V) {
+ return ("0x" + Twine::utohexstr(V)).str();
+}
+
+static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
+ json::Object Json({{"ModuleName", Request.ModuleName.str()}});
+ if (Request.Address)
+ Json["Address"] = toHex(*Request.Address);
+ if (!ErrorMsg.empty())
+ Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});
+ return Json;
+}
+
+void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
+ DIInliningInfo InliningInfo;
+ InliningInfo.addFrame(Info);
+ print(Request, InliningInfo);
+}
+
+void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {
+ json::Array Array;
+ for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {
+ const DILineInfo &LineInfo = Info.getFrame(I);
+ json::Object Object(
+ {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
+ ? LineInfo.FunctionName
+ : ""},
+ {"StartFileName", LineInfo.StartFileName != DILineInfo::BadString
+ ? LineInfo.StartFileName
+ : ""},
+ {"StartLine", LineInfo.StartLine},
+ {"StartAddress",
+ LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},
+ {"FileName",
+ LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
+ {"Line", LineInfo.Line},
+ {"Column", LineInfo.Column},
+ {"Discriminator", LineInfo.Discriminator}});
+ SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,
+ Config.SourceContextLines, LineInfo.Source);
+ std::string FormattedSource;
+ raw_string_ostream Stream(FormattedSource);
+ SourceCode.format(Stream);
+ if (!FormattedSource.empty())
+ Object["Source"] = std::move(FormattedSource);
+ Array.push_back(std::move(Object));
+ }
+ json::Object Json = toJSON(Request);
+ Json["Symbol"] = std::move(Array);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
else
- OS << "??\n";
- return *this;
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {
+ json::Object Data(
+ {{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},
+ {"Start", toHex(Global.Start)},
+ {"Size", toHex(Global.Size)}});
+ json::Object Json = toJSON(Request);
+ Json["Data"] = std::move(Data);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::print(const Request &Request,
+ const std::vector<DILocal> &Locals) {
+ json::Array Frame;
+ for (const DILocal &Local : Locals) {
+ json::Object FrameObject(
+ {{"FunctionName", Local.FunctionName},
+ {"Name", Local.Name},
+ {"DeclFile", Local.DeclFile},
+ {"DeclLine", int64_t(Local.DeclLine)},
+ {"Size", Local.Size ? toHex(*Local.Size) : ""},
+ {"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});
+ if (Local.FrameOffset)
+ FrameObject["FrameOffset"] = *Local.FrameOffset;
+ Frame.push_back(std::move(FrameObject));
+ }
+ json::Object Json = toJSON(Request);
+ Json["Frame"] = std::move(Frame);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::printInvalidCommand(const Request &Request,
+ StringRef Command) {
+ printError(Request,
+ StringError("unable to parse arguments: " + Command,
+ std::make_error_code(std::errc::invalid_argument)),
+ "");
+}
+
+bool JSONPrinter::printError(const Request &Request,
+ const ErrorInfoBase &ErrorInfo,
+ StringRef ErrorBanner) {
+ json::Object Json = toJSON(Request, ErrorInfo.message());
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+ return false;
+}
+
+void JSONPrinter::listBegin() {
+ assert(!ObjectList);
+ ObjectList = std::make_unique<json::Array>();
+}
+
+void JSONPrinter::listEnd() {
+ assert(ObjectList);
+ printJSON(std::move(*ObjectList));
+ ObjectList.reset();
}
} // end namespace symbolize
diff --git a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index 93d05e4..a9c7883 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -16,6 +16,7 @@
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolSize.h"
#include "llvm/Support/Casting.h"
@@ -69,24 +70,19 @@
return std::move(E);
}
- std::vector<std::pair<SymbolDesc, StringRef>> &Fs = res->Functions,
- &Os = res->Objects;
- auto Uniquify = [](std::vector<std::pair<SymbolDesc, StringRef>> &S) {
- // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr,
- // pick the one with the largest Size. This helps us avoid symbols with no
- // size information (Size=0).
- llvm::sort(S);
- auto I = S.begin(), E = S.end(), J = S.begin();
- while (I != E) {
- auto OI = I;
- while (++I != E && OI->first.Addr == I->first.Addr) {
- }
- *J++ = I[-1];
+ std::vector<SymbolDesc> &SS = res->Symbols;
+ // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr,
+ // pick the one with the largest Size. This helps us avoid symbols with no
+ // size information (Size=0).
+ llvm::stable_sort(SS);
+ auto I = SS.begin(), E = SS.end(), J = SS.begin();
+ while (I != E) {
+ auto OI = I;
+ while (++I != E && OI->Addr == I->Addr) {
}
- S.erase(J, S.end());
- };
- Uniquify(Fs);
- Uniquify(Os);
+ *J++ = I[-1];
+ }
+ SS.erase(J, SS.end());
return std::move(res);
}
@@ -138,8 +134,7 @@
uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
uint64_t SymbolStart = ImageBase + Export.Offset;
uint64_t SymbolSize = NextOffset - Export.Offset;
- SymbolDesc SD = {SymbolStart, SymbolSize};
- Functions.emplace_back(SD, Export.Name);
+ Symbols.push_back({SymbolStart, SymbolSize, Export.Name, 0});
}
return Error::success();
}
@@ -149,16 +144,46 @@
DataExtractor *OpdExtractor,
uint64_t OpdAddress) {
// Avoid adding symbols from an unknown/undefined section.
- const ObjectFile *Obj = Symbol.getObject();
+ const ObjectFile &Obj = *Symbol.getObject();
+ Expected<StringRef> SymbolNameOrErr = Symbol.getName();
+ if (!SymbolNameOrErr)
+ return SymbolNameOrErr.takeError();
+ StringRef SymbolName = *SymbolNameOrErr;
+
+ uint32_t ELFSymIdx =
+ Obj.isELF() ? ELFSymbolRef(Symbol).getRawDataRefImpl().d.b : 0;
Expected<section_iterator> Sec = Symbol.getSection();
- if (!Sec || (Obj && Obj->section_end() == *Sec))
+ if (!Sec || Obj.section_end() == *Sec) {
+ if (Obj.isELF()) {
+ // Store the (index, filename) pair for a file symbol.
+ ELFSymbolRef ESym(Symbol);
+ if (ESym.getELFType() == ELF::STT_FILE)
+ FileSymbols.emplace_back(ELFSymIdx, SymbolName);
+ }
return Error::success();
+ }
+
Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
if (!SymbolTypeOrErr)
return SymbolTypeOrErr.takeError();
SymbolRef::Type SymbolType = *SymbolTypeOrErr;
- if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data)
+ if (Obj.isELF()) {
+ // Allow function and data symbols. Additionally allow STT_NONE, which are
+ // common for functions defined in assembly.
+ uint8_t Type = ELFSymbolRef(Symbol).getELFType();
+ if (Type != ELF::STT_NOTYPE && Type != ELF::STT_FUNC &&
+ Type != ELF::STT_OBJECT && Type != ELF::STT_GNU_IFUNC)
+ return Error::success();
+ // Some STT_NOTYPE symbols are not desired. This excludes STT_SECTION and
+ // ARM mapping symbols.
+ uint32_t Flags = cantFail(Symbol.getFlags());
+ if (Flags & SymbolRef::SF_FormatSpecific)
+ return Error::success();
+ } else if (SymbolType != SymbolRef::ST_Function &&
+ SymbolType != SymbolRef::ST_Data) {
return Error::success();
+ }
+
Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
if (!SymbolAddressOrErr)
return SymbolAddressOrErr.takeError();
@@ -179,18 +204,13 @@
if (OpdExtractor->isValidOffsetForAddress(OpdOffset))
SymbolAddress = OpdExtractor->getAddress(&OpdOffset);
}
- Expected<StringRef> SymbolNameOrErr = Symbol.getName();
- if (!SymbolNameOrErr)
- return SymbolNameOrErr.takeError();
- StringRef SymbolName = *SymbolNameOrErr;
// Mach-O symbol table names have leading underscore, skip it.
if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
SymbolName = SymbolName.drop_front();
- // FIXME: If a function has alias, there are two entries in symbol table
- // with same address size. Make sure we choose the correct one.
- auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
- SymbolDesc SD = { SymbolAddress, SymbolSize };
- M.emplace_back(SD, SymbolName);
+
+ if (Obj.isELF() && ELFSymbolRef(Symbol).getBinding() != ELF::STB_LOCAL)
+ ELFSymIdx = 0;
+ Symbols.push_back({SymbolAddress, SymbolSize, SymbolName, ELFSymIdx});
return Error::success();
}
@@ -206,23 +226,32 @@
return 0;
}
-bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type,
- uint64_t Address,
- std::string &Name,
- uint64_t &Addr,
- uint64_t &Size) const {
- const auto &Symbols = Type == SymbolRef::ST_Function ? Functions : Objects;
- std::pair<SymbolDesc, StringRef> SD{{Address, UINT64_C(-1)}, StringRef()};
+bool SymbolizableObjectFile::getNameFromSymbolTable(
+ uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size,
+ std::string &FileName) const {
+ SymbolDesc SD{Address, UINT64_C(-1), StringRef(), 0};
auto SymbolIterator = llvm::upper_bound(Symbols, SD);
if (SymbolIterator == Symbols.begin())
return false;
--SymbolIterator;
- if (SymbolIterator->first.Size != 0 &&
- SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
+ if (SymbolIterator->Size != 0 &&
+ SymbolIterator->Addr + SymbolIterator->Size <= Address)
return false;
- Name = SymbolIterator->second.str();
- Addr = SymbolIterator->first.Addr;
- Size = SymbolIterator->first.Size;
+ Name = SymbolIterator->Name.str();
+ Addr = SymbolIterator->Addr;
+ Size = SymbolIterator->Size;
+
+ if (SymbolIterator->ELFLocalSymIdx != 0) {
+ // If this is an ELF local symbol, find the STT_FILE symbol preceding
+ // SymbolIterator to get the filename. The ELF spec requires the STT_FILE
+ // symbol (if present) precedes the other STB_LOCAL symbols for the file.
+ assert(Module->isELF());
+ auto It = llvm::upper_bound(
+ FileSymbols,
+ std::make_pair(SymbolIterator->ELFLocalSymIdx, StringRef()));
+ if (It != FileSymbols.begin())
+ FileName = It[-1].second.str();
+ }
return true;
}
@@ -248,11 +277,14 @@
// Override function name from symbol table if necessary.
if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
- std::string FunctionName;
+ std::string FunctionName, FileName;
uint64_t Start, Size;
- if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
- FunctionName, Start, Size)) {
+ if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,
+ FileName)) {
LineInfo.FunctionName = FunctionName;
+ LineInfo.StartAddress = Start;
+ if (LineInfo.FileName == DILineInfo::BadString && !FileName.empty())
+ LineInfo.FileName = FileName;
}
}
return LineInfo;
@@ -273,12 +305,16 @@
// Override the function name in lower frame with name from symbol table.
if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
- std::string FunctionName;
+ std::string FunctionName, FileName;
uint64_t Start, Size;
- if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address,
- FunctionName, Start, Size)) {
- InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1)
- ->FunctionName = FunctionName;
+ if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,
+ FileName)) {
+ DILineInfo *LI = InlinedContext.getMutableFrame(
+ InlinedContext.getNumberOfFrames() - 1);
+ LI->FunctionName = FunctionName;
+ LI->StartAddress = Start;
+ if (LI->FileName == DILineInfo::BadString && !FileName.empty())
+ LI->FileName = FileName;
}
}
@@ -288,8 +324,9 @@
DIGlobal SymbolizableObjectFile::symbolizeData(
object::SectionedAddress ModuleOffset) const {
DIGlobal Res;
- getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name,
- Res.Start, Res.Size);
+ std::string FileName;
+ getNameFromSymbolTable(ModuleOffset.Address, Res.Name, Res.Start, Res.Size,
+ FileName);
return Res;
}
diff --git a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h
index be3c66d..8fb003f 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h
+++ b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h
@@ -55,9 +55,9 @@
bool shouldOverrideWithSymbolTable(FunctionNameKind FNKind,
bool UseSymbolTable) const;
- bool getNameFromSymbolTable(object::SymbolRef::Type Type, uint64_t Address,
- std::string &Name, uint64_t &Addr,
- uint64_t &Size) const;
+ bool getNameFromSymbolTable(uint64_t Address, std::string &Name,
+ uint64_t &Addr, uint64_t &Size,
+ std::string &FileName) const;
// For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd
// (function descriptor) section and OpdExtractor refers to its contents.
Error addSymbol(const object::SymbolRef &Symbol, uint64_t SymbolSize,
@@ -78,12 +78,18 @@
// the following symbol.
uint64_t Size;
+ StringRef Name;
+ // Non-zero if this is an ELF local symbol. See the comment in
+ // getNameFromSymbolTable.
+ uint32_t ELFLocalSymIdx;
+
bool operator<(const SymbolDesc &RHS) const {
return Addr != RHS.Addr ? Addr < RHS.Addr : Size < RHS.Size;
}
};
- std::vector<std::pair<SymbolDesc, StringRef>> Functions;
- std::vector<std::pair<SymbolDesc, StringRef>> Objects;
+ std::vector<SymbolDesc> Symbols;
+ // (index, filename) pairs of ELF STT_FILE symbols.
+ std::vector<std::pair<uint32_t, StringRef>> FileSymbols;
SymbolizableObjectFile(const object::ObjectFile *Obj,
std::unique_ptr<DIContext> DICtx,
diff --git a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index da157a5..72ca722 100644
--- a/src/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/src/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -39,9 +39,17 @@
namespace llvm {
namespace symbolize {
+template <typename T>
Expected<DILineInfo>
-LLVMSymbolizer::symbolizeCodeCommon(SymbolizableModule *Info,
+LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
object::SectionedAddress ModuleOffset) {
+
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+
// A null module means an error has already been reported. Return an empty
// result.
if (!Info)
@@ -63,37 +71,24 @@
Expected<DILineInfo>
LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
object::SectionedAddress ModuleOffset) {
- StringRef ModuleName = Obj.getFileName();
- auto I = Modules.find(ModuleName);
- if (I != Modules.end())
- return symbolizeCodeCommon(I->second.get(), ModuleOffset);
-
- std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
- Expected<SymbolizableModule *> InfoOrErr =
- createModuleInfo(&Obj, std::move(Context), ModuleName);
- if (!InfoOrErr)
- return InfoOrErr.takeError();
- return symbolizeCodeCommon(*InfoOrErr, ModuleOffset);
+ return symbolizeCodeCommon(Obj, ModuleOffset);
}
Expected<DILineInfo>
LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
object::SectionedAddress ModuleOffset) {
- Expected<SymbolizableModule *> InfoOrErr = getOrCreateModuleInfo(ModuleName);
- if (!InfoOrErr)
- return InfoOrErr.takeError();
- return symbolizeCodeCommon(*InfoOrErr, ModuleOffset);
+ return symbolizeCodeCommon(ModuleName, ModuleOffset);
}
-Expected<DIInliningInfo>
-LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
- object::SectionedAddress ModuleOffset) {
- SymbolizableModule *Info;
- if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
- Info = InfoOrErr.get();
- else
+template <typename T>
+Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
+ const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
return InfoOrErr.takeError();
+ SymbolizableModule *Info = *InfoOrErr;
+
// A null module means an error has already been reported. Return an empty
// result.
if (!Info)
@@ -116,15 +111,28 @@
return InlinedContext;
}
+Expected<DIInliningInfo>
+LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
+}
+
+Expected<DIInliningInfo>
+LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
+}
+
+template <typename T>
Expected<DIGlobal>
-LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
- object::SectionedAddress ModuleOffset) {
- SymbolizableModule *Info;
- if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
- Info = InfoOrErr.get();
- else
+LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
+ object::SectionedAddress ModuleOffset) {
+
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
return InfoOrErr.takeError();
+ SymbolizableModule *Info = *InfoOrErr;
// A null module means an error has already been reported. Return an empty
// result.
if (!Info)
@@ -142,15 +150,27 @@
return Global;
}
+Expected<DIGlobal>
+LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeDataCommon(Obj, ModuleOffset);
+}
+
+Expected<DIGlobal>
+LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeDataCommon(ModuleName, ModuleOffset);
+}
+
+template <typename T>
Expected<std::vector<DILocal>>
-LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
- object::SectionedAddress ModuleOffset) {
- SymbolizableModule *Info;
- if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
- Info = InfoOrErr.get();
- else
+LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
+ object::SectionedAddress ModuleOffset) {
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
return InfoOrErr.takeError();
+ SymbolizableModule *Info = *InfoOrErr;
// A null module means an error has already been reported. Return an empty
// result.
if (!Info)
@@ -165,6 +185,18 @@
return Info->symbolizeFrame(ModuleOffset);
}
+Expected<std::vector<DILocal>>
+LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeFrameCommon(Obj, ModuleOffset);
+}
+
+Expected<std::vector<DILocal>>
+LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeFrameCommon(ModuleName, ModuleOffset);
+}
+
void LLVMSymbolizer::flush() {
ObjectForUBPathAndArch.clear();
BinaryForPath.clear();
@@ -178,8 +210,8 @@
// /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
// /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
-std::string getDarwinDWARFResourceForPath(
- const std::string &Path, const std::string &Basename) {
+std::string getDarwinDWARFResourceForPath(const std::string &Path,
+ const std::string &Basename) {
SmallString<16> ResourceName = StringRef(Path);
if (sys::path::extension(Path) != ".dSYM") {
ResourceName += ".dSYM";
@@ -298,7 +330,8 @@
continue;
Error Err = Error::success();
for (auto N : Obj.notes(P, Err))
- if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU)
+ if (N.getType() == ELF::NT_GNU_BUILD_ID &&
+ N.getName() == ELF::ELF_NOTE_GNU)
return N.getDesc();
consumeError(std::move(Err));
}
@@ -321,8 +354,7 @@
}
bool findDebugBinary(const std::vector<std::string> &DebugFileDirectory,
- const ArrayRef<uint8_t> BuildID,
- std::string &Result) {
+ const ArrayRef<uint8_t> BuildID, std::string &Result) {
auto getDebugPath = [&](StringRef Directory) {
SmallString<128> Path{Directory};
sys::path::append(Path, ".build-id",
@@ -334,11 +366,11 @@
if (DebugFileDirectory.empty()) {
SmallString<128> Path = getDebugPath(
#if defined(__NetBSD__)
- // Try /usr/libdata/debug/.build-id/../...
- "/usr/libdata/debug"
+ // Try /usr/libdata/debug/.build-id/../...
+ "/usr/libdata/debug"
#else
- // Try /usr/lib/debug/.build-id/../...
- "/usr/lib/debug"
+ // Try /usr/lib/debug/.build-id/../...
+ "/usr/lib/debug"
#endif
);
if (llvm::sys::fs::exists(Path)) {
@@ -361,7 +393,8 @@
} // end anonymous namespace
ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
- const MachOObjectFile *MachExeObj, const std::string &ArchName) {
+ const MachOObjectFile *MachExeObj,
+ const std::string &ArchName) {
// On Darwin we may find DWARF in separate object file in
// resource directory.
std::vector<std::string> DsymPaths;
@@ -571,6 +604,18 @@
return createModuleInfo(Objects.first, std::move(Context), ModuleName);
}
+Expected<SymbolizableModule *>
+LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
+ StringRef ObjName = Obj.getFileName();
+ auto I = Modules.find(ObjName);
+ if (I != Modules.end())
+ return I->second.get();
+
+ std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
+ // FIXME: handle COFF object with PDB info to use PDBContext
+ return createModuleInfo(&Obj, std::move(Context), ObjName);
+}
+
namespace {
// Undo these various manglings for Win32 extern "C" functions:
@@ -609,7 +654,8 @@
// approach to check if the name should be demangled.
if (Name.substr(0, 2) == "_Z") {
int status = 0;
- char *DemangledName = itaniumDemangle(Name.c_str(), nullptr, nullptr, &status);
+ char *DemangledName =
+ itaniumDemangle(Name.c_str(), nullptr, nullptr, &status);
if (status != 0)
return Name;
std::string Result = DemangledName;