1 | //===- DWARFDebugPubTable.cpp ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" |
10 | #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" |
11 | #include "llvm/ADT/StringRef.h" |
12 | #include "llvm/BinaryFormat/Dwarf.h" |
13 | #include "llvm/Support/DataExtractor.h" |
14 | #include "llvm/Support/Errc.h" |
15 | #include "llvm/Support/Format.h" |
16 | #include "llvm/Support/raw_ostream.h" |
17 | #include <cstdint> |
18 | |
19 | using namespace llvm; |
20 | using namespace dwarf; |
21 | |
22 | void DWARFDebugPubTable::( |
23 | DWARFDataExtractor Data, bool GnuStyle, |
24 | function_ref<void(Error)> RecoverableErrorHandler) { |
25 | this->GnuStyle = GnuStyle; |
26 | Sets.clear(); |
27 | uint64_t Offset = 0; |
28 | while (Data.isValidOffset(offset: Offset)) { |
29 | uint64_t SetOffset = Offset; |
30 | Sets.push_back(x: {}); |
31 | Set &NewSet = Sets.back(); |
32 | |
33 | DataExtractor::Cursor C(Offset); |
34 | std::tie(args&: NewSet.Length, args&: NewSet.Format) = Data.getInitialLength(C); |
35 | if (!C) { |
36 | // Drop the newly added set because it does not contain anything useful |
37 | // to dump. |
38 | Sets.pop_back(); |
39 | RecoverableErrorHandler(createStringError( |
40 | EC: errc::invalid_argument, |
41 | Fmt: "name lookup table at offset 0x%" PRIx64 " parsing failed: %s" , |
42 | Vals: SetOffset, Vals: toString(E: C.takeError()).c_str())); |
43 | return; |
44 | } |
45 | |
46 | Offset = C.tell() + NewSet.Length; |
47 | DWARFDataExtractor SetData(Data, Offset); |
48 | const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(Format: NewSet.Format); |
49 | |
50 | NewSet.Version = SetData.getU16(C); |
51 | NewSet.Offset = SetData.getRelocatedValue(C, Size: OffsetSize); |
52 | NewSet.Size = SetData.getUnsigned(C, Size: OffsetSize); |
53 | |
54 | if (!C) { |
55 | // Preserve the newly added set because at least some fields of the header |
56 | // are read and can be dumped. |
57 | RecoverableErrorHandler( |
58 | createStringError(EC: errc::invalid_argument, |
59 | Fmt: "name lookup table at offset 0x%" PRIx64 |
60 | " does not have a complete header: %s" , |
61 | Vals: SetOffset, Vals: toString(E: C.takeError()).c_str())); |
62 | continue; |
63 | } |
64 | |
65 | while (C) { |
66 | uint64_t DieRef = SetData.getUnsigned(C, Size: OffsetSize); |
67 | if (DieRef == 0) |
68 | break; |
69 | uint8_t IndexEntryValue = GnuStyle ? SetData.getU8(C) : 0; |
70 | StringRef Name = SetData.getCStrRef(C); |
71 | if (C) |
72 | NewSet.Entries.push_back( |
73 | x: {.SecOffset: DieRef, .Descriptor: PubIndexEntryDescriptor(IndexEntryValue), .Name: Name}); |
74 | } |
75 | |
76 | if (!C) { |
77 | RecoverableErrorHandler(createStringError( |
78 | EC: errc::invalid_argument, |
79 | Fmt: "name lookup table at offset 0x%" PRIx64 " parsing failed: %s" , |
80 | Vals: SetOffset, Vals: toString(E: C.takeError()).c_str())); |
81 | continue; |
82 | } |
83 | if (C.tell() != Offset) |
84 | RecoverableErrorHandler(createStringError( |
85 | EC: errc::invalid_argument, |
86 | Fmt: "name lookup table at offset 0x%" PRIx64 |
87 | " has a terminator at offset 0x%" PRIx64 |
88 | " before the expected end at 0x%" PRIx64, |
89 | Vals: SetOffset, Vals: C.tell() - OffsetSize, Vals: Offset - OffsetSize)); |
90 | } |
91 | } |
92 | |
93 | void DWARFDebugPubTable::dump(raw_ostream &OS) const { |
94 | for (const Set &S : Sets) { |
95 | int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format: S.Format); |
96 | OS << "length = " << format(Fmt: "0x%0*" PRIx64, Vals: OffsetDumpWidth, Vals: S.Length); |
97 | OS << ", format = " << dwarf::FormatString(Format: S.Format); |
98 | OS << ", version = " << format(Fmt: "0x%04x" , Vals: S.Version); |
99 | OS << ", unit_offset = " |
100 | << format(Fmt: "0x%0*" PRIx64, Vals: OffsetDumpWidth, Vals: S.Offset); |
101 | OS << ", unit_size = " << format(Fmt: "0x%0*" PRIx64, Vals: OffsetDumpWidth, Vals: S.Size) |
102 | << '\n'; |
103 | OS << (GnuStyle ? "Offset Linkage Kind Name\n" |
104 | : "Offset Name\n" ); |
105 | |
106 | for (const Entry &E : S.Entries) { |
107 | OS << format(Fmt: "0x%0*" PRIx64 " " , Vals: OffsetDumpWidth, Vals: E.SecOffset); |
108 | if (GnuStyle) { |
109 | StringRef EntryLinkage = |
110 | GDBIndexEntryLinkageString(Linkage: E.Descriptor.Linkage); |
111 | StringRef EntryKind = dwarf::GDBIndexEntryKindString(Kind: E.Descriptor.Kind); |
112 | OS << format(Fmt: "%-8s" , Vals: EntryLinkage.data()) << ' ' |
113 | << format(Fmt: "%-8s" , Vals: EntryKind.data()) << ' '; |
114 | } |
115 | OS << '\"' << E.Name << "\"\n" ; |
116 | } |
117 | } |
118 | } |
119 | |