summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo')
-rw-r--r--llvm/lib/DebugInfo/BTF/BTFContext.cpp4
-rw-r--r--llvm/lib/DebugInfo/BTF/BTFParser.cpp620
-rw-r--r--llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp2
-rw-r--r--llvm/lib/DebugInfo/CodeView/EnumTables.cpp18
-rw-r--r--llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp5
-rw-r--r--llvm/lib/DebugInfo/CodeView/RecordName.cpp2
-rw-r--r--llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp4
-rw-r--r--llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp2
-rw-r--r--llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp31
-rw-r--r--llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp13
-rw-r--r--llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp5
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp3
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp88
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFContext.cpp1148
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp14
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp11
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDie.cpp40
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp11
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp83
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp48
-rw-r--r--llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp247
-rw-r--r--llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp4
-rw-r--r--llvm/lib/DebugInfo/GSYM/GsymCreator.cpp218
-rw-r--r--llvm/lib/DebugInfo/GSYM/GsymReader.cpp130
-rw-r--r--llvm/lib/DebugInfo/GSYM/InlineInfo.cpp11
-rw-r--r--llvm/lib/DebugInfo/GSYM/LineTable.cpp5
-rw-r--r--llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp15
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp9
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp3
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp10
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp21
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp55
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp2
-rw-r--r--llvm/lib/DebugInfo/MSF/MSFBuilder.cpp7
-rw-r--r--llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp4
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/FormatUtil.cpp5
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp4
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp2
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/InputFile.cpp4
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp8
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp24
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp2
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp1
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp2
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp4
-rw-r--r--llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp40
-rw-r--r--llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp4
-rw-r--r--llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp13
-rw-r--r--llvm/lib/DebugInfo/Symbolize/Symbolize.cpp46
54 files changed, 2193 insertions, 864 deletions
diff --git a/llvm/lib/DebugInfo/BTF/BTFContext.cpp b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
index 24898739b824..2e651cb378db 100644
--- a/llvm/lib/DebugInfo/BTF/BTFContext.cpp
+++ b/llvm/lib/DebugInfo/BTF/BTFContext.cpp
@@ -63,7 +63,9 @@ std::unique_ptr<BTFContext>
BTFContext::create(const ObjectFile &Obj,
std::function<void(Error)> ErrorHandler) {
auto Ctx = std::make_unique<BTFContext>();
- if (Error E = Ctx->BTF.parse(Obj))
+ BTFParser::ParseOptions Opts;
+ Opts.LoadLines = true;
+ if (Error E = Ctx->BTF.parse(Obj, Opts))
ErrorHandler(std::move(E));
return Ctx;
}
diff --git a/llvm/lib/DebugInfo/BTF/BTFParser.cpp b/llvm/lib/DebugInfo/BTF/BTFParser.cpp
index 6151e1b15cbb..4fc31a445603 100644
--- a/llvm/lib/DebugInfo/BTF/BTFParser.cpp
+++ b/llvm/lib/DebugInfo/BTF/BTFParser.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/BTF/BTFParser.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#define DEBUG_TYPE "debug-info-btf-parser"
@@ -74,11 +76,13 @@ public:
// Used by BTFParser::parse* auxiliary functions.
struct BTFParser::ParseContext {
const ObjectFile &Obj;
+ const ParseOptions &Opts;
// Map from ELF section name to SectionRef
DenseMap<StringRef, SectionRef> Sections;
public:
- ParseContext(const ObjectFile &Obj) : Obj(Obj) {}
+ ParseContext(const ObjectFile &Obj, const ParseOptions &Opts)
+ : Obj(Obj), Opts(Opts) {}
Expected<DataExtractor> makeExtractor(SectionRef Sec) {
Expected<StringRef> Contents = Sec.getContents();
@@ -119,19 +123,126 @@ Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) {
return Err(".BTF", C);
if (HdrLen < 8)
return Err("unexpected .BTF header length: ") << HdrLen;
- (void)Extractor.getU32(C); // type_off
- (void)Extractor.getU32(C); // type_len
+ uint32_t TypeOff = Extractor.getU32(C);
+ uint32_t TypeLen = Extractor.getU32(C);
uint32_t StrOff = Extractor.getU32(C);
uint32_t StrLen = Extractor.getU32(C);
uint32_t StrStart = HdrLen + StrOff;
uint32_t StrEnd = StrStart + StrLen;
+ uint32_t TypesInfoStart = HdrLen + TypeOff;
+ uint32_t TypesInfoEnd = TypesInfoStart + TypeLen;
+ uint32_t BytesExpected = std::max(StrEnd, TypesInfoEnd);
if (!C)
return Err(".BTF", C);
- if (Extractor.getData().size() < StrEnd)
+ if (Extractor.getData().size() < BytesExpected)
return Err("invalid .BTF section size, expecting at-least ")
- << StrEnd << " bytes";
+ << BytesExpected << " bytes";
+
+ StringsTable = Extractor.getData().slice(StrStart, StrEnd);
+
+ if (TypeLen > 0 && Ctx.Opts.LoadTypes) {
+ StringRef RawData = Extractor.getData().slice(TypesInfoStart, TypesInfoEnd);
+ if (Error E = parseTypesInfo(Ctx, TypesInfoStart, RawData))
+ return E;
+ }
+
+ return Error::success();
+}
+
+// Compute record size for each BTF::CommonType sub-type
+// (including entries in the tail position).
+static size_t byteSize(BTF::CommonType *Type) {
+ size_t Size = sizeof(BTF::CommonType);
+ switch (Type->getKind()) {
+ case BTF::BTF_KIND_INT:
+ Size += sizeof(uint32_t);
+ break;
+ case BTF::BTF_KIND_ARRAY:
+ Size += sizeof(BTF::BTFArray);
+ break;
+ case BTF::BTF_KIND_VAR:
+ Size += sizeof(uint32_t);
+ break;
+ case BTF::BTF_KIND_DECL_TAG:
+ Size += sizeof(uint32_t);
+ break;
+ case BTF::BTF_KIND_STRUCT:
+ case BTF::BTF_KIND_UNION:
+ Size += sizeof(BTF::BTFMember) * Type->getVlen();
+ break;
+ case BTF::BTF_KIND_ENUM:
+ Size += sizeof(BTF::BTFEnum) * Type->getVlen();
+ break;
+ case BTF::BTF_KIND_ENUM64:
+ Size += sizeof(BTF::BTFEnum64) * Type->getVlen();
+ break;
+ case BTF::BTF_KIND_FUNC_PROTO:
+ Size += sizeof(BTF::BTFParam) * Type->getVlen();
+ break;
+ case BTF::BTF_KIND_DATASEC:
+ Size += sizeof(BTF::BTFDataSec) * Type->getVlen();
+ break;
+ }
+ return Size;
+}
+
+// Guard value for voids, simplifies code a bit, but NameOff is not
+// actually valid.
+const BTF::CommonType VoidTypeInst = {0, BTF::BTF_KIND_UNKN << 24, {0}};
+
+// Type information "parsing" is very primitive:
+// - The `RawData` is copied to a buffer owned by `BTFParser` instance.
+// - The buffer is treated as an array of `uint32_t` values, each value
+// is swapped to use native endianness. This is possible, because
+// according to BTF spec all buffer elements are structures comprised
+// of `uint32_t` fields.
+// - `BTFParser::Types` vector is filled with pointers to buffer
+// elements, using `byteSize()` function to slice the buffer at type
+// record boundaries.
+// - If at some point a type definition with incorrect size (logical size
+// exceeding buffer boundaries) is reached it is not added to the
+// `BTFParser::Types` vector and the process stops.
+Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
+ StringRef RawData) {
+ using support::endian::byte_swap;
+
+ TypesBuffer = OwningArrayRef<uint8_t>(arrayRefFromStringRef(RawData));
+ // Switch endianness if necessary.
+ endianness Endianness = Ctx.Obj.isLittleEndian() ? llvm::endianness::little
+ : llvm::endianness::big;
+ uint32_t *TypesBuffer32 = (uint32_t *)TypesBuffer.data();
+ for (uint64_t I = 0; I < TypesBuffer.size() / 4; ++I)
+ TypesBuffer32[I] = byte_swap(TypesBuffer32[I], Endianness);
+
+ // The type id 0 is reserved for void type.
+ Types.push_back(&VoidTypeInst);
+
+ uint64_t Pos = 0;
+ while (Pos < RawData.size()) {
+ uint64_t BytesLeft = RawData.size() - Pos;
+ uint64_t Offset = TypesInfoStart + Pos;
+ BTF::CommonType *Type = (BTF::CommonType *)&TypesBuffer[Pos];
+ if (BytesLeft < sizeof(*Type))
+ return Err("incomplete type definition in .BTF section:")
+ << " offset " << Offset << ", index " << Types.size();
+
+ uint64_t Size = byteSize(Type);
+ if (BytesLeft < Size)
+ return Err("incomplete type definition in .BTF section:")
+ << " offset=" << Offset << ", index=" << Types.size()
+ << ", vlen=" << Type->getVlen();
+
+ LLVM_DEBUG({
+ llvm::dbgs() << "Adding BTF type:\n"
+ << " Id = " << Types.size() << "\n"
+ << " Kind = " << Type->getKind() << "\n"
+ << " Name = " << findString(Type->NameOff) << "\n"
+ << " Record Size = " << Size << "\n";
+ });
+ Types.push_back(Type);
+ Pos += Size;
+ }
- StringsTable = Extractor.getData().substr(StrStart, StrLen);
return Error::success();
}
@@ -162,12 +273,24 @@ Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) {
(void)Extractor.getU32(C); // func_info_len
uint32_t LineInfoOff = Extractor.getU32(C);
uint32_t LineInfoLen = Extractor.getU32(C);
+ uint32_t RelocInfoOff = Extractor.getU32(C);
+ uint32_t RelocInfoLen = Extractor.getU32(C);
if (!C)
return Err(".BTF.ext", C);
- uint32_t LineInfoStart = HdrLen + LineInfoOff;
- uint32_t LineInfoEnd = LineInfoStart + LineInfoLen;
- if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd))
- return E;
+
+ if (LineInfoLen > 0 && Ctx.Opts.LoadLines) {
+ uint32_t LineInfoStart = HdrLen + LineInfoOff;
+ uint32_t LineInfoEnd = LineInfoStart + LineInfoLen;
+ if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd))
+ return E;
+ }
+
+ if (RelocInfoLen > 0 && Ctx.Opts.LoadRelocs) {
+ uint32_t RelocInfoStart = HdrLen + RelocInfoOff;
+ uint32_t RelocInfoEnd = RelocInfoStart + RelocInfoLen;
+ if (Error E = parseRelocInfo(Ctx, Extractor, RelocInfoStart, RelocInfoEnd))
+ return E;
+ }
return Error::success();
}
@@ -214,11 +337,52 @@ Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
return Error::success();
}
-Error BTFParser::parse(const ObjectFile &Obj) {
+Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor,
+ uint64_t RelocInfoStart,
+ uint64_t RelocInfoEnd) {
+ DataExtractor::Cursor C = DataExtractor::Cursor(RelocInfoStart);
+ uint32_t RecSize = Extractor.getU32(C);
+ if (!C)
+ return Err(".BTF.ext", C);
+ if (RecSize < 16)
+ return Err("unexpected .BTF.ext field reloc info record length: ")
+ << RecSize;
+ while (C && C.tell() < RelocInfoEnd) {
+ uint32_t SecNameOff = Extractor.getU32(C);
+ uint32_t NumInfo = Extractor.getU32(C);
+ StringRef SecName = findString(SecNameOff);
+ std::optional<SectionRef> Sec = Ctx.findSection(SecName);
+ BTFRelocVector &Relocs = SectionRelocs[Sec->getIndex()];
+ for (uint32_t I = 0; C && I < NumInfo; ++I) {
+ uint64_t RecStart = C.tell();
+ uint32_t InsnOff = Extractor.getU32(C);
+ uint32_t TypeID = Extractor.getU32(C);
+ uint32_t OffsetNameOff = Extractor.getU32(C);
+ uint32_t RelocKind = Extractor.getU32(C);
+ if (!C)
+ return Err(".BTF.ext", C);
+ Relocs.push_back({InsnOff, TypeID, OffsetNameOff, RelocKind});
+ C.seek(RecStart + RecSize);
+ }
+ llvm::stable_sort(
+ Relocs, [](const BTF::BPFFieldReloc &L, const BTF::BPFFieldReloc &R) {
+ return L.InsnOffset < R.InsnOffset;
+ });
+ }
+ if (!C)
+ return Err(".BTF.ext", C);
+
+ return Error::success();
+}
+
+Error BTFParser::parse(const ObjectFile &Obj, const ParseOptions &Opts) {
StringsTable = StringRef();
SectionLines.clear();
+ SectionRelocs.clear();
+ Types.clear();
+ TypesBuffer = OwningArrayRef<uint8_t>();
- ParseContext Ctx(Obj);
+ ParseContext Ctx(Obj, Opts);
std::optional<SectionRef> BTF;
std::optional<SectionRef> BTFExt;
for (SectionRef Sec : Obj.sections()) {
@@ -264,20 +428,430 @@ StringRef BTFParser::findString(uint32_t Offset) const {
return StringsTable.slice(Offset, StringsTable.find(0, Offset));
}
-const BTF::BPFLineInfo *
-BTFParser::findLineInfo(SectionedAddress Address) const {
- auto MaybeSecInfo = SectionLines.find(Address.SectionIndex);
- if (MaybeSecInfo == SectionLines.end())
+template <typename T>
+static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap,
+ SectionedAddress Address) {
+ auto MaybeSecInfo = SecMap.find(Address.SectionIndex);
+ if (MaybeSecInfo == SecMap.end())
return nullptr;
- const BTFLinesVector &SecInfo = MaybeSecInfo->second;
+ const SmallVector<T, 0> &SecInfo = MaybeSecInfo->second;
const uint64_t TargetOffset = Address.Address;
- BTFLinesVector::const_iterator LineInfo =
- llvm::partition_point(SecInfo, [=](const BTF::BPFLineInfo &Line) {
- return Line.InsnOffset < TargetOffset;
- });
- if (LineInfo == SecInfo.end() || LineInfo->InsnOffset != Address.Address)
+ typename SmallVector<T, 0>::const_iterator MaybeInfo = llvm::partition_point(
+ SecInfo, [=](const T &Entry) { return Entry.InsnOffset < TargetOffset; });
+ if (MaybeInfo == SecInfo.end() || MaybeInfo->InsnOffset != Address.Address)
return nullptr;
- return LineInfo;
+ return &*MaybeInfo;
+}
+
+const BTF::BPFLineInfo *
+BTFParser::findLineInfo(SectionedAddress Address) const {
+ return findInfo(SectionLines, Address);
+}
+
+const BTF::BPFFieldReloc *
+BTFParser::findFieldReloc(SectionedAddress Address) const {
+ return findInfo(SectionRelocs, Address);
+}
+
+const BTF::CommonType *BTFParser::findType(uint32_t Id) const {
+ if (Id < Types.size())
+ return Types[Id];
+ return nullptr;
+}
+
+enum RelocKindGroup {
+ RKG_FIELD,
+ RKG_TYPE,
+ RKG_ENUMVAL,
+ RKG_UNKNOWN,
+};
+
+static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc) {
+ switch (Reloc->RelocKind) {
+ case BTF::FIELD_BYTE_OFFSET:
+ case BTF::FIELD_BYTE_SIZE:
+ case BTF::FIELD_EXISTENCE:
+ case BTF::FIELD_SIGNEDNESS:
+ case BTF::FIELD_LSHIFT_U64:
+ case BTF::FIELD_RSHIFT_U64:
+ return RKG_FIELD;
+ case BTF::BTF_TYPE_ID_LOCAL:
+ case BTF::BTF_TYPE_ID_REMOTE:
+ case BTF::TYPE_EXISTENCE:
+ case BTF::TYPE_MATCH:
+ case BTF::TYPE_SIZE:
+ return RKG_TYPE;
+ case BTF::ENUM_VALUE_EXISTENCE:
+ case BTF::ENUM_VALUE:
+ return RKG_ENUMVAL;
+ default:
+ return RKG_UNKNOWN;
+ }
+}
+
+static bool isMod(const BTF::CommonType *Type) {
+ switch (Type->getKind()) {
+ case BTF::BTF_KIND_VOLATILE:
+ case BTF::BTF_KIND_CONST:
+ case BTF::BTF_KIND_RESTRICT:
+ case BTF::BTF_KIND_TYPE_TAG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type,
+ raw_ostream &Stream) {
+ switch (Type->getKind()) {
+ case BTF::BTF_KIND_CONST:
+ Stream << " const";
+ break;
+ case BTF::BTF_KIND_VOLATILE:
+ Stream << " volatile";
+ break;
+ case BTF::BTF_KIND_RESTRICT:
+ Stream << " restrict";
+ break;
+ case BTF::BTF_KIND_TYPE_TAG:
+ Stream << " type_tag(\"" << BTF.findString(Type->NameOff) << "\")";
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static const BTF::CommonType *skipModsAndTypedefs(const BTFParser &BTF,
+ const BTF::CommonType *Type) {
+ while (isMod(Type) || Type->getKind() == BTF::BTF_KIND_TYPEDEF) {
+ auto *Base = BTF.findType(Type->Type);
+ if (!Base)
+ break;
+ Type = Base;
+ }
+ return Type;
+}
+
+namespace {
+struct StrOrAnon {
+ const BTFParser &BTF;
+ uint32_t Offset;
+ uint32_t Idx;
+};
+
+static raw_ostream &operator<<(raw_ostream &Stream, const StrOrAnon &S) {
+ StringRef Str = S.BTF.findString(S.Offset);
+ if (Str.empty())
+ Stream << "<anon " << S.Idx << ">";
+ else
+ Stream << Str;
+ return Stream;
+}
+} // anonymous namespace
+
+static void relocKindName(uint32_t X, raw_ostream &Out) {
+ Out << "<";
+ switch (X) {
+ default:
+ Out << "reloc kind #" << X;
+ break;
+ case BTF::FIELD_BYTE_OFFSET:
+ Out << "byte_off";
+ break;
+ case BTF::FIELD_BYTE_SIZE:
+ Out << "byte_sz";
+ break;
+ case BTF::FIELD_EXISTENCE:
+ Out << "field_exists";
+ break;
+ case BTF::FIELD_SIGNEDNESS:
+ Out << "signed";
+ break;
+ case BTF::FIELD_LSHIFT_U64:
+ Out << "lshift_u64";
+ break;
+ case BTF::FIELD_RSHIFT_U64:
+ Out << "rshift_u64";
+ break;
+ case BTF::BTF_TYPE_ID_LOCAL:
+ Out << "local_type_id";
+ break;
+ case BTF::BTF_TYPE_ID_REMOTE:
+ Out << "target_type_id";
+ break;
+ case BTF::TYPE_EXISTENCE:
+ Out << "type_exists";
+ break;
+ case BTF::TYPE_MATCH:
+ Out << "type_matches";
+ break;
+ case BTF::TYPE_SIZE:
+ Out << "type_size";
+ break;
+ case BTF::ENUM_VALUE_EXISTENCE:
+ Out << "enumval_exists";
+ break;
+ case BTF::ENUM_VALUE:
+ Out << "enumval_value";
+ break;
+ }
+ Out << ">";
+}
+
+// Produces a human readable description of a CO-RE relocation.
+// Such relocations are generated by BPF backend, and processed
+// by libbpf's BPF program loader [1].
+//
+// Each relocation record has the following information:
+// - Relocation kind;
+// - BTF type ID;
+// - Access string offset in string table.
+//
+// There are different kinds of relocations, these kinds could be split
+// in three groups:
+// - load-time information about types (size, existence),
+// `BTFParser::symbolize()` output for such relocations uses the template:
+//
+// <relocation-kind> [<id>] <type-name>
+//
+// For example:
+// - "<type_exists> [7] struct foo"
+// - "<type_size> [7] struct foo"
+//
+// - load-time information about enums (literal existence, literal value),
+// `BTFParser::symbolize()` output for such relocations uses the template:
+//
+// <relocation-kind> [<id>] <type-name>::<literal-name> = <original-value>
+//
+// For example:
+// - "<enumval_exists> [5] enum foo::U = 1"
+// - "<enumval_value> [5] enum foo::V = 2"
+//
+// - load-time information about fields (e.g. field offset),
+// `BTFParser::symbolize()` output for such relocations uses the template:
+//
+// <relocation-kind> [<id>] \
+// <type-name>::[N].<field-1-name>...<field-M-name> \
+// (<access string>)
+//
+// For example:
+// - "<byte_off> [8] struct bar::[7].v (7:1)"
+// - "<field_exists> [8] struct bar::v (0:1)"
+//
+// If relocation description is not valid output follows the following pattern:
+//
+// <relocation-kind> <type-id>::<unprocessedaccess-string> <<error-msg>>
+//
+// For example:
+//
+// - "<type_sz> [42] '' <unknown type id: 42>"
+// - "<byte_off> [4] '0:' <field spec too short>"
+//
+// Additional examples could be found in unit tests, see
+// llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp.
+//
+// [1] https://www.kernel.org/doc/html/latest/bpf/libbpf/index.html
+void BTFParser::symbolize(const BTF::BPFFieldReloc *Reloc,
+ SmallVectorImpl<char> &Result) const {
+ raw_svector_ostream Stream(Result);
+ StringRef FullSpecStr = findString(Reloc->OffsetNameOff);
+ SmallVector<uint32_t, 8> RawSpec;
+
+ auto Fail = [&](auto Msg) {
+ Result.resize(0);
+ relocKindName(Reloc->RelocKind, Stream);
+ Stream << " [" << Reloc->TypeID << "] '" << FullSpecStr << "'"
+ << " <" << Msg << ">";
+ };
+
+ // Relocation access string follows pattern [0-9]+(:[0-9]+)*,
+ // e.g.: 12:22:3. Code below splits `SpecStr` by ':', parses
+ // numbers, and pushes them to `RawSpec`.
+ StringRef SpecStr = FullSpecStr;
+ while (SpecStr.size()) {
+ unsigned long long Val;
+ if (consumeUnsignedInteger(SpecStr, 10, Val))
+ return Fail("spec string is not a number");
+ RawSpec.push_back(Val);
+ if (SpecStr.empty())
+ break;
+ if (SpecStr[0] != ':')
+ return Fail(format("unexpected spec string delimiter: '%c'", SpecStr[0]));
+ SpecStr = SpecStr.substr(1);
+ }
+
+ // Print relocation kind to `Stream`.
+ relocKindName(Reloc->RelocKind, Stream);
+
+ uint32_t CurId = Reloc->TypeID;
+ const BTF::CommonType *Type = findType(CurId);
+ if (!Type)
+ return Fail(format("unknown type id: %d", CurId));
+
+ Stream << " [" << CurId << "]";
+
+ // `Type` might have modifiers, e.g. for type 'const int' the `Type`
+ // would refer to BTF type of kind BTF_KIND_CONST.
+ // Print all these modifiers to `Stream`.
+ for (uint32_t ChainLen = 0; printMod(*this, Type, Stream); ++ChainLen) {
+ if (ChainLen >= 32)
+ return Fail("modifiers chain is too long");
+
+ CurId = Type->Type;
+ const BTF::CommonType *NextType = findType(CurId);
+ if (!NextType)
+ return Fail(format("unknown type id: %d in modifiers chain", CurId));
+ Type = NextType;
+ }
+ // Print the type name to `Stream`.
+ if (CurId == 0) {
+ Stream << " void";
+ } else {
+ switch (Type->getKind()) {
+ case BTF::BTF_KIND_TYPEDEF:
+ Stream << " typedef";
+ break;
+ case BTF::BTF_KIND_STRUCT:
+ Stream << " struct";
+ break;
+ case BTF::BTF_KIND_UNION:
+ Stream << " union";
+ break;
+ case BTF::BTF_KIND_ENUM:
+ Stream << " enum";
+ break;
+ case BTF::BTF_KIND_ENUM64:
+ Stream << " enum";
+ break;
+ case BTF::BTF_KIND_FWD:
+ if (Type->Info & BTF::FWD_UNION_FLAG)
+ Stream << " fwd union";
+ else
+ Stream << " fwd struct";
+ break;
+ default:
+ break;
+ }
+ Stream << " " << StrOrAnon({*this, Type->NameOff, CurId});
+ }
+
+ RelocKindGroup Group = relocKindGroup(Reloc);
+ // Type-based relocations don't use access string but clang backend
+ // generates '0' and libbpf checks it's value, do the same here.
+ if (Group == RKG_TYPE) {
+ if (RawSpec.size() != 1 || RawSpec[0] != 0)
+ return Fail("unexpected type-based relocation spec: should be '0'");
+ return;
+ }
+
+ Stream << "::";
+
+ // For enum-based relocations access string is a single number,
+ // corresponding to the enum literal sequential number.
+ // E.g. for `enum E { U, V }`, relocation requesting value of `V`
+ // would look as follows:
+ // - kind: BTF::ENUM_VALUE
+ // - BTF id: id for `E`
+ // - access string: "1"
+ if (Group == RKG_ENUMVAL) {
+ Type = skipModsAndTypedefs(*this, Type);
+
+ if (RawSpec.size() != 1)
+ return Fail("unexpected enumval relocation spec size");
+
+ uint32_t NameOff;
+ uint64_t Val;
+ uint32_t Idx = RawSpec[0];
+ if (auto *T = dyn_cast<BTF::EnumType>(Type)) {
+ if (T->values().size() <= Idx)
+ return Fail(format("bad value index: %d", Idx));
+ const BTF::BTFEnum &E = T->values()[Idx];
+ NameOff = E.NameOff;
+ Val = E.Val;
+ } else if (auto *T = dyn_cast<BTF::Enum64Type>(Type)) {
+ if (T->values().size() <= Idx)
+ return Fail(format("bad value index: %d", Idx));
+ const BTF::BTFEnum64 &E = T->values()[Idx];
+ NameOff = E.NameOff;
+ Val = (uint64_t)E.Val_Hi32 << 32u | E.Val_Lo32;
+ } else {
+ return Fail(format("unexpected type kind for enum relocation: %d",
+ Type->getKind()));
+ }
+
+ Stream << StrOrAnon({*this, NameOff, Idx});
+ if (Type->Info & BTF::ENUM_SIGNED_FLAG)
+ Stream << " = " << (int64_t)Val;
+ else
+ Stream << " = " << (uint64_t)Val;
+ return;
+ }
+
+ // For type-based relocations access string is an array of numbers,
+ // which resemble index parameters for `getelementptr` LLVM IR instruction.
+ // E.g. for the following types:
+ //
+ // struct foo {
+ // int a;
+ // int b;
+ // };
+ // struct bar {
+ // int u;
+ // struct foo v[7];
+ // };
+ //
+ // Relocation requesting `offsetof(struct bar, v[2].b)` will have
+ // the following access string: 0:1:2:1
+ // ^ ^ ^ ^
+ // | | | |
+ // initial index | | field 'b' is a field #1
+ // | | (counting from 0)
+ // | array index #2
+ // field 'v' is a field #1
+ // (counting from 0)
+ if (Group == RKG_FIELD) {
+ if (RawSpec.size() < 1)
+ return Fail("field spec too short");
+
+ if (RawSpec[0] != 0)
+ Stream << "[" << RawSpec[0] << "]";
+ for (uint32_t I = 1; I < RawSpec.size(); ++I) {
+ Type = skipModsAndTypedefs(*this, Type);
+ uint32_t Idx = RawSpec[I];
+
+ if (auto *T = dyn_cast<BTF::StructType>(Type)) {
+ if (T->getVlen() <= Idx)
+ return Fail(
+ format("member index %d for spec sub-string %d is out of range",
+ Idx, I));
+
+ const BTF::BTFMember &Member = T->members()[Idx];
+ if (I != 1 || RawSpec[0] != 0)
+ Stream << ".";
+ Stream << StrOrAnon({*this, Member.NameOff, Idx});
+ Type = findType(Member.Type);
+ if (!Type)
+ return Fail(format("unknown member type id %d for spec sub-string %d",
+ Member.Type, I));
+ } else if (auto *T = dyn_cast<BTF::ArrayType>(Type)) {
+ Stream << "[" << Idx << "]";
+ Type = findType(T->getArray().ElemType);
+ if (!Type)
+ return Fail(
+ format("unknown element type id %d for spec sub-string %d",
+ T->getArray().ElemType, I));
+ } else {
+ return Fail(format("unexpected type kind %d for spec sub-string %d",
+ Type->getKind(), I));
+ }
+ }
+
+ Stream << " (" << FullSpecStr << ")";
+ return;
+ }
+
+ return Fail(format("unknown relocation kind: %d", Reloc->RelocKind));
}
diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
index 689c643a7006..3cafa3a93a0d 100644
--- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -185,7 +185,7 @@ Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
struct FieldListVisitHelper {
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
VisitorDataSource Source)
- : Stream(Data, llvm::support::little), Reader(Stream),
+ : Stream(Data, llvm::endianness::little), Reader(Stream),
Deserializer(Reader),
Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
if (Source == VDS_BytesPresent) {
diff --git a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
index b2f0099bd01c..7e3087373bfa 100644
--- a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
+++ b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -434,6 +434,20 @@ static const EnumEntry<uint16_t> LabelTypeEnum[] = {
CV_ENUM_CLASS_ENT(LabelType, Far),
};
+static const EnumEntry<uint16_t> JumpTableEntrySizeNames[] = {
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Int8),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, UInt8),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Int16),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, UInt16),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Int32),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, UInt32),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Pointer),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, UInt8ShiftLeft),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, UInt16ShiftLeft),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Int8ShiftLeft),
+ CV_ENUM_CLASS_ENT(JumpTableEntrySize, Int16ShiftLeft),
+};
+
namespace llvm {
namespace codeview {
@@ -559,5 +573,9 @@ ArrayRef<EnumEntry<uint16_t>> getLabelTypeEnum() {
return ArrayRef(LabelTypeEnum);
}
+ArrayRef<EnumEntry<uint16_t>> getJumpTableEntrySizeNames() {
+ return ArrayRef(JumpTableEntrySizeNames);
+}
+
} // end namespace codeview
} // end namespace llvm
diff --git a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
index 460f95d96a29..e59a0197d650 100644
--- a/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
+++ b/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -15,7 +15,6 @@
#include "llvm/DebugInfo/CodeView/RecordName.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <algorithm>
#include <cassert>
@@ -69,13 +68,13 @@ void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader,
}
void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) {
- BinaryStreamReader Reader(Data, support::little);
+ BinaryStreamReader Reader(Data, llvm::endianness::little);
reset(Reader, RecordCountHint);
}
void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data,
uint32_t RecordCountHint) {
- BinaryStreamReader Reader(Data, support::little);
+ BinaryStreamReader Reader(Data, llvm::endianness::little);
reset(Reader, RecordCountHint);
}
diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
index 5fbbc4a5d497..e06b036ede63 100644
--- a/llvm/lib/DebugInfo/CodeView/RecordName.cpp
+++ b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
@@ -324,7 +324,7 @@ StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
if (Sym.kind() == SymbolKind::S_CONSTANT) {
// S_CONSTANT is preceded by an APSInt, which has a variable length. So we
// have to do a full deserialization.
- BinaryStreamReader Reader(Sym.content(), llvm::support::little);
+ BinaryStreamReader Reader(Sym.content(), llvm::endianness::little);
// The container doesn't matter for single records.
SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
ConstantSym Const(SymbolKind::S_CONSTANT);
diff --git a/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp b/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
index d76905df8681..032704478ffe 100644
--- a/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
+++ b/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -103,7 +103,7 @@ Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
- BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryByteStream S(Bytes, llvm::endianness::little);
BinaryStreamReader SR(S);
auto EC = consume(SR, Num);
Data = Data.take_back(SR.bytesRemaining());
@@ -129,7 +129,7 @@ Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
- BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryByteStream S(Bytes, llvm::endianness::little);
BinaryStreamReader SR(S);
auto EC = consume(SR, Item);
Data = Data.take_back(SR.bytesRemaining());
diff --git a/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
index cf0c877fdbf8..25725853fb39 100644
--- a/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
@@ -34,7 +34,7 @@ SimpleTypeSerializer::~SimpleTypeSerializer() = default;
template <typename T>
ArrayRef<uint8_t> SimpleTypeSerializer::serialize(T &Record) {
- BinaryStreamWriter Writer(ScratchBuffer, support::little);
+ BinaryStreamWriter Writer(ScratchBuffer, llvm::endianness::little);
TypeRecordMapping Mapping(Writer);
// Write the record prefix first with a dummy length but real kind.
diff --git a/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
index cfb12dbae845..f56739db7c75 100644
--- a/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -589,7 +589,22 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
}
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
- ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers");
+ llvm::StringRef ScopeName;
+ switch (CVR.kind()) {
+ case S_CALLEES:
+ ScopeName = "Callees";
+ break;
+ case S_CALLERS:
+ ScopeName = "Callers";
+ break;
+ case S_INLINEES:
+ ScopeName = "Inlinees";
+ break;
+ default:
+ return llvm::make_error<CodeViewError>(
+ "Unknown CV Record type for a CallerSym object!");
+ }
+ ListScope S(W, ScopeName);
for (auto FuncID : Caller.Indices)
printTypeIndex("FuncID", FuncID);
return Error::success();
@@ -643,6 +658,20 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
return Error::success();
}
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ JumpTableSym &JumpTable) {
+ W.printHex("BaseOffset", JumpTable.BaseOffset);
+ W.printNumber("BaseSegment", JumpTable.BaseSegment);
+ W.printEnum("SwitchType", static_cast<uint16_t>(JumpTable.SwitchType),
+ getJumpTableEntrySizeNames());
+ W.printHex("BranchOffset", JumpTable.BranchOffset);
+ W.printHex("TableOffset", JumpTable.TableOffset);
+ W.printNumber("BranchSegment", JumpTable.BranchSegment);
+ W.printNumber("TableSegment", JumpTable.TableSegment);
+ W.printNumber("EntriesCount", JumpTable.EntriesCount);
+ return Error::success();
+}
+
Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
W.printNumber("Length", CVR.length());
return Error::success();
diff --git a/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
index 3b627930e271..b5e366b965a9 100644
--- a/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
@@ -483,6 +483,19 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
return Error::success();
}
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ JumpTableSym &JumpTable) {
+ error(IO.mapInteger(JumpTable.BaseOffset));
+ error(IO.mapInteger(JumpTable.BaseSegment));
+ error(IO.mapEnum(JumpTable.SwitchType));
+ error(IO.mapInteger(JumpTable.BranchOffset));
+ error(IO.mapInteger(JumpTable.TableOffset));
+ error(IO.mapInteger(JumpTable.BranchSegment));
+ error(IO.mapInteger(JumpTable.TableSegment));
+ error(IO.mapInteger(JumpTable.EntriesCount));
+ return Error::success();
+}
+
RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg,
CPUType CPU) {
assert(unsigned(EncodedReg) < 4);
diff --git a/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
index 5fb8d497b957..eadc50f2da80 100644
--- a/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
+++ b/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
@@ -8,7 +8,6 @@
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
@@ -20,8 +19,8 @@ using namespace llvm::codeview;
SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
CodeViewContainer Container)
- : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream),
- Mapping(Writer, Container) {}
+ : Storage(Allocator), Stream(RecordBuffer, llvm::endianness::little),
+ Writer(Stream), Mapping(Writer, Container) {}
Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
assert(!CurrentSymbol && "Already in a symbol mapping!");
diff --git a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index 682747a2b81f..59e2a85c4d4c 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -442,6 +442,7 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
case SymbolKind::S_THUNK32:
case SymbolKind::S_FRAMECOOKIE:
case SymbolKind::S_UNAMESPACE:
+ case SymbolKind::S_ARMSWITCHTABLE:
break;
// Scope ending symbols.
case SymbolKind::S_END:
@@ -469,7 +470,7 @@ static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
RecordData = RecordData.drop_front(sizeof(RecordPrefix));
- BinaryStreamReader Reader(RecordData, support::little);
+ BinaryStreamReader Reader(RecordData, llvm::endianness::little);
for (const auto &Ref : Refs) {
Reader.setOffset(Ref.Offset);
FixedStreamArray<TypeIndex> Run;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 14962cd36c23..0f9c8ef485d4 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -621,7 +621,10 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
return Off->getAsUnsignedConstant();
// In a per-CU index, the entries without a DW_IDX_compile_unit attribute
- // implicitly refer to the single CU.
+ // implicitly refer to the single CU, but only if we don't have a
+ // DW_IDX_type_unit.
+ if (lookup(dwarf::DW_IDX_type_unit).has_value())
+ return std::nullopt;
if (NameIdx->getCUCount() == 1)
return 0;
return std::nullopt;
@@ -634,8 +637,21 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
return NameIdx->getCUOffset(*Index);
}
+std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {
+ std::optional<uint64_t> Index = getLocalTUIndex();
+ if (!Index || *Index >= NameIdx->getLocalTUCount())
+ return std::nullopt;
+ return NameIdx->getLocalTUOffset(*Index);
+}
+
+std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
+ if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit))
+ return Off->getAsUnsignedConstant();
+ return std::nullopt;
+}
+
void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
- W.printHex("Abbrev", Abbr->Code);
+ W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code);
W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
assert(Abbr->Attributes.size() == Values.size());
for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
@@ -969,3 +985,71 @@ DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {
}
return CUToNameIndex.lookup(CUOffset);
}
+
+static bool isObjCSelector(StringRef Name) {
+ return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') &&
+ (Name[1] == '[');
+}
+
+std::optional<ObjCSelectorNames> llvm::getObjCNamesIfSelector(StringRef Name) {
+ if (!isObjCSelector(Name))
+ return std::nullopt;
+ // "-[Atom setMass:]"
+ StringRef ClassNameStart(Name.drop_front(2));
+ size_t FirstSpace = ClassNameStart.find(' ');
+ if (FirstSpace == StringRef::npos)
+ return std::nullopt;
+
+ StringRef SelectorStart = ClassNameStart.drop_front(FirstSpace + 1);
+ if (!SelectorStart.size())
+ return std::nullopt;
+
+ ObjCSelectorNames Ans;
+ Ans.ClassName = ClassNameStart.take_front(FirstSpace);
+ Ans.Selector = SelectorStart.drop_back(); // drop ']';
+
+ // "-[Class(Category) selector :withArg ...]"
+ if (Ans.ClassName.back() == ')') {
+ size_t OpenParens = Ans.ClassName.find('(');
+ if (OpenParens != StringRef::npos) {
+ Ans.ClassNameNoCategory = Ans.ClassName.take_front(OpenParens);
+
+ Ans.MethodNameNoCategory = Name.take_front(OpenParens + 2);
+ // FIXME: The missing space here may be a bug, but dsymutil-classic also
+ // does it this way.
+ append_range(*Ans.MethodNameNoCategory, SelectorStart);
+ }
+ }
+ return Ans;
+}
+
+std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) {
+ // We are looking for template parameters to strip from Name. e.g.
+ //
+ // operator<<B>
+ //
+ // We look for > at the end but if it does not contain any < then we
+ // have something like operator>>. We check for the operator<=> case.
+ if (!Name.ends_with(">") || Name.count("<") == 0 || Name.ends_with("<=>"))
+ return {};
+
+ // How many < until we have the start of the template parameters.
+ size_t NumLeftAnglesToSkip = 1;
+
+ // If we have operator<=> then we need to skip its < as well.
+ NumLeftAnglesToSkip += Name.count("<=>");
+
+ size_t RightAngleCount = Name.count('>');
+ size_t LeftAngleCount = Name.count('<');
+
+ // If we have more < than > we have operator< or operator<<
+ // we to account for their < as well.
+ if (LeftAngleCount > RightAngleCount)
+ NumLeftAnglesToSkip += LeftAngleCount - RightAngleCount;
+
+ size_t StartOfTemplate = 0;
+ while (NumLeftAnglesToSkip--)
+ StartOfTemplate = Name.find('<', StartOfTemplate) + 1;
+
+ return Name.substr(0, StartOfTemplate - 1);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 33168abbdc38..c671aedbc9e5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -70,13 +70,692 @@ using DWARFLineTable = DWARFDebugLine::LineTable;
using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
+
+void fixupIndexV4(DWARFContext &C, DWARFUnitIndex &Index) {
+ using EntryType = DWARFUnitIndex::Entry::SectionContribution;
+ using EntryMap = DenseMap<uint32_t, EntryType>;
+ EntryMap Map;
+ const auto &DObj = C.getDWARFObj();
+ if (DObj.getCUIndexSection().empty())
+ return;
+
+ uint64_t Offset = 0;
+ uint32_t TruncOffset = 0;
+ DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
+ if (!(C.getParseCUTUIndexManually() ||
+ S.Data.size() >= std::numeric_limits<uint32_t>::max()))
+ return;
+
+ DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0);
+ while (Data.isValidOffset(Offset)) {
+ DWARFUnitHeader Header;
+ if (Error ExtractionErr = Header.extract(
+ C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) {
+ C.getWarningHandler()(
+ createError("Failed to parse CU header in DWP file: " +
+ toString(std::move(ExtractionErr))));
+ Map.clear();
+ break;
+ }
+
+ auto Iter = Map.insert({TruncOffset,
+ {Header.getOffset(), Header.getNextUnitOffset() -
+ Header.getOffset()}});
+ if (!Iter.second) {
+ logAllUnhandledErrors(
+ createError("Collision occured between for truncated offset 0x" +
+ Twine::utohexstr(TruncOffset)),
+ errs());
+ Map.clear();
+ return;
+ }
+
+ Offset = Header.getNextUnitOffset();
+ TruncOffset = Offset;
+ }
+ });
+
+ if (Map.empty())
+ return;
+
+ for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) {
+ if (!E.isValid())
+ continue;
+ DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution();
+ auto Iter = Map.find(CUOff.getOffset());
+ if (Iter == Map.end()) {
+ logAllUnhandledErrors(createError("Could not find CU offset 0x" +
+ Twine::utohexstr(CUOff.getOffset()) +
+ " in the Map"),
+ errs());
+ break;
+ }
+ CUOff.setOffset(Iter->second.getOffset());
+ if (CUOff.getOffset() != Iter->second.getOffset())
+ logAllUnhandledErrors(createError("Length of CU in CU index doesn't "
+ "match calculated length at offset 0x" +
+ Twine::utohexstr(CUOff.getOffset())),
+ errs());
+ }
+}
+
+void fixupIndexV5(DWARFContext &C, DWARFUnitIndex &Index) {
+ DenseMap<uint64_t, uint64_t> Map;
+
+ const auto &DObj = C.getDWARFObj();
+ DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
+ if (!(C.getParseCUTUIndexManually() ||
+ S.Data.size() >= std::numeric_limits<uint32_t>::max()))
+ return;
+ DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0);
+ uint64_t Offset = 0;
+ while (Data.isValidOffset(Offset)) {
+ DWARFUnitHeader Header;
+ if (Error ExtractionErr = Header.extract(
+ C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) {
+ C.getWarningHandler()(
+ createError("Failed to parse CU header in DWP file: " +
+ toString(std::move(ExtractionErr))));
+ break;
+ }
+ bool CU = Header.getUnitType() == DW_UT_split_compile;
+ uint64_t Sig = CU ? *Header.getDWOId() : Header.getTypeHash();
+ Map[Sig] = Header.getOffset();
+ Offset = Header.getNextUnitOffset();
+ }
+ });
+ if (Map.empty())
+ return;
+ for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) {
+ if (!E.isValid())
+ continue;
+ DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution();
+ auto Iter = Map.find(E.getSignature());
+ if (Iter == Map.end()) {
+ logAllUnhandledErrors(
+ createError("Could not find unit with signature 0x" +
+ Twine::utohexstr(E.getSignature()) + " in the Map"),
+ errs());
+ break;
+ }
+ CUOff.setOffset(Iter->second);
+ }
+}
+
+void fixupIndex(DWARFContext &C, DWARFUnitIndex &Index) {
+ if (Index.getVersion() < 5)
+ fixupIndexV4(C, Index);
+ else
+ fixupIndexV5(C, Index);
+}
+
+template <typename T>
+static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj,
+ const DWARFSection &Section, StringRef StringSection,
+ bool IsLittleEndian) {
+ if (Cache)
+ return *Cache;
+ DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
+ DataExtractor StrData(StringSection, IsLittleEndian, 0);
+ Cache = std::make_unique<T>(AccelSection, StrData);
+ if (Error E = Cache->extract())
+ llvm::consumeError(std::move(E));
+ return *Cache;
+}
+
+
+std::unique_ptr<DWARFDebugMacro>
+DWARFContext::DWARFContextState::parseMacroOrMacinfo(MacroSecType SectionType) {
+ auto Macro = std::make_unique<DWARFDebugMacro>();
+ auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) {
+ if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection
+ ? D.compile_units()
+ : D.dwo_compile_units(),
+ SectionType == MacroSection
+ ? D.getStringExtractor()
+ : D.getStringDWOExtractor(),
+ Data)
+ : Macro->parseMacinfo(Data)) {
+ D.getRecoverableErrorHandler()(std::move(Err));
+ Macro = nullptr;
+ }
+ };
+ const DWARFObject &DObj = D.getDWARFObj();
+ switch (SectionType) {
+ case MacinfoSection: {
+ DWARFDataExtractor Data(DObj.getMacinfoSection(), D.isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/false);
+ break;
+ }
+ case MacinfoDwoSection: {
+ DWARFDataExtractor Data(DObj.getMacinfoDWOSection(), D.isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/false);
+ break;
+ }
+ case MacroSection: {
+ DWARFDataExtractor Data(DObj, DObj.getMacroSection(), D.isLittleEndian(),
+ 0);
+ ParseAndDump(Data, /*IsMacro=*/true);
+ break;
+ }
+ case MacroDwoSection: {
+ DWARFDataExtractor Data(DObj.getMacroDWOSection(), D.isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/true);
+ break;
+ }
+ }
+ return Macro;
+}
+
+class ThreadUnsafeDWARFContextState : public DWARFContext::DWARFContextState {
+
+ DWARFUnitVector NormalUnits;
+ std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> NormalTypeUnits;
+ std::unique_ptr<DWARFUnitIndex> CUIndex;
+ std::unique_ptr<DWARFGdbIndex> GdbIndex;
+ std::unique_ptr<DWARFUnitIndex> TUIndex;
+ std::unique_ptr<DWARFDebugAbbrev> Abbrev;
+ std::unique_ptr<DWARFDebugLoc> Loc;
+ std::unique_ptr<DWARFDebugAranges> Aranges;
+ std::unique_ptr<DWARFDebugLine> Line;
+ std::unique_ptr<DWARFDebugFrame> DebugFrame;
+ std::unique_ptr<DWARFDebugFrame> EHFrame;
+ std::unique_ptr<DWARFDebugMacro> Macro;
+ std::unique_ptr<DWARFDebugMacro> Macinfo;
+ std::unique_ptr<DWARFDebugNames> Names;
+ std::unique_ptr<AppleAcceleratorTable> AppleNames;
+ std::unique_ptr<AppleAcceleratorTable> AppleTypes;
+ std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
+ std::unique_ptr<AppleAcceleratorTable> AppleObjC;
+ DWARFUnitVector DWOUnits;
+ std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> DWOTypeUnits;
+ std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
+ std::unique_ptr<DWARFDebugMacro> MacinfoDWO;
+ std::unique_ptr<DWARFDebugMacro> MacroDWO;
+ struct DWOFile {
+ object::OwningBinary<object::ObjectFile> File;
+ std::unique_ptr<DWARFContext> Context;
+ };
+ StringMap<std::weak_ptr<DWOFile>> DWOFiles;
+ std::weak_ptr<DWOFile> DWP;
+ bool CheckedForDWP = false;
+ std::string DWPName;
+
+public:
+ ThreadUnsafeDWARFContextState(DWARFContext &DC, std::string &DWP) :
+ DWARFContext::DWARFContextState(DC),
+ DWPName(std::move(DWP)) {}
+
+ DWARFUnitVector &getNormalUnits() override {
+ if (NormalUnits.empty()) {
+ const DWARFObject &DObj = D.getDWARFObj();
+ DObj.forEachInfoSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(D, S, DW_SECT_INFO);
+ });
+ NormalUnits.finishedInfoUnits();
+ DObj.forEachTypesSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(D, S, DW_SECT_EXT_TYPES);
+ });
+ }
+ return NormalUnits;
+ }
+
+ DWARFUnitVector &getDWOUnits(bool Lazy) override {
+ if (DWOUnits.empty()) {
+ const DWARFObject &DObj = D.getDWARFObj();
+
+ DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(D, S, DW_SECT_INFO, Lazy);
+ });
+ DWOUnits.finishedInfoUnits();
+ DObj.forEachTypesDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(D, S, DW_SECT_EXT_TYPES, Lazy);
+ });
+ }
+ return DWOUnits;
+ }
+
+ const DWARFDebugAbbrev *getDebugAbbrevDWO() override {
+ if (AbbrevDWO)
+ return AbbrevDWO.get();
+ const DWARFObject &DObj = D.getDWARFObj();
+ DataExtractor abbrData(DObj.getAbbrevDWOSection(), D.isLittleEndian(), 0);
+ AbbrevDWO = std::make_unique<DWARFDebugAbbrev>(abbrData);
+ return AbbrevDWO.get();
+ }
+
+ const DWARFUnitIndex &getCUIndex() override {
+ if (CUIndex)
+ return *CUIndex;
+
+ DataExtractor Data(D.getDWARFObj().getCUIndexSection(),
+ D.isLittleEndian(), 0);
+ CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
+ if (CUIndex->parse(Data))
+ fixupIndex(D, *CUIndex);
+ return *CUIndex;
+ }
+ const DWARFUnitIndex &getTUIndex() override {
+ if (TUIndex)
+ return *TUIndex;
+
+ DataExtractor Data(D.getDWARFObj().getTUIndexSection(),
+ D.isLittleEndian(), 0);
+ TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_EXT_TYPES);
+ bool isParseSuccessful = TUIndex->parse(Data);
+ // If we are parsing TU-index and for .debug_types section we don't need
+ // to do anything.
+ if (isParseSuccessful && TUIndex->getVersion() != 2)
+ fixupIndex(D, *TUIndex);
+ return *TUIndex;
+ }
+
+ DWARFGdbIndex &getGdbIndex() override {
+ if (GdbIndex)
+ return *GdbIndex;
+
+ DataExtractor Data(D.getDWARFObj().getGdbIndexSection(), true /*LE*/, 0);
+ GdbIndex = std::make_unique<DWARFGdbIndex>();
+ GdbIndex->parse(Data);
+ return *GdbIndex;
+ }
+
+ const DWARFDebugAbbrev *getDebugAbbrev() override {
+ if (Abbrev)
+ return Abbrev.get();
+
+ DataExtractor Data(D.getDWARFObj().getAbbrevSection(),
+ D.isLittleEndian(), 0);
+ Abbrev = std::make_unique<DWARFDebugAbbrev>(Data);
+ return Abbrev.get();
+ }
+
+ const DWARFDebugLoc *getDebugLoc() override {
+ if (Loc)
+ return Loc.get();
+
+ const DWARFObject &DObj = D.getDWARFObj();
+ // Assume all units have the same address byte size.
+ auto Data =
+ D.getNumCompileUnits()
+ ? DWARFDataExtractor(DObj, DObj.getLocSection(), D.isLittleEndian(),
+ D.getUnitAtIndex(0)->getAddressByteSize())
+ : DWARFDataExtractor("", D.isLittleEndian(), 0);
+ Loc = std::make_unique<DWARFDebugLoc>(std::move(Data));
+ return Loc.get();
+ }
+
+ const DWARFDebugAranges *getDebugAranges() override {
+ if (Aranges)
+ return Aranges.get();
+
+ Aranges = std::make_unique<DWARFDebugAranges>();
+ Aranges->generate(&D);
+ return Aranges.get();
+ }
+
+ Expected<const DWARFDebugLine::LineTable *>
+ getLineTableForUnit(DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) override {
+ if (!Line)
+ Line = std::make_unique<DWARFDebugLine>();
+
+ auto UnitDIE = U->getUnitDIE();
+ if (!UnitDIE)
+ return nullptr;
+
+ auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
+ if (!Offset)
+ return nullptr; // No line table for this compile unit.
+
+ uint64_t stmtOffset = *Offset + U->getLineTableOffset();
+ // See if the line table is cached.
+ if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
+ return lt;
+
+ // Make sure the offset is good before we try to parse.
+ if (stmtOffset >= U->getLineSection().Data.size())
+ return nullptr;
+
+ // We have to parse it first.
+ DWARFDataExtractor Data(U->getContext().getDWARFObj(), U->getLineSection(),
+ U->isLittleEndian(), U->getAddressByteSize());
+ return Line->getOrParseLineTable(Data, stmtOffset, U->getContext(), U,
+ RecoverableErrorHandler);
+
+ }
+
+ void clearLineTableForUnit(DWARFUnit *U) override {
+ if (!Line)
+ return;
+
+ auto UnitDIE = U->getUnitDIE();
+ if (!UnitDIE)
+ return;
+
+ auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
+ if (!Offset)
+ return;
+
+ uint64_t stmtOffset = *Offset + U->getLineTableOffset();
+ Line->clearLineTable(stmtOffset);
+ }
+
+ Expected<const DWARFDebugFrame *> getDebugFrame() override {
+ if (DebugFrame)
+ return DebugFrame.get();
+ const DWARFObject &DObj = D.getDWARFObj();
+ 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",
+ // which isn't specified in DWARF in general. It's only specified for CUs, but
+ // .eh_frame can appear without a .debug_info section. Follow the example of
+ // other tools (libdwarf) and extract this from the container (ObjectFile
+ // 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 Data(DObj, DS, D.isLittleEndian(),
+ DObj.getAddressSize());
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(D.getArch(), /*IsEH=*/false,
+ DS.Address);
+ if (Error E = DF->parse(Data))
+ return std::move(E);
+
+ DebugFrame.swap(DF);
+ return DebugFrame.get();
+ }
+
+ Expected<const DWARFDebugFrame *> getEHFrame() override {
+ if (EHFrame)
+ return EHFrame.get();
+ const DWARFObject &DObj = D.getDWARFObj();
+
+ const DWARFSection &DS = DObj.getEHFrameSection();
+ DWARFDataExtractor Data(DObj, DS, D.isLittleEndian(),
+ DObj.getAddressSize());
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(D.getArch(), /*IsEH=*/true,
+ DS.Address);
+ if (Error E = DF->parse(Data))
+ return std::move(E);
+ EHFrame.swap(DF);
+ return EHFrame.get();
+ }
+
+ const DWARFDebugMacro *getDebugMacinfo() override {
+ if (!Macinfo)
+ Macinfo = parseMacroOrMacinfo(MacinfoSection);
+ return Macinfo.get();
+ }
+ const DWARFDebugMacro *getDebugMacinfoDWO() override {
+ if (!MacinfoDWO)
+ MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection);
+ return MacinfoDWO.get();
+ }
+ const DWARFDebugMacro *getDebugMacro() override {
+ if (!Macro)
+ Macro = parseMacroOrMacinfo(MacroSection);
+ return Macro.get();
+ }
+ const DWARFDebugMacro *getDebugMacroDWO() override {
+ if (!MacroDWO)
+ MacroDWO = parseMacroOrMacinfo(MacroDwoSection);
+ return MacroDWO.get();
+ }
+ const DWARFDebugNames &getDebugNames() override {
+ const DWARFObject &DObj = D.getDWARFObj();
+ return getAccelTable(Names, DObj, DObj.getNamesSection(),
+ DObj.getStrSection(), D.isLittleEndian());
+ }
+ const AppleAcceleratorTable &getAppleNames() override {
+ const DWARFObject &DObj = D.getDWARFObj();
+ return getAccelTable(AppleNames, DObj, DObj.getAppleNamesSection(),
+ DObj.getStrSection(), D.isLittleEndian());
+
+ }
+ const AppleAcceleratorTable &getAppleTypes() override {
+ const DWARFObject &DObj = D.getDWARFObj();
+ return getAccelTable(AppleTypes, DObj, DObj.getAppleTypesSection(),
+ DObj.getStrSection(), D.isLittleEndian());
+
+ }
+ const AppleAcceleratorTable &getAppleNamespaces() override {
+ const DWARFObject &DObj = D.getDWARFObj();
+ return getAccelTable(AppleNamespaces, DObj,
+ DObj.getAppleNamespacesSection(),
+ DObj.getStrSection(), D.isLittleEndian());
+
+ }
+ const AppleAcceleratorTable &getAppleObjC() override {
+ const DWARFObject &DObj = D.getDWARFObj();
+ return getAccelTable(AppleObjC, DObj, DObj.getAppleObjCSection(),
+ DObj.getStrSection(), D.isLittleEndian());
+ }
+
+ std::shared_ptr<DWARFContext>
+ getDWOContext(StringRef AbsolutePath) override {
+ if (auto S = DWP.lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
+
+ if (auto S = Entry->lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ const DWARFObject &DObj = D.getDWARFObj();
+
+ Expected<OwningBinary<ObjectFile>> Obj = [&] {
+ if (!CheckedForDWP) {
+ SmallString<128> DWPName;
+ auto Obj = object::ObjectFile::createObjectFile(
+ this->DWPName.empty()
+ ? (DObj.getFileName() + ".dwp").toStringRef(DWPName)
+ : StringRef(this->DWPName));
+ if (Obj) {
+ Entry = &DWP;
+ return Obj;
+ } else {
+ CheckedForDWP = true;
+ // TODO: Should this error be handled (maybe in a high verbosity mode)
+ // before falling back to .dwo files?
+ consumeError(Obj.takeError());
+ }
+ }
+
+ return object::ObjectFile::createObjectFile(AbsolutePath);
+ }();
+
+ if (!Obj) {
+ // TODO: Actually report errors helpfully.
+ consumeError(Obj.takeError());
+ return nullptr;
+ }
+
+ auto S = std::make_shared<DWOFile>();
+ S->File = std::move(Obj.get());
+ // Allow multi-threaded access if there is a .dwp file as the CU index and
+ // TU index might be accessed from multiple threads.
+ bool ThreadSafe = isThreadSafe();
+ S->Context = DWARFContext::create(
+ *S->File.getBinary(), DWARFContext::ProcessDebugRelocations::Ignore,
+ nullptr, "", WithColor::defaultErrorHandler,
+ WithColor::defaultWarningHandler, ThreadSafe);
+ *Entry = S;
+ auto *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ bool isThreadSafe() const override { return false; }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &getNormalTypeUnitMap() {
+ if (!NormalTypeUnits) {
+ NormalTypeUnits.emplace();
+ for (const auto &U :D.normal_units()) {
+ if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
+ (*NormalTypeUnits)[TU->getTypeHash()] = TU;
+ }
+ }
+ return *NormalTypeUnits;
+ }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &getDWOTypeUnitMap() {
+ if (!DWOTypeUnits) {
+ DWOTypeUnits.emplace();
+ for (const auto &U :D.dwo_units()) {
+ if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
+ (*DWOTypeUnits)[TU->getTypeHash()] = TU;
+ }
+ }
+ return *DWOTypeUnits;
+ }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &
+ getTypeUnitMap(bool IsDWO) override {
+ if (IsDWO)
+ return getDWOTypeUnitMap();
+ else
+ return getNormalTypeUnitMap();
+ }
+
+
+};
+
+class ThreadSafeState : public ThreadUnsafeDWARFContextState {
+ std::recursive_mutex Mutex;
+
+public:
+ ThreadSafeState(DWARFContext &DC, std::string &DWP) :
+ ThreadUnsafeDWARFContextState(DC, DWP) {}
+
+ DWARFUnitVector &getNormalUnits() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getNormalUnits();
+ }
+ DWARFUnitVector &getDWOUnits(bool Lazy) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ // We need to not do lazy parsing when we need thread safety as
+ // DWARFUnitVector, in lazy mode, will slowly add things to itself and
+ // will cause problems in a multi-threaded environment.
+ return ThreadUnsafeDWARFContextState::getDWOUnits(false);
+ }
+ const DWARFUnitIndex &getCUIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getCUIndex();
+ }
+ const DWARFDebugAbbrev *getDebugAbbrevDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAbbrevDWO();
+ }
+
+ const DWARFUnitIndex &getTUIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getTUIndex();
+ }
+ DWARFGdbIndex &getGdbIndex() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getGdbIndex();
+ }
+ const DWARFDebugAbbrev *getDebugAbbrev() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAbbrev();
+ }
+ const DWARFDebugLoc *getDebugLoc() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugLoc();
+ }
+ const DWARFDebugAranges *getDebugAranges() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugAranges();
+ }
+ Expected<const DWARFDebugLine::LineTable *>
+ getLineTableForUnit(DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getLineTableForUnit(U, RecoverableErrorHandler);
+ }
+ void clearLineTableForUnit(DWARFUnit *U) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::clearLineTableForUnit(U);
+ }
+ Expected<const DWARFDebugFrame *> getDebugFrame() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugFrame();
+ }
+ Expected<const DWARFDebugFrame *> getEHFrame() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getEHFrame();
+ }
+ const DWARFDebugMacro *getDebugMacinfo() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacinfo();
+ }
+ const DWARFDebugMacro *getDebugMacinfoDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacinfoDWO();
+ }
+ const DWARFDebugMacro *getDebugMacro() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacro();
+ }
+ const DWARFDebugMacro *getDebugMacroDWO() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugMacroDWO();
+ }
+ const DWARFDebugNames &getDebugNames() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDebugNames();
+ }
+ const AppleAcceleratorTable &getAppleNames() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleNames();
+ }
+ const AppleAcceleratorTable &getAppleTypes() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleTypes();
+ }
+ const AppleAcceleratorTable &getAppleNamespaces() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleNamespaces();
+ }
+ const AppleAcceleratorTable &getAppleObjC() override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getAppleObjC();
+ }
+ std::shared_ptr<DWARFContext>
+ getDWOContext(StringRef AbsolutePath) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getDWOContext(AbsolutePath);
+ }
+
+ bool isThreadSafe() const override { return true; }
+
+ const DenseMap<uint64_t, DWARFTypeUnit *> &
+ getTypeUnitMap(bool IsDWO) override {
+ std::unique_lock<std::recursive_mutex> LockGuard(Mutex);
+ return ThreadUnsafeDWARFContextState::getTypeUnitMap(IsDWO);
+ }
+};
+
+
+
DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
std::string DWPName,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler)
- : DIContext(CK_DWARF), DWPName(std::move(DWPName)),
+ std::function<void(Error)> WarningHandler,
+ bool ThreadSafe)
+ : DIContext(CK_DWARF),
RecoverableErrorHandler(RecoverableErrorHandler),
- WarningHandler(WarningHandler), DObj(std::move(DObj)) {}
+ WarningHandler(WarningHandler), DObj(std::move(DObj)) {
+ if (ThreadSafe)
+ State = std::make_unique<ThreadSafeState>(*this, DWPName);
+ else
+ State = std::make_unique<ThreadUnsafeDWARFContextState>(*this, DWPName);
+ }
DWARFContext::~DWARFContext() = default;
@@ -266,47 +945,6 @@ static void dumpRnglistsSection(
}
}
-std::unique_ptr<DWARFDebugMacro>
-DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) {
- auto Macro = std::make_unique<DWARFDebugMacro>();
- auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) {
- if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection
- ? compile_units()
- : dwo_compile_units(),
- SectionType == MacroSection
- ? getStringExtractor()
- : getStringDWOExtractor(),
- Data)
- : Macro->parseMacinfo(Data)) {
- RecoverableErrorHandler(std::move(Err));
- Macro = nullptr;
- }
- };
- switch (SectionType) {
- case MacinfoSection: {
- DWARFDataExtractor Data(DObj->getMacinfoSection(), isLittleEndian(), 0);
- ParseAndDump(Data, /*IsMacro=*/false);
- break;
- }
- case MacinfoDwoSection: {
- DWARFDataExtractor Data(DObj->getMacinfoDWOSection(), isLittleEndian(), 0);
- ParseAndDump(Data, /*IsMacro=*/false);
- break;
- }
- case MacroSection: {
- DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(),
- 0);
- ParseAndDump(Data, /*IsMacro=*/true);
- break;
- }
- case MacroDwoSection: {
- DWARFDataExtractor Data(DObj->getMacroDWOSection(), isLittleEndian(), 0);
- ParseAndDump(Data, /*IsMacro=*/true);
- break;
- }
- }
- return Macro;
-}
static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
DWARFDataExtractor Data, const DWARFObject &Obj,
@@ -700,34 +1338,22 @@ void DWARFContext::dump(
DWARFTypeUnit *DWARFContext::getTypeUnitForHash(uint16_t Version, uint64_t Hash,
bool IsDWO) {
- parseDWOUnits(LazyParse);
-
+ DWARFUnitVector &DWOUnits = State->getDWOUnits();
if (const auto &TUI = getTUIndex()) {
if (const auto *R = TUI.getFromHash(Hash))
return dyn_cast_or_null<DWARFTypeUnit>(
DWOUnits.getUnitForIndexEntry(*R));
return nullptr;
}
-
- struct UnitContainers {
- const DWARFUnitVector &Units;
- std::optional<DenseMap<uint64_t, DWARFTypeUnit *>> &Map;
- };
- UnitContainers Units = IsDWO ? UnitContainers{DWOUnits, DWOTypeUnits}
- : UnitContainers{NormalUnits, NormalTypeUnits};
- if (!Units.Map) {
- Units.Map.emplace();
- for (const auto &U : IsDWO ? dwo_units() : normal_units()) {
- if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
- (*Units.Map)[TU->getTypeHash()] = TU;
- }
- }
-
- return (*Units.Map)[Hash];
+ const DenseMap<uint64_t, DWARFTypeUnit *> &Map = State->getTypeUnitMap(IsDWO);
+ auto Iter = Map.find(Hash);
+ if (Iter != Map.end())
+ return Iter->second;
+ return nullptr;
}
DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
- parseDWOUnits(LazyParse);
+ DWARFUnitVector &DWOUnits = State->getDWOUnits(LazyParse);
if (const auto &CUI = getCUIndex()) {
if (const auto *R = CUI.getFromHash(Hash))
@@ -757,8 +1383,7 @@ DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
}
DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) {
- parseNormalUnits();
- if (auto *CU = NormalUnits.getUnitForOffset(Offset))
+ if (auto *CU = State->getNormalUnits().getUnitForOffset(Offset))
return CU->getDIEForOffset(Offset);
return DWARFDie();
}
@@ -782,302 +1407,77 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
return Success;
}
-void fixupIndexV4(const DWARFObject &DObj, DWARFContext &C,
- DWARFUnitIndex &Index) {
- using EntryType = DWARFUnitIndex::Entry::SectionContribution;
- using EntryMap = DenseMap<uint32_t, EntryType>;
- EntryMap Map;
- if (DObj.getCUIndexSection().empty())
- return;
-
- uint64_t Offset = 0;
- uint32_t TruncOffset = 0;
- DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
- if (!(C.getParseCUTUIndexManually() ||
- S.Data.size() >= std::numeric_limits<uint32_t>::max()))
- return;
-
- DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0);
- while (Data.isValidOffset(Offset)) {
- DWARFUnitHeader Header;
- if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) {
- logAllUnhandledErrors(
- createError("Failed to parse CU header in DWP file"), errs());
- Map.clear();
- break;
- }
-
- auto Iter = Map.insert({TruncOffset,
- {Header.getOffset(), Header.getNextUnitOffset() -
- Header.getOffset()}});
- if (!Iter.second) {
- logAllUnhandledErrors(
- createError("Collision occured between for truncated offset 0x" +
- Twine::utohexstr(TruncOffset)),
- errs());
- Map.clear();
- return;
- }
-
- Offset = Header.getNextUnitOffset();
- TruncOffset = Offset;
- }
- });
-
- if (Map.empty())
- return;
-
- for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) {
- if (!E.isValid())
- continue;
- DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution();
- auto Iter = Map.find(CUOff.getOffset());
- if (Iter == Map.end()) {
- logAllUnhandledErrors(createError("Could not find CU offset 0x" +
- Twine::utohexstr(CUOff.getOffset()) +
- " in the Map"),
- errs());
- break;
- }
- CUOff.setOffset(Iter->second.getOffset());
- if (CUOff.getOffset() != Iter->second.getOffset())
- logAllUnhandledErrors(createError("Length of CU in CU index doesn't "
- "match calculated length at offset 0x" +
- Twine::utohexstr(CUOff.getOffset())),
- errs());
- }
-}
-
-void fixupIndexV5(const DWARFObject &DObj, DWARFContext &C,
- DWARFUnitIndex &Index) {
- DenseMap<uint64_t, uint64_t> Map;
-
- DObj.forEachInfoDWOSections([&](const DWARFSection &S) {
- if (!(C.getParseCUTUIndexManually() ||
- S.Data.size() >= std::numeric_limits<uint32_t>::max()))
- return;
- DWARFDataExtractor Data(DObj, S, C.isLittleEndian(), 0);
- uint64_t Offset = 0;
- while (Data.isValidOffset(Offset)) {
- DWARFUnitHeader Header;
- if (!Header.extract(C, Data, &Offset, DWARFSectionKind::DW_SECT_INFO)) {
- logAllUnhandledErrors(
- createError("Failed to parse unit header in DWP file"), errs());
- break;
- }
- bool CU = Header.getUnitType() == DW_UT_split_compile;
- uint64_t Sig = CU ? *Header.getDWOId() : Header.getTypeHash();
- Map[Sig] = Header.getOffset();
- Offset = Header.getNextUnitOffset();
- }
- });
- if (Map.empty())
- return;
- for (DWARFUnitIndex::Entry &E : Index.getMutableRows()) {
- if (!E.isValid())
- continue;
- DWARFUnitIndex::Entry::SectionContribution &CUOff = E.getContribution();
- auto Iter = Map.find(E.getSignature());
- if (Iter == Map.end()) {
- logAllUnhandledErrors(
- createError("Could not find unit with signature 0x" +
- Twine::utohexstr(E.getSignature()) + " in the Map"),
- errs());
- break;
- }
- CUOff.setOffset(Iter->second);
- }
-}
-
-void fixupIndex(const DWARFObject &DObj, DWARFContext &C,
- DWARFUnitIndex &Index) {
- if (Index.getVersion() < 5)
- fixupIndexV4(DObj, C, Index);
- else
- fixupIndexV5(DObj, C, Index);
-}
-
const DWARFUnitIndex &DWARFContext::getCUIndex() {
- if (CUIndex)
- return *CUIndex;
-
- DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
- CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
- bool IsParseSuccessful = CUIndex->parse(CUIndexData);
- if (IsParseSuccessful)
- fixupIndex(*DObj, *this, *CUIndex);
- return *CUIndex;
+ return State->getCUIndex();
}
const DWARFUnitIndex &DWARFContext::getTUIndex() {
- if (TUIndex)
- return *TUIndex;
-
- DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
- TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_EXT_TYPES);
- bool isParseSuccessful = TUIndex->parse(TUIndexData);
- // If we are parsing TU-index and for .debug_types section we don't need
- // to do anything.
- if (isParseSuccessful && TUIndex->getVersion() != 2)
- fixupIndex(*DObj, *this, *TUIndex);
- return *TUIndex;
+ return State->getTUIndex();
}
DWARFGdbIndex &DWARFContext::getGdbIndex() {
- if (GdbIndex)
- return *GdbIndex;
-
- DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
- GdbIndex = std::make_unique<DWARFGdbIndex>();
- GdbIndex->parse(GdbIndexData);
- return *GdbIndex;
+ return State->getGdbIndex();
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
- if (Abbrev)
- return Abbrev.get();
-
- DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
- Abbrev = std::make_unique<DWARFDebugAbbrev>(abbrData);
- return Abbrev.get();
+ return State->getDebugAbbrev();
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
- if (AbbrevDWO)
- return AbbrevDWO.get();
-
- DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
- AbbrevDWO = std::make_unique<DWARFDebugAbbrev>(abbrData);
- return AbbrevDWO.get();
+ return State->getDebugAbbrevDWO();
}
const DWARFDebugLoc *DWARFContext::getDebugLoc() {
- if (Loc)
- return Loc.get();
-
- // Assume all units have the same address byte size.
- auto LocData =
- getNumCompileUnits()
- ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(),
- getUnitAtIndex(0)->getAddressByteSize())
- : DWARFDataExtractor("", isLittleEndian(), 0);
- Loc.reset(new DWARFDebugLoc(std::move(LocData)));
- return Loc.get();
+ return State->getDebugLoc();
}
const DWARFDebugAranges *DWARFContext::getDebugAranges() {
- if (Aranges)
- return Aranges.get();
-
- Aranges.reset(new DWARFDebugAranges());
- Aranges->generate(this);
- return Aranges.get();
+ return State->getDebugAranges();
}
Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
- if (DebugFrame)
- return DebugFrame.get();
-
- const DWARFSection &DS = DObj->getFrameSection();
-
- // There's a "bug" in the DWARFv3 standard with respect to the target address
- // size within debug frame sections. While DWARF is supposed to be independent
- // of its container, FDEs have fields with size being "target address size",
- // which isn't specified in DWARF in general. It's only specified for CUs, but
- // .eh_frame can appear without a .debug_info section. Follow the example of
- // other tools (libdwarf) and extract this from the container (ObjectFile
- // 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, 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);
- return DebugFrame.get();
+ return State->getDebugFrame();
}
Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
- if (EHFrame)
- return EHFrame.get();
-
- const DWARFSection &DS = DObj->getEHFrameSection();
- DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
- DObj->getAddressSize());
-
- 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();
+ return State->getEHFrame();
}
const DWARFDebugMacro *DWARFContext::getDebugMacro() {
- if (!Macro)
- Macro = parseMacroOrMacinfo(MacroSection);
- return Macro.get();
+ return State->getDebugMacro();
}
const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() {
- if (!MacroDWO)
- MacroDWO = parseMacroOrMacinfo(MacroDwoSection);
- return MacroDWO.get();
+ return State->getDebugMacroDWO();
}
const DWARFDebugMacro *DWARFContext::getDebugMacinfo() {
- if (!Macinfo)
- Macinfo = parseMacroOrMacinfo(MacinfoSection);
- return Macinfo.get();
+ return State->getDebugMacinfo();
}
const DWARFDebugMacro *DWARFContext::getDebugMacinfoDWO() {
- if (!MacinfoDWO)
- MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection);
- return MacinfoDWO.get();
+ return State->getDebugMacinfoDWO();
}
-template <typename T>
-static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj,
- const DWARFSection &Section, StringRef StringSection,
- bool IsLittleEndian) {
- if (Cache)
- return *Cache;
- DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
- DataExtractor StrData(StringSection, IsLittleEndian, 0);
- Cache.reset(new T(AccelSection, StrData));
- if (Error E = Cache->extract())
- llvm::consumeError(std::move(E));
- return *Cache;
-}
const DWARFDebugNames &DWARFContext::getDebugNames() {
- return getAccelTable(Names, *DObj, DObj->getNamesSection(),
- DObj->getStrSection(), isLittleEndian());
+ return State->getDebugNames();
}
const AppleAcceleratorTable &DWARFContext::getAppleNames() {
- return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
- DObj->getStrSection(), isLittleEndian());
+ return State->getAppleNames();
}
const AppleAcceleratorTable &DWARFContext::getAppleTypes() {
- return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
- DObj->getStrSection(), isLittleEndian());
+ return State->getAppleTypes();
}
const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() {
- return getAccelTable(AppleNamespaces, *DObj,
- DObj->getAppleNamespacesSection(),
- DObj->getStrSection(), isLittleEndian());
+ return State->getAppleNamespaces();
}
const AppleAcceleratorTable &DWARFContext::getAppleObjC() {
- return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
- DObj->getStrSection(), isLittleEndian());
+ return State->getAppleObjC();
}
const DWARFDebugLine::LineTable *
@@ -1093,77 +1493,20 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) {
- if (!Line)
- Line.reset(new DWARFDebugLine);
-
- auto UnitDIE = U->getUnitDIE();
- if (!UnitDIE)
- return nullptr;
-
- auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
- if (!Offset)
- return nullptr; // No line table for this compile unit.
-
- uint64_t stmtOffset = *Offset + U->getLineTableOffset();
- // See if the line table is cached.
- if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
- return lt;
-
- // Make sure the offset is good before we try to parse.
- if (stmtOffset >= U->getLineSection().Data.size())
- return nullptr;
-
- // We have to parse it first.
- DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
- U->getAddressByteSize());
- return Line->getOrParseLineTable(lineData, stmtOffset, *this, U,
- RecoverableErrorHandler);
+ return State->getLineTableForUnit(U, RecoverableErrorHandler);
}
void DWARFContext::clearLineTableForUnit(DWARFUnit *U) {
- if (!Line)
- return;
-
- auto UnitDIE = U->getUnitDIE();
- if (!UnitDIE)
- return;
-
- auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
- if (!Offset)
- return;
-
- uint64_t stmtOffset = *Offset + U->getLineTableOffset();
- Line->clearLineTable(stmtOffset);
+ return State->clearLineTableForUnit(U);
}
-void DWARFContext::parseNormalUnits() {
- if (!NormalUnits.empty())
- return;
- DObj->forEachInfoSections([&](const DWARFSection &S) {
- NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO);
- });
- NormalUnits.finishedInfoUnits();
- DObj->forEachTypesSections([&](const DWARFSection &S) {
- NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES);
- });
-}
-
-void DWARFContext::parseDWOUnits(bool Lazy) {
- if (!DWOUnits.empty())
- return;
- DObj->forEachInfoDWOSections([&](const DWARFSection &S) {
- DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy);
- });
- DWOUnits.finishedInfoUnits();
- DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
- DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy);
- });
+DWARFUnitVector &DWARFContext::getDWOUnits(bool Lazy) {
+ return State->getDWOUnits(Lazy);
}
DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) {
- parseNormalUnits();
return dyn_cast_or_null<DWARFCompileUnit>(
- NormalUnits.getUnitForOffset(Offset));
+ State->getNormalUnits().getUnitForOffset(Offset));
}
DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) {
@@ -1187,7 +1530,7 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForDataAddress(uint64_t Address) {
// So, we walk the CU's and their child DI's manually, looking for the
// specific global variable.
for (std::unique_ptr<DWARFUnit> &CU : compile_units()) {
- if (DWARFDie Die = CU->getVariableForAddress(Address)) {
+ if (CU->getVariableForAddress(Address)) {
return static_cast<DWARFCompileUnit *>(CU.get());
}
}
@@ -1519,52 +1862,7 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
std::shared_ptr<DWARFContext>
DWARFContext::getDWOContext(StringRef AbsolutePath) {
- if (auto S = DWP.lock()) {
- DWARFContext *Ctxt = S->Context.get();
- return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
- }
-
- std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
-
- if (auto S = Entry->lock()) {
- DWARFContext *Ctxt = S->Context.get();
- return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
- }
-
- Expected<OwningBinary<ObjectFile>> Obj = [&] {
- if (!CheckedForDWP) {
- SmallString<128> DWPName;
- auto Obj = object::ObjectFile::createObjectFile(
- this->DWPName.empty()
- ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
- : StringRef(this->DWPName));
- if (Obj) {
- Entry = &DWP;
- return Obj;
- } else {
- CheckedForDWP = true;
- // TODO: Should this error be handled (maybe in a high verbosity mode)
- // before falling back to .dwo files?
- consumeError(Obj.takeError());
- }
- }
-
- return object::ObjectFile::createObjectFile(AbsolutePath);
- }();
-
- if (!Obj) {
- // TODO: Actually report errors helpfully.
- consumeError(Obj.takeError());
- return nullptr;
- }
-
- auto S = std::make_shared<DWOFile>();
- S->File = std::move(Obj.get());
- S->Context = DWARFContext::create(*S->File.getBinary(),
- ProcessDebugRelocations::Ignore);
- *Entry = S;
- auto *Ctxt = S->Context.get();
- return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ return State->getDWOContext(AbsolutePath);
}
static Error createError(const Twine &Reason, llvm::Error E) {
@@ -1909,7 +2207,7 @@ public:
continue;
if (!Section.relocations().empty() && Name.ends_with(".dwo") &&
- RelSecName.startswith(".debug")) {
+ RelSecName.starts_with(".debug")) {
HandleWarning(createError("unexpected relocations for dwo section '" +
RelSecName + "'"));
}
@@ -2115,23 +2413,27 @@ DWARFContext::create(const object::ObjectFile &Obj,
ProcessDebugRelocations RelocAction,
const LoadedObjectInfo *L, std::string DWPName,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler) {
+ std::function<void(Error)> WarningHandler,
+ bool ThreadSafe) {
auto DObj = std::make_unique<DWARFObjInMemory>(
Obj, L, RecoverableErrorHandler, WarningHandler, RelocAction);
- return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName),
+ return std::make_unique<DWARFContext>(std::move(DObj),
+ std::move(DWPName),
RecoverableErrorHandler,
- WarningHandler);
+ WarningHandler,
+ ThreadSafe);
}
std::unique_ptr<DWARFContext>
DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
uint8_t AddrSize, bool isLittleEndian,
std::function<void(Error)> RecoverableErrorHandler,
- std::function<void(Error)> WarningHandler) {
+ std::function<void(Error)> WarningHandler,
+ bool ThreadSafe) {
auto DObj =
std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
return std::make_unique<DWARFContext>(
- std::move(DObj), "", RecoverableErrorHandler, WarningHandler);
+ std::move(DObj), "", RecoverableErrorHandler, WarningHandler, ThreadSafe);
}
uint8_t DWARFContext::getCUAddrSize() {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
index 3014e61f566a..85959ecc5e17 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -105,9 +105,9 @@ std::string DWARFAbbreviationDeclarationSet::getCodeRange() const {
DWARFDebugAbbrev::DWARFDebugAbbrev(DataExtractor Data)
: AbbrDeclSets(), PrevAbbrOffsetPos(AbbrDeclSets.end()), Data(Data) {}
-void DWARFDebugAbbrev::parse() const {
+Error DWARFDebugAbbrev::parse() const {
if (!Data)
- return;
+ return Error::success();
uint64_t Offset = 0;
auto I = AbbrDeclSets.begin();
while (Data->isValidOffset(Offset)) {
@@ -116,17 +116,19 @@ void DWARFDebugAbbrev::parse() const {
uint64_t CUAbbrOffset = Offset;
DWARFAbbreviationDeclarationSet AbbrDecls;
if (Error Err = AbbrDecls.extract(*Data, &Offset)) {
- // FIXME: We should propagate the error upwards.
- consumeError(std::move(Err));
- break;
+ Data = std::nullopt;
+ return Err;
}
AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls)));
}
Data = std::nullopt;
+ return Error::success();
}
void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
- parse();
+ if (Error Err = parse())
+ // FIXME: We should propagate this error or otherwise display it.
+ llvm::consumeError(std::move(Err));
if (AbbrDeclSets.empty()) {
OS << "< EMPTY >\n";
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 6f2afe5d50e9..78792cf83891 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -170,9 +170,14 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
if (ContentTypes.HasLength)
OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length);
if (ContentTypes.HasSource) {
- OS << " source: ";
- FileEntry.Source.dump(OS, DumpOptions);
- OS << '\n';
+ auto Source = FileEntry.Source.getAsCString();
+ if (!Source)
+ consumeError(Source.takeError());
+ else if ((*Source)[0]) {
+ OS << " source: ";
+ FileEntry.Source.dump(OS, DumpOptions);
+ OS << '\n';
+ }
}
}
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 7af7ed8be7b4..66492f7bf804 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
@@ -147,7 +148,8 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
if (!Name.empty())
WithColor(OS, Color) << Name;
- else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) {
+ else if (Attr == DW_AT_decl_line || Attr == DW_AT_decl_column ||
+ Attr == DW_AT_call_line || Attr == DW_AT_call_column) {
if (std::optional<uint64_t> Val = FormValue.getAsUnsignedConstant())
OS << *Val;
else
@@ -189,7 +191,8 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
// We have dumped the attribute raw value. For some attributes
// having both the raw value and the pretty-printed value is
// interesting. These attributes are handled below.
- if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) {
+ if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin ||
+ Attr == DW_AT_call_origin) {
if (const char *Name =
Die.getAttributeValueAsReferencedDie(FormValue).getName(
DINameKind::LinkageName))
@@ -487,18 +490,23 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
}
-std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
- if (auto SizeAttr = find(DW_AT_byte_size))
+static std::optional<uint64_t>
+getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize,
+ SmallPtrSetImpl<const DWARFDebugInfoEntry *> &Visited) {
+ // Cycle detected?
+ if (!Visited.insert(Die.getDebugInfoEntry()).second)
+ return {};
+ if (auto SizeAttr = Die.find(DW_AT_byte_size))
if (std::optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant())
return Size;
- switch (getTag()) {
+ switch (Die.getTag()) {
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
case DW_TAG_rvalue_reference_type:
return PointerSize;
case DW_TAG_ptr_to_member_type: {
- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
+ if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
if (BaseType.getTag() == DW_TAG_subroutine_type)
return 2 * PointerSize;
return PointerSize;
@@ -508,19 +516,20 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
case DW_TAG_volatile_type:
case DW_TAG_restrict_type:
case DW_TAG_typedef: {
- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
- return BaseType.getTypeSize(PointerSize);
+ if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
+ return getTypeSizeImpl(BaseType, PointerSize, Visited);
break;
}
case DW_TAG_array_type: {
- DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type);
+ DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type);
if (!BaseType)
return std::nullopt;
- std::optional<uint64_t> BaseSize = BaseType.getTypeSize(PointerSize);
+ std::optional<uint64_t> BaseSize =
+ getTypeSizeImpl(BaseType, PointerSize, Visited);
if (!BaseSize)
return std::nullopt;
uint64_t Size = *BaseSize;
- for (DWARFDie Child : *this) {
+ for (DWARFDie Child : Die) {
if (Child.getTag() != DW_TAG_subrange_type)
continue;
@@ -540,13 +549,18 @@ std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
return Size;
}
default:
- if (DWARFDie BaseType = getAttributeValueAsReferencedDie(DW_AT_type))
- return BaseType.getTypeSize(PointerSize);
+ if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
+ return getTypeSizeImpl(BaseType, PointerSize, Visited);
break;
}
return std::nullopt;
}
+std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) {
+ SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited;
+ return getTypeSizeImpl(*this, PointerSize, Visited);
+}
+
/// Helper to dump a DIE with all of its parents, but no siblings.
static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
DIDumpOptions DumpOpts, unsigned Depth = 0) {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
index c474de607626..20242d958b6b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
@@ -8,7 +8,7 @@ void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
StringRef TagStr = TagString(T);
static constexpr StringRef Prefix = "DW_TAG_";
static constexpr StringRef Suffix = "_type";
- if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
+ if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
return;
OS << TagStr.substr(Prefix.size(),
TagStr.size() - (Prefix.size() + Suffix.size()))
@@ -181,7 +181,7 @@ DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
Word = true;
StringRef Name = NamePtr;
static constexpr StringRef MangledPrefix = "_STN|";
- if (Name.startswith(MangledPrefix)) {
+ if (Name.starts_with(MangledPrefix)) {
Name = Name.drop_front(MangledPrefix.size());
auto Separator = Name.find('|');
assert(Separator != StringRef::npos);
@@ -191,12 +191,12 @@ DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
*OriginalFullName = (BaseName + TemplateArgs).str();
Name = BaseName;
} else
- EndedWithTemplate = Name.endswith(">");
+ EndedWithTemplate = Name.ends_with(">");
OS << Name;
// This check would be insufficient for operator overloads like
// "operator>>" - but for now Clang doesn't try to simplify them, so this
// is OK. Add more nuanced operator overload handling here if/when needed.
- if (Name.endswith(">"))
+ if (Name.ends_with(">"))
break;
if (!appendTemplateParameters(D))
break;
@@ -620,6 +620,9 @@ void DWARFTypePrinter::appendSubroutineNameAfter(
case CallingConvention::DW_CC_LLVM_X86RegCall:
OS << " __attribute__((regcall))";
break;
+ case CallingConvention::DW_CC_LLVM_M68kRTD:
+ OS << " __attribute__((m68k_rtd))";
+ break;
}
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 19678f121982..9f455fa7e96a 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -81,8 +81,11 @@ void DWARFUnitVector::addUnitsImpl(
if (!Data.isValidOffset(Offset))
return nullptr;
DWARFUnitHeader Header;
- if (!Header.extract(Context, Data, &Offset, SectionKind))
+ if (Error ExtractErr =
+ Header.extract(Context, Data, &Offset, SectionKind)) {
+ Context.getWarningHandler()(std::move(ExtractErr));
return nullptr;
+ }
if (!IndexEntry && IsDWO) {
const DWARFUnitIndex &Index = getDWARFUnitIndex(
Context, Header.isTypeUnit() ? DW_SECT_EXT_TYPES : DW_SECT_INFO);
@@ -244,10 +247,10 @@ Expected<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
return DA.getRelocatedValue(ItemSize, &Offset);
}
-bool DWARFUnitHeader::extract(DWARFContext &Context,
- const DWARFDataExtractor &debug_info,
- uint64_t *offset_ptr,
- DWARFSectionKind SectionKind) {
+Error DWARFUnitHeader::extract(DWARFContext &Context,
+ const DWARFDataExtractor &debug_info,
+ uint64_t *offset_ptr,
+ DWARFSectionKind SectionKind) {
Offset = *offset_ptr;
Error Err = Error::success();
IndexEntry = nullptr;
@@ -277,72 +280,58 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
} else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
DWOId = debug_info.getU64(offset_ptr, &Err);
- if (Err) {
- Context.getWarningHandler()(joinErrors(
+ if (Err)
+ return joinErrors(
createStringError(
errc::invalid_argument,
"DWARF unit at 0x%8.8" PRIx64 " cannot be parsed:", Offset),
- std::move(Err)));
- return false;
- }
+ std::move(Err));
// 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 (!debug_info.isValidOffset(getNextUnitOffset() - 1))
+ return 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());
- if (!DWARFContext::isSupportedVersion(getVersion())) {
- Context.getWarningHandler()(createStringError(
+ if (!DWARFContext::isSupportedVersion(getVersion()))
+ return 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;
- }
+ Offset, getVersion(), DWARFContext::getMaxSupportedVersion());
// Type offset is unit-relative; should be after the header and before
// the end of the current unit.
- 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(
+ if (isTypeUnit() && TypeOffset < Size)
+ return 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);
+
+ if (isTypeUnit() && TypeOffset >= getUnitLengthFieldByteSize() + getLength())
+ return 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;
- }
+ Offset, NextCUOffset, Offset + TypeOffset);
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
getAddressByteSize(), errc::invalid_argument,
- "DWARF unit at offset 0x%8.8" PRIx64, Offset)) {
- Context.getWarningHandler()(std::move(SizeErr));
- return false;
- }
+ "DWARF unit at offset 0x%8.8" PRIx64, Offset))
+ return SizeErr;
// Keep track of the highest DWARF version we encounter across all units.
Context.setMaxVersionIfGreater(getVersion());
- return true;
+ return Error::success();
}
bool DWARFUnitHeader::applyIndexEntry(const DWARFUnitIndex::Entry *Entry) {
@@ -784,7 +773,7 @@ void DWARFUnit::updateVariableDieMap(DWARFDie Die) {
for (const DWARFLocationExpression &Location : *Locations) {
uint8_t AddressSize = getAddressByteSize();
- DataExtractor Data(Location.Expr, /*IsLittleEndian=*/true, AddressSize);
+ DataExtractor Data(Location.Expr, isLittleEndian(), AddressSize);
DWARFExpression Expr(Data, AddressSize);
auto It = Expr.begin();
if (It == Expr.end())
@@ -828,7 +817,7 @@ void DWARFUnit::updateVariableDieMap(DWARFDie Die) {
// no type), then we use a size of one to still allow symbolization of the
// exact address.
uint64_t GVSize = 1;
- if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type))
+ if (Die.getAttributeValueAsReferencedDie(DW_AT_type))
if (std::optional<uint64_t> Size = Die.getTypeSize(getAddressByteSize()))
GVSize = *Size;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 58900e1e80cb..43ed60d7f977 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -1351,12 +1351,34 @@ DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
return NumErrors;
}
-static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE,
- bool IncludeLinkageName = true) {
- SmallVector<StringRef, 2> Result;
- if (const char *Str = DIE.getShortName())
- Result.emplace_back(Str);
- else if (DIE.getTag() == dwarf::DW_TAG_namespace)
+static SmallVector<std::string, 3> getNames(const DWARFDie &DIE,
+ bool IncludeStrippedTemplateNames,
+ bool IncludeObjCNames = true,
+ bool IncludeLinkageName = true) {
+ SmallVector<std::string, 3> Result;
+ if (const char *Str = DIE.getShortName()) {
+ StringRef Name(Str);
+ Result.emplace_back(Name);
+ if (IncludeStrippedTemplateNames) {
+ if (std::optional<StringRef> StrippedName =
+ StripTemplateParameters(Result.back()))
+ // Convert to std::string and push; emplacing the StringRef may trigger
+ // a vector resize which may destroy the StringRef memory.
+ Result.push_back(StrippedName->str());
+ }
+
+ if (IncludeObjCNames) {
+ if (std::optional<ObjCSelectorNames> ObjCNames =
+ getObjCNamesIfSelector(Name)) {
+ Result.emplace_back(ObjCNames->ClassName);
+ Result.emplace_back(ObjCNames->Selector);
+ if (ObjCNames->ClassNameNoCategory)
+ Result.emplace_back(*ObjCNames->ClassNameNoCategory);
+ if (ObjCNames->MethodNameNoCategory)
+ Result.push_back(std::move(*ObjCNames->MethodNameNoCategory));
+ }
+ }
+ } else if (DIE.getTag() == dwarf::DW_TAG_namespace)
Result.emplace_back("(anonymous namespace)");
if (IncludeLinkageName) {
@@ -1423,7 +1445,12 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
++NumErrors;
}
- auto EntryNames = getNames(DIE);
+ // We allow an extra name for functions: their name without any template
+ // parameters.
+ auto IncludeStrippedTemplateNames =
+ DIE.getTag() == DW_TAG_subprogram ||
+ DIE.getTag() == DW_TAG_inlined_subroutine;
+ auto EntryNames = getNames(DIE, IncludeStrippedTemplateNames);
if (!is_contained(EntryNames, Str)) {
error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
"of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
@@ -1496,7 +1523,12 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
// the linkage name."
auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||
Die.getTag() == DW_TAG_inlined_subroutine;
- auto EntryNames = getNames(Die, IncludeLinkageName);
+ // We *allow* stripped template names / ObjectiveC names as extra entries into
+ // the table, but we don't *require* them to pass the completeness test.
+ auto IncludeStrippedTemplateNames = false;
+ auto IncludeObjCNames = false;
+ auto EntryNames = getNames(Die, IncludeStrippedTemplateNames,
+ IncludeObjCNames, IncludeLinkageName);
if (EntryNames.empty())
return 0;
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index d266960ae302..0b225376349e 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -65,10 +65,10 @@ struct llvm::gsym::CUInfo {
/// the first client that asks for a compile unit file index will end up
/// doing the conversion, and subsequent clients will get the cached GSYM
/// index.
- uint32_t DWARFToGSYMFileIndex(GsymCreator &Gsym, uint32_t DwarfFileIdx) {
- if (!LineTable)
- return 0;
- assert(DwarfFileIdx < FileCache.size());
+ std::optional<uint32_t> DWARFToGSYMFileIndex(GsymCreator &Gsym,
+ uint32_t DwarfFileIdx) {
+ if (!LineTable || DwarfFileIdx >= FileCache.size())
+ return std::nullopt;
uint32_t &GsymFileIdx = FileCache[DwarfFileIdx];
if (GsymFileIdx != UINT32_MAX)
return GsymFileIdx;
@@ -132,11 +132,11 @@ static DWARFDie GetParentDeclContextDIE(DWARFDie &Die) {
static std::optional<uint32_t>
getQualifiedNameIndex(DWARFDie &Die, uint64_t Language, GsymCreator &Gsym) {
// If the dwarf has mangled name, use mangled name
- if (auto LinkageName =
- dwarf::toString(Die.findRecursively({dwarf::DW_AT_MIPS_linkage_name,
- dwarf::DW_AT_linkage_name}),
- nullptr))
- return Gsym.insertString(LinkageName, /* Copy */ false);
+ if (auto LinkageName = Die.getLinkageName()) {
+ // We have seen cases were linkage name is actually empty.
+ if (strlen(LinkageName) > 0)
+ return Gsym.insertString(LinkageName, /* Copy */ false);
+ }
StringRef ShortName(Die.getName(DINameKind::ShortName));
if (ShortName.empty())
@@ -156,7 +156,7 @@ getQualifiedNameIndex(DWARFDie &Die, uint64_t Language, GsymCreator &Gsym) {
// Some GCC optimizations create functions with names ending with .isra.<num>
// or .part.<num> and those names are just DW_AT_name, not DW_AT_linkage_name
// If it looks like it could be the case, don't add any prefix
- if (ShortName.startswith("_Z") &&
+ if (ShortName.starts_with("_Z") &&
(ShortName.contains(".isra.") || ShortName.contains(".part.")))
return Gsym.insertString(ShortName, /* Copy */ false);
@@ -205,9 +205,21 @@ static bool hasInlineInfo(DWARFDie Die, uint32_t Depth) {
return false;
}
-static void parseInlineInfo(GsymCreator &Gsym, CUInfo &CUI, DWARFDie Die,
- uint32_t Depth, FunctionInfo &FI,
- InlineInfo &parent) {
+static AddressRanges
+ConvertDWARFRanges(const DWARFAddressRangesVector &DwarfRanges) {
+ AddressRanges Ranges;
+ for (const DWARFAddressRange &DwarfRange : DwarfRanges) {
+ if (DwarfRange.LowPC < DwarfRange.HighPC)
+ Ranges.insert({DwarfRange.LowPC, DwarfRange.HighPC});
+ }
+ return Ranges;
+}
+
+static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
+ DWARFDie Die, uint32_t Depth, FunctionInfo &FI,
+ InlineInfo &Parent,
+ const AddressRanges &AllParentRanges,
+ bool &WarnIfEmpty) {
if (!hasInlineInfo(Die, Depth))
return;
@@ -215,39 +227,80 @@ static void parseInlineInfo(GsymCreator &Gsym, CUInfo &CUI, DWARFDie Die,
if (Tag == dwarf::DW_TAG_inlined_subroutine) {
// create new InlineInfo and append to parent.children
InlineInfo II;
- DWARFAddressRange FuncRange =
- DWARFAddressRange(FI.startAddress(), FI.endAddress());
+ AddressRanges AllInlineRanges;
Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
if (RangesOrError) {
- for (const DWARFAddressRange &Range : RangesOrError.get()) {
- // Check that the inlined function is within the range of the function
- // info, it might not be in case of split functions
- if (FuncRange.LowPC <= Range.LowPC && Range.HighPC <= FuncRange.HighPC)
- II.Ranges.insert(AddressRange(Range.LowPC, Range.HighPC));
+ AllInlineRanges = ConvertDWARFRanges(RangesOrError.get());
+ uint32_t EmptyCount = 0;
+ for (const AddressRange &InlineRange : AllInlineRanges) {
+ // Check for empty inline range in case inline function was outlined
+ // or has not code
+ if (InlineRange.empty()) {
+ ++EmptyCount;
+ } else {
+ if (Parent.Ranges.contains(InlineRange)) {
+ II.Ranges.insert(InlineRange);
+ } else {
+ // Only warn if the current inline range is not within any of all
+ // of the parent ranges. If we have a DW_TAG_subpgram with multiple
+ // ranges we will emit a FunctionInfo for each range of that
+ // function that only emits information within the current range,
+ // so we only want to emit an error if the DWARF has issues, not
+ // when a range currently just isn't in the range we are currently
+ // parsing for.
+ if (AllParentRanges.contains(InlineRange)) {
+ WarnIfEmpty = false;
+ } else if (Log) {
+ *Log << "error: inlined function DIE at "
+ << HEX32(Die.getOffset()) << " has a range ["
+ << HEX64(InlineRange.start()) << " - "
+ << HEX64(InlineRange.end()) << ") that isn't contained in "
+ << "any parent address ranges, this inline range will be "
+ "removed.\n";
+ }
+ }
+ }
}
+ // If we have all empty ranges for the inlines, then don't warn if we
+ // have an empty InlineInfo at the top level as all inline functions
+ // were elided.
+ if (EmptyCount == AllInlineRanges.size())
+ WarnIfEmpty = false;
}
if (II.Ranges.empty())
return;
if (auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym))
II.Name = *NameIndex;
- II.CallFile = CUI.DWARFToGSYMFileIndex(
- Gsym, dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_file), 0));
- II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
- // parse all children and append to parent
- for (DWARFDie ChildDie : Die.children())
- parseInlineInfo(Gsym, CUI, ChildDie, Depth + 1, FI, II);
- parent.Children.emplace_back(std::move(II));
+ const uint64_t DwarfFileIdx = dwarf::toUnsigned(
+ Die.findRecursively(dwarf::DW_AT_call_file), UINT32_MAX);
+ std::optional<uint32_t> OptGSymFileIdx =
+ CUI.DWARFToGSYMFileIndex(Gsym, DwarfFileIdx);
+ if (OptGSymFileIdx) {
+ II.CallFile = OptGSymFileIdx.value();
+ II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
+ // parse all children and append to parent
+ for (DWARFDie ChildDie : Die.children())
+ parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II,
+ AllInlineRanges, WarnIfEmpty);
+ Parent.Children.emplace_back(std::move(II));
+ } else if (Log) {
+ *Log << "error: inlined function DIE at " << HEX32(Die.getOffset())
+ << " has an invalid file index " << DwarfFileIdx
+ << " in its DW_AT_call_file attribute, this inline entry and all "
+ << "children will be removed.\n";
+ }
return;
}
if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
// skip this Die and just recurse down
for (DWARFDie ChildDie : Die.children())
- parseInlineInfo(Gsym, CUI, ChildDie, Depth + 1, FI, parent);
+ parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, Parent,
+ AllParentRanges, WarnIfEmpty);
}
}
-static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
+static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
DWARFDie Die, GsymCreator &Gsym,
FunctionInfo &FI) {
std::vector<uint32_t> RowVector;
@@ -263,8 +316,20 @@ static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
// the DW_AT_decl_file an d DW_AT_decl_line if we have both attributes.
std::string FilePath = Die.getDeclFile(
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
- if (FilePath.empty())
+ if (FilePath.empty()) {
+ // If we had a DW_AT_decl_file, but got no file then we need to emit a
+ // warning.
+ if (Log) {
+ const uint64_t DwarfFileIdx = dwarf::toUnsigned(
+ Die.findRecursively(dwarf::DW_AT_decl_file), UINT32_MAX);
+ *Log << "error: function DIE at " << HEX32(Die.getOffset())
+ << " has an invalid file index " << DwarfFileIdx
+ << " in its DW_AT_decl_file attribute, unable to create a single "
+ << "line entry from the DW_AT_decl_file/DW_AT_decl_line "
+ << "attributes.\n";
+ }
return;
+ }
if (auto Line =
dwarf::toUnsigned(Die.findRecursively({dwarf::DW_AT_decl_line}))) {
LineEntry LE(StartAddress, Gsym.insertFile(FilePath), *Line);
@@ -279,7 +344,20 @@ static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
for (uint32_t RowIndex : RowVector) {
// Take file number and line/column from the row.
const DWARFDebugLine::Row &Row = CUI.LineTable->Rows[RowIndex];
- const uint32_t FileIdx = CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
+ std::optional<uint32_t> OptFileIdx =
+ CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
+ if (!OptFileIdx) {
+ if (Log) {
+ *Log << "error: function DIE at " << HEX32(Die.getOffset()) << " has "
+ << "a line entry with invalid DWARF file index, this entry will "
+ << "be removed:\n";
+ Row.dumpTableHeader(*Log, /*Indent=*/0);
+ Row.dump(*Log);
+ *Log << "\n";
+ }
+ continue;
+ }
+ const uint32_t FileIdx = OptFileIdx.value();
uint64_t RowAddress = Row.Address.Address;
// Watch out for a RowAddress that is in the middle of a line table entry
// in the DWARF. If we pass an address in between two line table entries
@@ -289,10 +367,12 @@ static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
// an error, but not worth stopping the creation of the GSYM.
if (!FI.Range.contains(RowAddress)) {
if (RowAddress < FI.Range.start()) {
- Log << "error: DIE has a start address whose LowPC is between the "
- "line table Row[" << RowIndex << "] with address "
- << HEX64(RowAddress) << " and the next one.\n";
- Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ if (Log) {
+ *Log << "error: DIE has a start address whose LowPC is between the "
+ "line table Row[" << RowIndex << "] with address "
+ << HEX64(RowAddress) << " and the next one.\n";
+ Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE());
+ }
RowAddress = FI.Range.start();
} else {
continue;
@@ -302,25 +382,25 @@ static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
LineEntry LE(RowAddress, FileIdx, Row.Line);
if (RowIndex != RowVector[0] && Row.Address < PrevRow.Address) {
// We have seen full duplicate line tables for functions in some
- // DWARF files. Watch for those here by checking the the last
+ // DWARF files. Watch for those here by checking the last
// row was the function's end address (HighPC) and that the
// current line table entry's address is the same as the first
// line entry we already have in our "function_info.Lines". If
// so break out after printing a warning.
auto FirstLE = FI.OptLineTable->first();
if (FirstLE && *FirstLE == LE) {
- if (!Gsym.isQuiet()) {
- Log << "warning: duplicate line table detected for DIE:\n";
- Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ if (Log && !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 "
- << "monotonically increase:\n";
- for (uint32_t RowIndex2 : RowVector) {
- CUI.LineTable->Rows[RowIndex2].dump(Log);
+ if (Log) {
+ *Log << "error: line table has addresses that do not "
+ << "monotonically increase:\n";
+ for (uint32_t RowIndex2 : RowVector)
+ CUI.LineTable->Rows[RowIndex2].dump(*Log);
+ Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE());
}
- Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
}
break;
}
@@ -349,7 +429,7 @@ static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
FI.OptLineTable = std::nullopt;
}
-void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
+void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
switch (Die.getTag()) {
case dwarf::DW_TAG_subprogram: {
Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
@@ -362,11 +442,20 @@ void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
break;
auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym);
if (!NameIndex) {
- OS << "error: function at " << HEX64(Die.getOffset())
- << " has no name\n ";
- Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
+ if (OS) {
+ *OS << "error: function at " << HEX64(Die.getOffset())
+ << " has no name\n ";
+ Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE());
+ }
break;
}
+ // All ranges for the subprogram DIE in case it has multiple. We need to
+ // pass this down into parseInlineInfo so we don't warn about inline
+ // ranges that are not in the current subrange of a function when they
+ // actually are in another subgrange. We do this because when a function
+ // has discontiguos ranges, we create multiple function entries with only
+ // the info for that range contained inside of it.
+ AddressRanges AllSubprogramRanges = ConvertDWARFRanges(Ranges);
// Create a function_info for each range
for (const DWARFAddressRange &Range : Ranges) {
@@ -393,11 +482,13 @@ void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
if (Range.LowPC != 0) {
if (!Gsym.isQuiet()) {
// Unexpected invalid address, emit a warning
- OS << "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(OS, 0, DIDumpOptions::getForSingleDIE());
+ if (OS) {
+ *OS << "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(*OS, 0, DIDumpOptions::getForSingleDIE());
+ }
}
}
break;
@@ -406,14 +497,33 @@ void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
FunctionInfo FI;
FI.Range = {Range.LowPC, Range.HighPC};
FI.Name = *NameIndex;
- if (CUI.LineTable) {
+ if (CUI.LineTable)
convertFunctionLineTable(OS, CUI, Die, Gsym, FI);
- }
+
if (hasInlineInfo(Die, 0)) {
FI.Inline = InlineInfo();
FI.Inline->Name = *NameIndex;
FI.Inline->Ranges.insert(FI.Range);
- parseInlineInfo(Gsym, CUI, Die, 0, FI, *FI.Inline);
+ bool WarnIfEmpty = true;
+ parseInlineInfo(Gsym, OS, CUI, Die, 0, FI, *FI.Inline,
+ AllSubprogramRanges, WarnIfEmpty);
+ // Make sure we at least got some valid inline info other than just
+ // the top level function. If we didn't then remove the inline info
+ // from the function info. We have seen cases where LTO tries to modify
+ // the DWARF for functions and it messes up the address ranges for
+ // the inline functions so it is no longer valid.
+ //
+ // By checking if there are any valid children on the top level inline
+ // information object, we will know if we got anything valid from the
+ // debug info.
+ if (FI.Inline->Children.empty()) {
+ if (WarnIfEmpty && OS && !Gsym.isQuiet()) {
+ *OS << "warning: DIE contains inline function information that has "
+ "no valid ranges, removing inline information:\n";
+ Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE());
+ }
+ FI.Inline = std::nullopt;
+ }
}
Gsym.addFunctionInfo(std::move(FI));
}
@@ -425,18 +535,18 @@ void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
handleDie(OS, CUI, ChildDie);
}
-Error DwarfTransformer::convert(uint32_t NumThreads) {
+Error DwarfTransformer::convert(uint32_t NumThreads, raw_ostream *OS) {
size_t NumBefore = Gsym.getNumFunctionInfos();
auto getDie = [&](DWARFUnit &DwarfUnit) -> DWARFDie {
DWARFDie ReturnDie = DwarfUnit.getUnitDIE(false);
- if (std::optional<uint64_t> DWOId = DwarfUnit.getDWOId()) {
+ if (DwarfUnit.getDWOId()) {
DWARFUnit *DWOCU = DwarfUnit.getNonSkeletonUnitDIE(false).getDwarfUnit();
- if (!DWOCU->isDWOUnit()) {
+ if (OS && !DWOCU->isDWOUnit()) {
std::string DWOName = dwarf::toString(
DwarfUnit.getUnitDIE().find(
{dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
"");
- Log << "warning: Unable to retrieve DWO .debug_info section for "
+ *OS << "warning: Unable to retrieve DWO .debug_info section for "
<< DWOName << "\n";
} else {
ReturnDie = DWOCU->getUnitDIE(false);
@@ -450,7 +560,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads) {
for (const auto &CU : DICtx.compile_units()) {
DWARFDie Die = getDie(*CU);
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
- handleDie(Log, CUI, Die);
+ handleDie(OS, CUI, Die);
}
} else {
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
@@ -476,15 +586,15 @@ Error DwarfTransformer::convert(uint32_t NumThreads) {
DWARFDie Die = getDie(*CU);
if (Die) {
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
- pool.async([this, CUI, &LogMutex, Die]() mutable {
+ pool.async([this, CUI, &LogMutex, OS, Die]() mutable {
std::string ThreadLogStorage;
raw_string_ostream ThreadOS(ThreadLogStorage);
- handleDie(ThreadOS, CUI, Die);
+ handleDie(OS ? &ThreadOS: nullptr, CUI, Die);
ThreadOS.flush();
- if (!ThreadLogStorage.empty()) {
+ if (OS && !ThreadLogStorage.empty()) {
// Print ThreadLogStorage lines into an actual stream under a lock
std::lock_guard<std::mutex> guard(LogMutex);
- Log << ThreadLogStorage;
+ *OS << ThreadLogStorage;
}
});
}
@@ -492,11 +602,12 @@ Error DwarfTransformer::convert(uint32_t NumThreads) {
pool.wait();
}
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
- Log << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
+ if (OS)
+ *OS << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
return Error::success();
}
-llvm::Error DwarfTransformer::verify(StringRef GsymPath) {
+llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) {
Log << "Verifying GSYM file \"" << GsymPath << "\":\n";
auto Gsym = GsymReader::openFile(GsymPath);
diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
index 145a43d3b381..07303d551af5 100644
--- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -101,7 +101,7 @@ uint64_t FunctionInfo::cacheEncoding() {
if (!isValid())
return 0;
raw_svector_ostream OutStrm(EncodingCache);
- FileWriter FW(OutStrm, support::endian::system_endianness());
+ FileWriter FW(OutStrm, llvm::endianness::native);
llvm::Expected<uint64_t> Result = encode(FW);
if (!Result) {
EncodingCache.clear();
@@ -123,7 +123,7 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &Out) const {
// precompute exactly how big FunctionInfo objects encode into so we can
// accurately make segments of a specific size.
if (!EncodingCache.empty() &&
- support::endian::system_endianness() == Out.getByteOrder()) {
+ llvm::endianness::native == Out.getByteOrder()) {
// We already encoded this object, just write out the bytes.
Out.writeData(llvm::ArrayRef<uint8_t>((const uint8_t *)EncodingCache.data(),
EncodingCache.size()));
diff --git a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 60b6dbc6a12d..ee7b0efba5ea 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -61,9 +61,7 @@ uint32_t GsymCreator::copyFile(const GsymCreator &SrcGC, uint32_t FileIdx) {
return insertFileEntry(DstFE);
}
-
-llvm::Error GsymCreator::save(StringRef Path,
- llvm::support::endianness ByteOrder,
+llvm::Error GsymCreator::save(StringRef Path, llvm::endianness ByteOrder,
std::optional<uint64_t> SegmentSize) const {
if (SegmentSize)
return saveSegments(Path, ByteOrder, *SegmentSize);
@@ -187,35 +185,12 @@ llvm::Error GsymCreator::encode(FileWriter &O) const {
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::mutex> Guard(Mutex);
if (Finalized)
return createStringError(std::errc::invalid_argument, "already finalized");
Finalized = true;
- // Sort function infos so we can emit sorted functions.
- llvm::sort(Funcs);
-
// Don't let the string table indexes change by finalizing in order.
StrTab.finalizeInOrder();
@@ -239,83 +214,85 @@ llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
// Note that in case of (b), we cannot include Y in the result because then
// we wouldn't find any function for range (end of Y, end of X)
// with binary search
- auto NumBefore = Funcs.size();
- 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
- // a high address might match our last entry. By fixing up this size, we can
- // 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())) {
- Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
+ const auto NumBefore = Funcs.size();
+ // Only sort and unique if this isn't a segment. If this is a segment we
+ // already finalized the main GsymCreator with all of the function infos
+ // and then the already sorted and uniqued function infos were added to this
+ // object.
+ if (!IsSegment) {
+ if (NumBefore > 1) {
+ // Sort function infos so we can emit sorted functions.
+ llvm::sort(Funcs);
+ std::vector<FunctionInfo> FinalizedFuncs;
+ FinalizedFuncs.reserve(Funcs.size());
+ FinalizedFuncs.emplace_back(std::move(Funcs.front()));
+ for (size_t Idx=1; Idx < NumBefore; ++Idx) {
+ FunctionInfo &Prev = FinalizedFuncs.back();
+ FunctionInfo &Curr = Funcs[Idx];
+ // 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)) {
+ if (Prev.hasRichInfo() && Curr.hasRichInfo()) {
+ if (!Quiet) {
+ OS << "warning: same address range contains "
+ "different debug "
+ << "info. Removing:\n"
+ << Prev << "\nIn favor of this one:\n"
+ << Curr << "\n";
+ }
+ }
+ // We want to swap the current entry with the previous since
+ // later entries with the same range always have more debug info
+ // or different debug info.
+ std::swap(Prev, Curr);
+ }
+ } else {
+ if (!Quiet) { // print warnings about overlaps
+ OS << "warning: function ranges overlap:\n"
+ << Prev << "\n"
+ << Curr << "\n";
+ }
+ FinalizedFuncs.emplace_back(std::move(Curr));
+ }
+ } else {
+ if (Prev.Range.size() == 0 && Curr.Range.contains(Prev.Range.start())) {
+ // Symbols on macOS don't have address ranges, so if the range
+ // doesn't match and the size is zero, then we replace the empty
+ // symbol function info with the current one.
+ std::swap(Prev, Curr);
+ } else {
+ FinalizedFuncs.emplace_back(std::move(Curr));
+ }
+ }
+ }
+ std::swap(Funcs, FinalizedFuncs);
+ }
+ // 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
+ // a high address might match our last entry. By fixing up this size, we can
+ // 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())) {
+ Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
+ }
}
+ OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
+ << Funcs.size() << " total\n";
}
- OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
- << Funcs.size() << " total\n";
return Error::success();
}
@@ -355,7 +332,6 @@ uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
std::lock_guard<std::mutex> Guard(Mutex);
- Ranges.insert(FI.Range);
Funcs.emplace_back(std::move(FI));
}
@@ -388,31 +364,24 @@ bool GsymCreator::IsValidTextAddress(uint64_t Addr) const {
return true; // No valid text ranges has been set, so accept all ranges.
}
-bool GsymCreator::hasFunctionInfoForAddress(uint64_t Addr) const {
- std::lock_guard<std::mutex> Guard(Mutex);
- return Ranges.contains(Addr);
-}
-
std::optional<uint64_t> GsymCreator::getFirstFunctionAddress() const {
- if (Finalized && !Funcs.empty())
+ // If we have finalized then Funcs are sorted. If we are a segment then
+ // Funcs will be sorted as well since function infos get added from an
+ // already finalized GsymCreator object where its functions were sorted and
+ // uniqued.
+ if ((Finalized || IsSegment) && !Funcs.empty())
return std::optional<uint64_t>(Funcs.front().startAddress());
- // This code gets used by the segmentation of GSYM files to help determine the
- // size of the GSYM header while continually adding new FunctionInfo objects
- // to this object, so we haven't finalized this object yet.
- if (Ranges.empty())
- return std::nullopt;
- return std::optional<uint64_t>(Ranges.begin()->start());
+ return std::nullopt;
}
std::optional<uint64_t> GsymCreator::getLastFunctionAddress() const {
- if (Finalized && !Funcs.empty())
+ // If we have finalized then Funcs are sorted. If we are a segment then
+ // Funcs will be sorted as well since function infos get added from an
+ // already finalized GsymCreator object where its functions were sorted and
+ // uniqued.
+ if ((Finalized || IsSegment) && !Funcs.empty())
return std::optional<uint64_t>(Funcs.back().startAddress());
- // This code gets used by the segmentation of GSYM files to help determine the
- // size of the GSYM header while continually adding new FunctionInfo objects
- // to this object, so we haven't finalized this object yet.
- if (Ranges.empty())
- return std::nullopt;
- return std::optional<uint64_t>((Ranges.end() - 1)->end());
+ return std::nullopt;
}
std::optional<uint64_t> GsymCreator::getBaseAddress() const {
@@ -477,7 +446,6 @@ uint64_t GsymCreator::copyFunctionInfo(const GsymCreator &SrcGC, size_t FuncIdx)
// this GsymCreator and then copy the function info and update the string
// table offsets to match the new offsets.
const FunctionInfo &SrcFI = SrcGC.Funcs[FuncIdx];
- Ranges.insert(SrcFI.Range);
FunctionInfo DstFI;
DstFI.Range = SrcFI.Range;
@@ -503,12 +471,12 @@ uint64_t GsymCreator::copyFunctionInfo(const GsymCreator &SrcGC, size_t FuncIdx)
fixupInlineInfo(SrcGC, *DstFI.Inline);
}
std::lock_guard<std::mutex> Guard(Mutex);
- Funcs.push_back(DstFI);
+ Funcs.emplace_back(DstFI);
return Funcs.back().cacheEncoding();
}
llvm::Error GsymCreator::saveSegments(StringRef Path,
- llvm::support::endianness ByteOrder,
+ llvm::endianness ByteOrder,
uint64_t SegmentSize) const {
if (SegmentSize == 0)
return createStringError(std::errc::invalid_argument,
@@ -551,6 +519,10 @@ GsymCreator::createSegment(uint64_t SegmentSize, size_t &FuncIdx) const {
return std::unique_ptr<GsymCreator>();
std::unique_ptr<GsymCreator> GC(new GsymCreator(/*Quiet=*/true));
+
+ // Tell the creator that this is a segment.
+ GC->setIsSegment();
+
// Set the base address if there is one.
if (BaseAddress)
GC->setBaseAddress(*BaseAddress);
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 6afaeea8f598..4b1b35246617 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -23,11 +23,10 @@
using namespace llvm;
using namespace gsym;
-GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
- MemBuffer(std::move(Buffer)),
- Endian(support::endian::system_endianness()) {}
+GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer)
+ : MemBuffer(std::move(Buffer)), Endian(llvm::endianness::native) {}
- GsymReader::GsymReader(GsymReader &&RHS) = default;
+GsymReader::GsymReader(GsymReader &&RHS) = default;
GsymReader::~GsymReader() = default;
@@ -60,8 +59,7 @@ GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
llvm::Error
GsymReader::parse() {
- BinaryStreamReader FileData(MemBuffer->getBuffer(),
- support::endian::system_endianness());
+ BinaryStreamReader FileData(MemBuffer->getBuffer(), llvm::endianness::native);
// Check for the magic bytes. This file format is designed to be mmap'ed
// into a process and accessed as read only. This is done for performance
// and efficiency for symbolicating and parsing GSYM data.
@@ -69,14 +67,15 @@ GsymReader::parse() {
return createStringError(std::errc::invalid_argument,
"not enough data for a GSYM header");
- const auto HostByteOrder = support::endian::system_endianness();
+ const auto HostByteOrder = llvm::endianness::native;
switch (Hdr->Magic) {
case GSYM_MAGIC:
Endian = HostByteOrder;
break;
case GSYM_CIGAM:
// This is a GSYM file, but not native endianness.
- Endian = sys::IsBigEndianHost ? support::little : support::big;
+ Endian = sys::IsBigEndianHost ? llvm::endianness::little
+ : llvm::endianness::big;
Swap.reset(new SwappedData);
break;
default:
@@ -84,7 +83,7 @@ GsymReader::parse() {
"not a GSYM file");
}
- bool DataIsLittleEndian = HostByteOrder != support::little;
+ bool DataIsLittleEndian = HostByteOrder != llvm::endianness::little;
// Read a correctly byte swapped header if we need to.
if (Swap) {
DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
@@ -254,41 +253,94 @@ GsymReader::getAddressIndex(const uint64_t Addr) const {
}
-llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
- Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
- if (!AddressIndex)
- return AddressIndex.takeError();
- // Address info offsets size should have been checked in parse().
- assert(*AddressIndex < AddrInfoOffsets.size());
- auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
- DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
- if (std::optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
- auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
- if (ExpectedFI) {
- if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
- return ExpectedFI;
- return createStringError(std::errc::invalid_argument,
- "address 0x%" PRIx64 " is not in GSYM", Addr);
+llvm::Expected<DataExtractor>
+GsymReader::getFunctionInfoDataForAddress(uint64_t Addr,
+ uint64_t &FuncStartAddr) const {
+ Expected<uint64_t> ExpectedAddrIdx = getAddressIndex(Addr);
+ if (!ExpectedAddrIdx)
+ return ExpectedAddrIdx.takeError();
+ const uint64_t FirstAddrIdx = *ExpectedAddrIdx;
+ // The AddrIdx is the first index of the function info entries that match
+ // \a Addr. We need to iterate over all function info objects that start with
+ // the same address until we find a range that contains \a Addr.
+ std::optional<uint64_t> FirstFuncStartAddr;
+ const size_t NumAddresses = getNumAddresses();
+ for (uint64_t AddrIdx = FirstAddrIdx; AddrIdx < NumAddresses; ++AddrIdx) {
+ auto ExpextedData = getFunctionInfoDataAtIndex(AddrIdx, FuncStartAddr);
+ // If there was an error, return the error.
+ if (!ExpextedData)
+ return ExpextedData;
+
+ // Remember the first function start address if it hasn't already been set.
+ // If it is already valid, check to see if it matches the first function
+ // start address and only continue if it matches.
+ if (FirstFuncStartAddr.has_value()) {
+ if (*FirstFuncStartAddr != FuncStartAddr)
+ break; // Done with consecutive function entries with same address.
+ } else {
+ FirstFuncStartAddr = FuncStartAddr;
}
+ // Make sure the current function address ranges contains \a Addr.
+ // Some symbols on Darwin don't have valid sizes, so if we run into a
+ // symbol with zero size, then we have found a match for our address.
+
+ // The first thing the encoding of a FunctionInfo object is the function
+ // size.
+ uint64_t Offset = 0;
+ uint32_t FuncSize = ExpextedData->getU32(&Offset);
+ if (FuncSize == 0 ||
+ AddressRange(FuncStartAddr, FuncStartAddr + FuncSize).contains(Addr))
+ return ExpextedData;
}
return createStringError(std::errc::invalid_argument,
- "failed to extract address[%" PRIu64 "]",
- *AddressIndex);
+ "address 0x%" PRIx64 " is not in GSYM", Addr);
+}
+
+llvm::Expected<DataExtractor>
+GsymReader::getFunctionInfoDataAtIndex(uint64_t AddrIdx,
+ uint64_t &FuncStartAddr) const {
+ if (AddrIdx >= getNumAddresses())
+ return createStringError(std::errc::invalid_argument,
+ "invalid address index %" PRIu64, AddrIdx);
+ const uint32_t AddrInfoOffset = AddrInfoOffsets[AddrIdx];
+ assert((Endian == endianness::big || Endian == endianness::little) &&
+ "Endian must be either big or little");
+ StringRef Bytes = MemBuffer->getBuffer().substr(AddrInfoOffset);
+ if (Bytes.empty())
+ return createStringError(std::errc::invalid_argument,
+ "invalid address info offset 0x%" PRIx32,
+ AddrInfoOffset);
+ std::optional<uint64_t> OptFuncStartAddr = getAddress(AddrIdx);
+ if (!OptFuncStartAddr)
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract address[%" PRIu64 "]", AddrIdx);
+ FuncStartAddr = *OptFuncStartAddr;
+ return DataExtractor(Bytes, Endian == llvm::endianness::little, 4);
+}
+
+llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
+ uint64_t FuncStartAddr = 0;
+ if (auto ExpectedData = getFunctionInfoDataForAddress(Addr, FuncStartAddr))
+ return FunctionInfo::decode(*ExpectedData, FuncStartAddr);
+ else
+ return ExpectedData.takeError();
+}
+
+llvm::Expected<FunctionInfo>
+GsymReader::getFunctionInfoAtIndex(uint64_t Idx) const {
+ uint64_t FuncStartAddr = 0;
+ if (auto ExpectedData = getFunctionInfoDataAtIndex(Idx, FuncStartAddr))
+ return FunctionInfo::decode(*ExpectedData, FuncStartAddr);
+ else
+ return ExpectedData.takeError();
}
llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
- Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
- if (!AddressIndex)
- return AddressIndex.takeError();
- // Address info offsets size should have been checked in parse().
- assert(*AddressIndex < AddrInfoOffsets.size());
- auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
- DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
- if (std::optional<uint64_t> OptAddr = getAddress(*AddressIndex))
- return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
- return createStringError(std::errc::invalid_argument,
- "failed to extract address[%" PRIu64 "]",
- *AddressIndex);
+ uint64_t FuncStartAddr = 0;
+ if (auto ExpectedData = getFunctionInfoDataForAddress(Addr, FuncStartAddr))
+ return FunctionInfo::lookup(*ExpectedData, *this, FuncStartAddr, Addr);
+ else
+ return ExpectedData.takeError();
}
void GsymReader::dump(raw_ostream &OS) {
@@ -339,7 +391,7 @@ void GsymReader::dump(raw_ostream &OS) {
for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
- if (auto FI = getFunctionInfo(*getAddress(I)))
+ if (auto FI = getFunctionInfoAtIndex(I))
dump(OS, *FI);
else
logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
diff --git a/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp b/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
index f775ab8fb65c..ecfb21501eda 100644
--- a/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/InlineInfo.cpp
@@ -264,3 +264,14 @@ llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const {
}
return Error::success();
}
+
+static uint64_t GetTotalNumChildren(const InlineInfo &II) {
+ uint64_t NumChildren = II.Children.size();
+ for (const auto &Child : II.Children)
+ NumChildren += GetTotalNumChildren(Child);
+ return NumChildren;
+}
+
+bool InlineInfo::operator<(const InlineInfo &RHS) const {
+ return GetTotalNumChildren(*this) < GetTotalNumChildren(RHS);
+}
diff --git a/llvm/lib/DebugInfo/GSYM/LineTable.cpp b/llvm/lib/DebugInfo/GSYM/LineTable.cpp
index a49a3ba9bf2a..666d9f15f1b4 100644
--- a/llvm/lib/DebugInfo/GSYM/LineTable.cpp
+++ b/llvm/lib/DebugInfo/GSYM/LineTable.cpp
@@ -270,11 +270,6 @@ Expected<LineEntry> LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, ui
if (Addr < Row.Addr)
return false; // Stop parsing, result contains the line table row!
Result = Row;
- if (Addr == Row.Addr) {
- // Stop parsing, this is the row we are looking for since the address
- // matches.
- return false;
- }
return true; // Keep parsing till we find the right row.
});
if (Err)
diff --git a/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp b/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
index ad35aefe7774..a60b2d386076 100644
--- a/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
@@ -68,7 +68,7 @@ static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
}
llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
- raw_ostream &Log,
+ raw_ostream *Log,
GsymCreator &Gsym) {
using namespace llvm::object;
@@ -92,15 +92,18 @@ llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
return AddrOrErr.takeError();
if (SymType.get() != SymbolRef::Type::ST_Function ||
- !Gsym.IsValidTextAddress(*AddrOrErr) ||
- Gsym.hasFunctionInfoForAddress(*AddrOrErr))
+ !Gsym.IsValidTextAddress(*AddrOrErr))
continue;
// Function size for MachO files will be 0
constexpr bool NoCopy = false;
const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
Expected<StringRef> Name = Sym.getName();
if (!Name) {
- logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: ");
+ if (Log)
+ logAllUnhandledErrors(Name.takeError(), *Log,
+ "ObjectFileTransformer: ");
+ else
+ consumeError(Name.takeError());
continue;
}
// Remove the leading '_' character in any symbol names if there is one
@@ -111,6 +114,8 @@ llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
}
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
- Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n";
+ if (Log)
+ *Log << "Loaded " << FunctionsAddedCount
+ << " functions from symbol table.\n";
return Error::success();
}
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
index 65baf52ffb44..3ed0de14f93f 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVCompare.cpp
@@ -206,11 +206,10 @@ Error LVCompare::execute(LVReader *ReferenceReader, LVReader *TargetReader) {
updateExpected(Reference);
Reference->setIsInCompare();
LVElement *CurrentTarget = nullptr;
- if (std::any_of(Targets.begin(), Targets.end(),
- [&](auto Target) -> bool {
- CurrentTarget = Target;
- return Reference->equals(Target);
- })) {
+ if (llvm::any_of(Targets, [&](auto Target) -> bool {
+ CurrentTarget = Target;
+ return Reference->equals(Target);
+ })) {
if (Pass == LVComparePass::Missing && Reference->getIsScope()) {
// If the elements being compared are scopes and are a match,
// they are recorded, to be used when creating the augmented
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index cfe304eead51..30ce937cda44 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -252,8 +252,7 @@ void LVElement::generateName(std::string &Prefix) const {
Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");
// Remove any whitespaces.
- Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace),
- Prefix.end());
+ llvm::erase_if(Prefix, ::isspace);
}
// Generate a name for unnamed elements.
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 2f26025d01ec..8bbaf93db0ca 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -299,20 +299,12 @@ void LVScope::addMissingElements(LVScope *Reference) {
LVSymbols References;
References.append(ReferenceSymbols->begin(), ReferenceSymbols->end());
- auto RemoveSymbol = [&](LVSymbols &Symbols, LVSymbol *Symbol) {
- LVSymbols::iterator Iter = std::remove_if(
- Symbols.begin(), Symbols.end(),
- [Symbol](LVSymbol *Item) -> bool { return Item == Symbol; });
- if (Iter != Symbols.end())
- Symbols.erase(Iter, Symbols.end());
- };
-
// Erase abstract symbols already in this scope from the collection of
// symbols in the referenced scope.
if (getSymbols())
for (const LVSymbol *Symbol : *getSymbols())
if (Symbol->getHasReferenceAbstract())
- RemoveSymbol(References, Symbol->getReference());
+ llvm::erase(References, Symbol->getReference());
// If we have elements left in 'References', those are the elements that
// need to be inserted in the current scope.
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
index d72fe2683f92..1f6724988ae9 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp
@@ -221,7 +221,7 @@ bool LVCodeViewReader::isSystemEntry(LVElement *Element, StringRef Name) const {
return StringRef::npos != Name.find(String);
};
auto Starts = [=](const char *Pattern) -> bool {
- return Name.startswith(Pattern);
+ return Name.starts_with(Pattern);
};
auto CheckExclude = [&]() -> bool {
if (Starts("__") || Starts("_PMD") || Starts("_PMFN"))
@@ -276,7 +276,7 @@ Error LVCodeViewReader::collectInlineeInfo(
}
Error LVCodeViewReader::traverseInlineeLines(StringRef Subsection) {
- BinaryStreamReader SR(Subsection, llvm::support::little);
+ BinaryStreamReader SR(Subsection, llvm::endianness::little);
DebugInlineeLinesSubsectionRef Lines;
if (Error E = Lines.initialize(SR))
return createStringError(errorToErrorCode(std::move(E)), getFileName());
@@ -349,7 +349,7 @@ Error LVCodeViewReader::initializeFileAndStringTables(
if (Error E = Reader.readFixedString(Contents, SubSectionSize))
return createStringError(errorToErrorCode(std::move(E)), getFileName());
- BinaryStreamRef ST(Contents, support::little);
+ BinaryStreamRef ST(Contents, llvm::endianness::little);
switch (DebugSubsectionKind(SubType)) {
case DebugSubsectionKind::FileChecksums:
if (Error E = CVFileChecksumTable.initialize(ST))
@@ -478,8 +478,8 @@ Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp,
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return errorCodeToError(object_error::parse_failed);
- ReaderPrecomp =
- std::make_unique<BinaryStreamReader>(*DataOrErr, support::little);
+ ReaderPrecomp = std::make_unique<BinaryStreamReader>(
+ *DataOrErr, llvm::endianness::little);
cantFail(
ReaderPrecomp->readArray(CVTypesPrecomp, ReaderPrecomp->getLength()));
@@ -514,7 +514,7 @@ Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp,
[&](TypeIndex TI, const CVType &Type) { TypeArray.push_back(Type); });
ItemStream =
- std::make_unique<BinaryItemStream<CVType>>(llvm::support::little);
+ std::make_unique<BinaryItemStream<CVType>>(llvm::endianness::little);
ItemStream->setItems(TypeArray);
TypeStream.setUnderlyingStream(*ItemStream);
@@ -550,7 +550,7 @@ Error LVCodeViewReader::traverseTypeSection(StringRef SectionName,
// Get the first type record. It will indicate if this object uses a type
// server (/Zi) or a PCH file (/Yu).
CVTypeArray CVTypes;
- BinaryStreamReader Reader(*DataOrErr, support::little);
+ BinaryStreamReader Reader(*DataOrErr, llvm::endianness::little);
cantFail(Reader.readArray(CVTypes, Reader.getLength()));
CVTypeArray::Iterator FirstType = CVTypes.begin();
@@ -621,7 +621,7 @@ Error LVCodeViewReader::traverseSymbolsSubsection(StringRef Subsection,
LVSymbolVisitorDelegate VisitorDelegate(this, Section, &getObj(),
SectionContents);
CVSymbolArray Symbols;
- BinaryStreamReader Reader(BinaryData, llvm::support::little);
+ BinaryStreamReader Reader(BinaryData, llvm::endianness::little);
if (Error E = Reader.readArray(Symbols, Reader.getLength()))
return createStringError(errorToErrorCode(std::move(E)), getFileName());
@@ -664,7 +664,7 @@ Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName,
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return createStringError(object_error::parse_failed, getFileName());
- BinaryStreamReader FSReader(Data, support::little);
+ BinaryStreamReader FSReader(Data, llvm::endianness::little);
if (Error Err = initializeFileAndStringTables(FSReader))
return Err;
@@ -752,7 +752,8 @@ Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName,
W.printString("Symbol Name", SymbolName);
});
- BinaryStreamReader Reader(FunctionLineTables[SymbolName], support::little);
+ BinaryStreamReader Reader(FunctionLineTables[SymbolName],
+ llvm::endianness::little);
DebugLinesSubsectionRef Lines;
if (Error E = Lines.initialize(Reader))
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
index e4f5f533262b..1d0178532882 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -465,13 +465,10 @@ LVScope *LVNamespaceDeduction::get(LVStringRefs Components) {
LVScope *LVNamespaceDeduction::get(StringRef ScopedName, bool CheckScope) {
LVStringRefs Components = getAllLexicalComponents(ScopedName);
if (CheckScope)
- Components.erase(std::remove_if(Components.begin(), Components.end(),
- [&](StringRef Component) {
- LookupSet::iterator Iter =
- IdentifiedNamespaces.find(Component);
- return Iter == IdentifiedNamespaces.end();
- }),
- Components.end());
+ llvm::erase_if(Components, [&](StringRef Component) {
+ LookupSet::iterator Iter = IdentifiedNamespaces.find(Component);
+ return Iter == IdentifiedNamespaces.end();
+ });
LLVM_DEBUG(
{ dbgs() << formatv("ScopedName: '{0}'\n", ScopedName.str().c_str()); });
@@ -1688,6 +1685,48 @@ Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
return Error::success();
}
+// S_ARMSWITCHTABLE
+Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR,
+ JumpTableSym &JumpTable) {
+ LLVM_DEBUG({
+ W.printHex("BaseOffset", JumpTable.BaseOffset);
+ W.printNumber("BaseSegment", JumpTable.BaseSegment);
+ W.printFlags("SwitchType", static_cast<uint16_t>(JumpTable.SwitchType),
+ getJumpTableEntrySizeNames());
+ W.printHex("BranchOffset", JumpTable.BranchOffset);
+ W.printHex("TableOffset", JumpTable.TableOffset);
+ W.printNumber("BranchSegment", JumpTable.BranchSegment);
+ W.printNumber("TableSegment", JumpTable.TableSegment);
+ W.printNumber("EntriesCount", JumpTable.EntriesCount);
+ });
+ return Error::success();
+}
+
+// S_CALLERS, S_CALLEES, S_INLINEES
+Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, CallerSym &Caller) {
+ LLVM_DEBUG({
+ llvm::StringRef FieldName;
+ switch (Caller.getKind()) {
+ case SymbolRecordKind::CallerSym:
+ FieldName = "Callee";
+ break;
+ case SymbolRecordKind::CalleeSym:
+ FieldName = "Caller";
+ break;
+ case SymbolRecordKind::InlineesSym:
+ FieldName = "Inlinee";
+ break;
+ default:
+ return llvm::make_error<CodeViewError>(
+ "Unknown CV Record type for a CallerSym object!");
+ }
+ for (auto FuncID : Caller.Indices) {
+ printTypeIndex(FieldName, FuncID);
+ }
+ });
+ return Error::success();
+}
+
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewLogicalVisitor"
@@ -2897,7 +2936,7 @@ Error LVLogicalVisitor::finishVisitation(CVType &Record, TypeIndex TI,
// Customized version of 'FieldListVisitHelper'.
Error LVLogicalVisitor::visitFieldListMemberStream(
TypeIndex TI, LVElement *Element, ArrayRef<uint8_t> FieldList) {
- BinaryByteStream Stream(FieldList, llvm::support::little);
+ BinaryByteStream Stream(FieldList, llvm::endianness::little);
BinaryStreamReader Reader(Stream);
FieldListDeserializer Deserializer(Reader);
TypeVisitorCallbackPipeline Pipeline;
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
index ab458341a0bd..4469092099da 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
@@ -1058,7 +1058,7 @@ void LVELFReader::processLocationMember(dwarf::Attribute Attr,
CurrentSymbol->addLocationConstant(Attr, *FormValue.getAsUnsignedConstant(),
OffsetOnEntry);
else
- // This is a a location description, or a reference to one.
+ // This is a location description, or a reference to one.
processLocationList(Attr, FormValue, Die, OffsetOnEntry);
}
diff --git a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
index c26caa647ed9..ed2d14dd79e4 100644
--- a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
+++ b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
@@ -16,6 +16,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -248,6 +249,8 @@ uint32_t MSFBuilder::computeDirectoryByteSize() const {
}
Expected<MSFLayout> MSFBuilder::generateLayout() {
+ llvm::TimeTraceScope timeScope("MSF: Generate layout");
+
SuperBlock *SB = Allocator.Allocate<SuperBlock>();
MSFLayout L;
L.SB = SB;
@@ -336,6 +339,8 @@ static void commitFpm(WritableBinaryStream &MsfBuffer, const MSFLayout &Layout,
Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path,
MSFLayout &Layout) {
+ llvm::TimeTraceScope timeScope("Commit MSF");
+
Expected<MSFLayout> L = generateLayout();
if (!L)
return L.takeError();
@@ -381,7 +386,7 @@ Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path,
return std::move(EC);
FileBufferByteStream Buffer(std::move(*OutFileOrError),
- llvm::support::little);
+ llvm::endianness::little);
BinaryStreamWriter Writer(Buffer);
if (auto EC = Writer.writeObject(*Layout.SB))
diff --git a/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp b/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
index 94935d63452e..5ebb76994b31 100644
--- a/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
+++ b/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
@@ -10,7 +10,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/Support/BinaryStreamWriter.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
index 9755f2ca3bdc..f27a645c7704 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
@@ -9,7 +9,6 @@
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include <cstdint>
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
index 37c1b0407268..ad3d09ae50e9 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -18,6 +18,7 @@
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Parallel.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -187,7 +188,7 @@ Error DbiStreamBuilder::generateFileInfoSubstream() {
uint32_t NamesOffset = calculateNamesOffset();
FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
- llvm::support::little);
+ llvm::endianness::little);
WritableBinaryStreamRef MetadataBuffer =
WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
@@ -381,6 +382,7 @@ void DbiStreamBuilder::createSectionMap(
Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
WritableBinaryStreamRef MsfBuffer) {
+ llvm::TimeTraceScope timeScope("Commit DBI stream");
if (auto EC = finalize())
return EC;
diff --git a/llvm/lib/DebugInfo/PDB/Native/FormatUtil.cpp b/llvm/lib/DebugInfo/PDB/Native/FormatUtil.cpp
index 9c05d585831a..c5999bffc021 100644
--- a/llvm/lib/DebugInfo/PDB/Native/FormatUtil.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/FormatUtil.cpp
@@ -9,6 +9,7 @@
#include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
@@ -119,9 +120,7 @@ std::string llvm::pdb::formatTypeLeafKind(TypeLeafKind K) {
return #EnumName;
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
default:
- return formatv("UNKNOWN RECORD ({0:X})",
- static_cast<std::underlying_type_t<TypeLeafKind>>(K))
- .str();
+ return formatv("UNKNOWN RECORD ({0:X})", llvm::to_underlying(K)).str();
}
}
diff --git a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
index b17fbd63e9fd..c195754c0c67 100644
--- a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/BinaryItemStream.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Parallel.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <vector>
@@ -393,7 +394,7 @@ static Error writePublics(BinaryStreamWriter &Writer,
static Error writeRecords(BinaryStreamWriter &Writer,
ArrayRef<CVSymbol> Records) {
- BinaryItemStream<CVSymbol> ItemStream(support::endianness::little);
+ BinaryItemStream<CVSymbol> ItemStream(llvm::endianness::little);
ItemStream.setItems(Records);
BinaryStreamRef RecordsRef(ItemStream);
return Writer.writeStreamRef(RecordsRef);
@@ -478,6 +479,7 @@ Error GSIStreamBuilder::commitGlobalsHashStream(
Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout,
WritableBinaryStreamRef Buffer) {
+ llvm::TimeTraceScope timeScope("Commit GSI stream");
auto GS = WritableMappedBlockStream::createIndexedStream(
Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator());
auto PS = WritableMappedBlockStream::createIndexedStream(
diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
index e8f5a451b08e..95107125701d 100644
--- a/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
@@ -14,6 +14,7 @@
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -55,6 +56,7 @@ Error InfoStreamBuilder::finalizeMsfLayout() {
Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout,
WritableBinaryStreamRef Buffer) const {
+ llvm::TimeTraceScope timeScope("Commit info stream");
auto InfoS = WritableMappedBlockStream::createIndexedStream(
Layout, Buffer, StreamPDB, Msf.getAllocator());
BinaryStreamWriter Writer(*InfoS);
diff --git a/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp b/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp
index f1e8adeb1b21..841068c77d48 100644
--- a/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp
@@ -14,7 +14,6 @@
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::msf;
diff --git a/llvm/lib/DebugInfo/PDB/Native/InputFile.cpp b/llvm/lib/DebugInfo/PDB/Native/InputFile.cpp
index 85c22483fa90..328d0f5ab060 100644
--- a/llvm/lib/DebugInfo/PDB/Native/InputFile.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/InputFile.cpp
@@ -107,7 +107,7 @@ static inline bool isCodeViewDebugSubsection(object::SectionRef Section,
return false;
}
- Reader = BinaryStreamReader(*ContentsOrErr, support::little);
+ Reader = BinaryStreamReader(*ContentsOrErr, llvm::endianness::little);
uint32_t Magic;
if (Reader.bytesRemaining() < sizeof(uint32_t))
return false;
@@ -561,7 +561,7 @@ static bool isMyCode(const SymbolGroup &Group) {
return true;
StringRef Name = Group.name();
- if (Name.startswith("Import:"))
+ if (Name.starts_with("Import:"))
return false;
if (Name.ends_with_insensitive(".dll"))
return false;
diff --git a/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
index 500923e57fbb..bdf8e6ec1acd 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
-#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/PDB/Native/Hash.h"
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
index 91b428afaddb..d5cac33d1519 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -74,7 +74,7 @@ Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,
std::unique_ptr<IPDBSession> &Session) {
StringRef Path = Buffer->getBufferIdentifier();
auto Stream = std::make_unique<MemoryBufferByteStream>(
- std::move(Buffer), llvm::support::little);
+ std::move(Buffer), llvm::endianness::little);
auto Allocator = std::make_unique<BumpPtrAllocator>();
auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator);
@@ -104,8 +104,8 @@ loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
if (EC || Magic != file_magic::pdb)
return make_error<RawError>(EC);
- auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer),
- llvm::support::little);
+ auto Stream = std::make_unique<MemoryBufferByteStream>(
+ std::move(Buffer), llvm::endianness::little);
auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
if (auto EC = File->parseFileHeaders())
@@ -176,7 +176,7 @@ NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
if (!PathOrErr)
return PathOrErr.takeError();
StringRef PathFromExe = PathOrErr.get();
- sys::path::Style Style = PathFromExe.startswith("/")
+ sys::path::Style Style = PathFromExe.starts_with("/")
? sys::path::Style::posix
: sys::path::Style::windows;
StringRef PdbName = sys::path::filename(PathFromExe, Style);
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
index cd30b56be7cd..06e379c3f6d2 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include <ctime>
@@ -129,6 +130,7 @@ void PDBFileBuilder::addInjectedSource(StringRef Name,
}
Error PDBFileBuilder::finalizeMsfLayout() {
+ llvm::TimeTraceScope timeScope("MSF layout");
if (Ipi && Ipi->getRecordCount() > 0) {
// In theory newer PDBs always have an ID stream, but by saying that we're
@@ -254,6 +256,7 @@ void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
if (InjectedSourceTable.empty())
return;
+ llvm::TimeTraceScope timeScope("Commit injected sources");
commitSrcHeaderBlock(MsfBuffer, Layout);
for (const auto &IS : InjectedSources) {
@@ -290,15 +293,18 @@ Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
if (auto EC = Strings.commit(NSWriter))
return EC;
- for (const auto &NSE : NamedStreamData) {
- if (NSE.second.empty())
- continue;
+ {
+ llvm::TimeTraceScope timeScope("Named stream data");
+ for (const auto &NSE : NamedStreamData) {
+ if (NSE.second.empty())
+ continue;
- auto NS = WritableMappedBlockStream::createIndexedStream(
- Layout, Buffer, NSE.first, Allocator);
- BinaryStreamWriter NSW(*NS);
- if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
- return EC;
+ auto NS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, NSE.first, Allocator);
+ BinaryStreamWriter NSW(*NS);
+ if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
+ return EC;
+ }
}
if (Info) {
@@ -338,6 +344,8 @@ Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
// Set the build id at the very end, after every other byte of the PDB
// has been written.
if (Info->hashPDBContentsToGUID()) {
+ llvm::TimeTraceScope timeScope("Compute build ID");
+
// Compute a hash of all sections of the output file.
uint64_t Digest =
xxh3_64bits({Buffer.getBufferStart(), Buffer.getBufferEnd()});
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
index c0245dc17cf1..91b3dd5c32b9 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
@@ -13,6 +13,7 @@
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/TimeProfiler.h"
#include <map>
@@ -207,6 +208,7 @@ Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const {
}
Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {
+ llvm::TimeTraceScope timeScope("Commit strings table");
BinaryStreamWriter SectionWriter;
std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader));
diff --git a/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp
index c7b9f443da5e..c350e0e0b3e1 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp
@@ -26,7 +26,6 @@
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cstdint>
diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp
index 5802d1c77527..5dd636f326b7 100644
--- a/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp
@@ -9,7 +9,6 @@
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::msf;
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
index b71b2b158144..941ce78027a2 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -19,7 +19,7 @@ using namespace llvm::pdb;
// Corresponds to `fUDTAnon`.
static bool isAnonymous(StringRef Name) {
return Name == "<unnamed-tag>" || Name == "__unnamed" ||
- Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed");
+ Name.ends_with("::<unnamed-tag>") || Name.ends_with("::__unnamed");
}
// Computes the hash for a user-defined type record. This could be a struct,
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
index aad5847651a0..22663f009637 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <cstdint>
#include <numeric>
@@ -164,13 +165,14 @@ Error TpiStreamBuilder::finalizeMsfLayout() {
reinterpret_cast<const uint8_t *>(HashBuffer.data()),
calculateHashBufferSize());
HashValueStream =
- std::make_unique<BinaryByteStream>(Bytes, llvm::support::little);
+ std::make_unique<BinaryByteStream>(Bytes, llvm::endianness::little);
}
return Error::success();
}
Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
WritableBinaryStreamRef Buffer) {
+ llvm::TimeTraceScope timeScope("Commit TPI stream");
if (auto EC = finalize())
return EC;
diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index f9669b554b47..716312f26e0b 100644
--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -90,7 +90,7 @@ public:
size_t PosEnd = PrunedSource->find('\n', Pos);
StringRef String = PrunedSource->substr(
Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
- if (String.endswith("\r"))
+ if (String.ends_with("\r"))
String = String.drop_back(1);
OS << format_decimal(L, MaxLineNumberWidth);
if (L == Line)
@@ -105,10 +105,10 @@ public:
}
};
-void PlainPrinterBase::printHeader(uint64_t Address) {
- if (Config.PrintAddress) {
+void PlainPrinterBase::printHeader(std::optional<uint64_t> Address) {
+ if (Address.has_value() && Config.PrintAddress) {
OS << "0x";
- OS.write_hex(Address);
+ OS.write_hex(*Address);
StringRef Delimiter = Config.Pretty ? ": " : "\n";
OS << Delimiter;
}
@@ -182,7 +182,7 @@ void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
}
void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
- printHeader(*Request.Address);
+ printHeader(Request.Address);
print(Info, false);
printFooter();
}
@@ -260,9 +260,15 @@ void PlainPrinterBase::print(const Request &Request,
printFooter();
}
-void PlainPrinterBase::printInvalidCommand(const Request &Request,
- StringRef Command) {
- OS << Command << '\n';
+void PlainPrinterBase::print(const Request &Request,
+ const std::vector<DILineInfo> &Locations) {
+ if (Locations.empty()) {
+ print(Request, DILineInfo());
+ } else {
+ for (const DILineInfo &L : Locations)
+ print(L, false);
+ printFooter();
+ }
}
bool PlainPrinterBase::printError(const Request &Request,
@@ -278,6 +284,8 @@ static std::string toHex(uint64_t V) {
static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
json::Object Json({{"ModuleName", Request.ModuleName.str()}});
+ if (!Request.Symbol.empty())
+ Json["SymName"] = Request.Symbol.str();
if (Request.Address)
Json["Address"] = toHex(*Request.Address);
if (!ErrorMsg.empty())
@@ -367,11 +375,17 @@ void JSONPrinter::print(const Request &Request,
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)));
+void JSONPrinter::print(const Request &Request,
+ const std::vector<DILineInfo> &Locations) {
+ json::Array Definitions;
+ for (const DILineInfo &L : Locations)
+ Definitions.push_back(toJSON(L));
+ json::Object Json = toJSON(Request);
+ Json["Loc"] = std::move(Definitions);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
}
bool JSONPrinter::printError(const Request &Request,
diff --git a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
index a2bc2577b70a..f7503ef49693 100644
--- a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp
@@ -552,7 +552,7 @@ std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str) const {
}
if (all_of(Str, [](char C) { return C == '0'; }))
return 0;
- if (!Str.startswith("0x")) {
+ if (!Str.starts_with("0x")) {
reportTypeError(Str, "address");
return std::nullopt;
}
@@ -741,7 +741,7 @@ uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const {
}
StringRef MarkupFilter::lineEnding() const {
- return Line.endswith("\r\n") ? "\r\n" : "\n";
+ return Line.ends_with("\r\n") ? "\r\n" : "\n";
}
bool MarkupFilter::MMap::contains(uint64_t Addr) const {
diff --git a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
index 6b8068a531c0..697303038507 100644
--- a/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -351,6 +351,19 @@ std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(
return DebugInfoContext->getLocalsForAddress(ModuleOffset);
}
+std::vector<object::SectionedAddress>
+SymbolizableObjectFile::findSymbol(StringRef Symbol) const {
+ std::vector<object::SectionedAddress> Result;
+ for (const SymbolDesc &Sym : Symbols) {
+ if (Sym.Name.equals(Symbol)) {
+ object::SectionedAddress A{Sym.Addr,
+ getModuleSectionIndexForAddress(Sym.Addr)};
+ Result.push_back(A);
+ }
+ }
+ return Result;
+}
+
/// Search for the first occurence of specified Address in ObjectFile.
uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(
uint64_t Address) const {
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 517f1e7dc284..15f2a6ece8b8 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -231,6 +231,50 @@ LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
return symbolizeFrameCommon(BuildID, ModuleOffset);
}
+template <typename T>
+Expected<std::vector<DILineInfo>>
+LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol) {
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+ std::vector<DILineInfo> Result;
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return Result;
+
+ for (object::SectionedAddress A : Info->findSymbol(Symbol)) {
+ DILineInfo LineInfo = Info->symbolizeCode(
+ A, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
+ Opts.UseSymbolTable);
+ if (LineInfo.FileName != DILineInfo::BadString) {
+ if (Opts.Demangle)
+ LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
+ Result.push_back(LineInfo);
+ }
+ }
+
+ return Result;
+}
+
+Expected<std::vector<DILineInfo>>
+LLVMSymbolizer::findSymbol(const ObjectFile &Obj, StringRef Symbol) {
+ return findSymbolCommon(Obj, Symbol);
+}
+
+Expected<std::vector<DILineInfo>>
+LLVMSymbolizer::findSymbol(StringRef ModuleName, StringRef Symbol) {
+ return findSymbolCommon(ModuleName.str(), Symbol);
+}
+
+Expected<std::vector<DILineInfo>>
+LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol) {
+ return findSymbolCommon(BuildID, Symbol);
+}
+
void LLVMSymbolizer::flush() {
ObjectForUBPathAndArch.clear();
LRUBinaries.clear();
@@ -673,7 +717,7 @@ StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
// Remove any ending '@' for vectorcall.
bool IsVectorCall = false;
- if (HasAtNumSuffix && SymbolName.endswith("@")) {
+ if (HasAtNumSuffix && SymbolName.ends_with("@")) {
SymbolName = SymbolName.drop_back();
IsVectorCall = true;
}