]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordName.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / DebugInfo / CodeView / RecordName.cpp
1 //===- RecordName.cpp ----------------------------------------- *- C++ --*-===//
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/CodeView/RecordName.h"
10
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
13 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
14 #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
16 #include "llvm/Support/FormatVariadic.h"
17
18 using namespace llvm;
19 using namespace llvm::codeview;
20
21 namespace {
22 class TypeNameComputer : public TypeVisitorCallbacks {
23   /// The type collection.  Used to calculate names of nested types.
24   TypeCollection &Types;
25   TypeIndex CurrentTypeIndex = TypeIndex::None();
26
27   /// Name of the current type. Only valid before visitTypeEnd.
28   SmallString<256> Name;
29
30 public:
31   explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
32
33   StringRef name() const { return Name; }
34
35   /// Paired begin/end actions for all types. Receives all record data,
36   /// including the fixed-length record prefix.
37   Error visitTypeBegin(CVType &Record) override;
38   Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
39   Error visitTypeEnd(CVType &Record) override;
40
41 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
42   Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
43 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
44 #define MEMBER_RECORD(EnumName, EnumVal, Name)
45 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
46 };
47 } // namespace
48
49 Error TypeNameComputer::visitTypeBegin(CVType &Record) {
50   llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
51   return Error::success();
52 }
53
54 Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) {
55   // Reset Name to the empty string. If the visitor sets it, we know it.
56   Name = "";
57   CurrentTypeIndex = Index;
58   return Error::success();
59 }
60
61 Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
62
63 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
64                                          FieldListRecord &FieldList) {
65   Name = "<field list>";
66   return Error::success();
67 }
68
69 Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
70                                          StringIdRecord &String) {
71   Name = String.getString();
72   return Error::success();
73 }
74
75 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
76   auto Indices = Args.getIndices();
77   uint32_t Size = Indices.size();
78   Name = "(";
79   for (uint32_t I = 0; I < Size; ++I) {
80     assert(Indices[I] < CurrentTypeIndex);
81
82     Name.append(Types.getTypeName(Indices[I]));
83     if (I + 1 != Size)
84       Name.append(", ");
85   }
86   Name.push_back(')');
87   return Error::success();
88 }
89
90 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
91                                          StringListRecord &Strings) {
92   auto Indices = Strings.getIndices();
93   uint32_t Size = Indices.size();
94   Name = "\"";
95   for (uint32_t I = 0; I < Size; ++I) {
96     Name.append(Types.getTypeName(Indices[I]));
97     if (I + 1 != Size)
98       Name.append("\" \"");
99   }
100   Name.push_back('\"');
101   return Error::success();
102 }
103
104 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
105   Name = Class.getName();
106   return Error::success();
107 }
108
109 Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
110   Name = Union.getName();
111   return Error::success();
112 }
113
114 Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
115   Name = Enum.getName();
116   return Error::success();
117 }
118
119 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
120   Name = AT.getName();
121   return Error::success();
122 }
123
124 Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
125   Name = VFT.getName();
126   return Error::success();
127 }
128
129 Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
130   Name = Id.getName();
131   return Error::success();
132 }
133
134 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
135   StringRef Ret = Types.getTypeName(Proc.getReturnType());
136   StringRef Params = Types.getTypeName(Proc.getArgumentList());
137   Name = formatv("{0} {1}", Ret, Params).sstr<256>();
138   return Error::success();
139 }
140
141 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
142                                          MemberFunctionRecord &MF) {
143   StringRef Ret = Types.getTypeName(MF.getReturnType());
144   StringRef Class = Types.getTypeName(MF.getClassType());
145   StringRef Params = Types.getTypeName(MF.getArgumentList());
146   Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
147   return Error::success();
148 }
149
150 Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
151   Name = Func.getName();
152   return Error::success();
153 }
154
155 Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
156   Name = TS.getName();
157   return Error::success();
158 }
159
160 Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
161
162   if (Ptr.isPointerToMember()) {
163     const MemberPointerInfo &MI = Ptr.getMemberInfo();
164
165     StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
166     StringRef Class = Types.getTypeName(MI.getContainingType());
167     Name = formatv("{0} {1}::*", Pointee, Class);
168   } else {
169     Name.append(Types.getTypeName(Ptr.getReferentType()));
170
171     if (Ptr.getMode() == PointerMode::LValueReference)
172       Name.append("&");
173     else if (Ptr.getMode() == PointerMode::RValueReference)
174       Name.append("&&");
175     else if (Ptr.getMode() == PointerMode::Pointer)
176       Name.append("*");
177
178     // Qualifiers in pointer records apply to the pointer, not the pointee, so
179     // they go on the right.
180     if (Ptr.isConst())
181       Name.append(" const");
182     if (Ptr.isVolatile())
183       Name.append(" volatile");
184     if (Ptr.isUnaligned())
185       Name.append(" __unaligned");
186     if (Ptr.isRestrict())
187       Name.append(" __restrict");
188   }
189   return Error::success();
190 }
191
192 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
193   uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
194
195   if (Mods & uint16_t(ModifierOptions::Const))
196     Name.append("const ");
197   if (Mods & uint16_t(ModifierOptions::Volatile))
198     Name.append("volatile ");
199   if (Mods & uint16_t(ModifierOptions::Unaligned))
200     Name.append("__unaligned ");
201   Name.append(Types.getTypeName(Mod.getModifiedType()));
202   return Error::success();
203 }
204
205 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
206                                          VFTableShapeRecord &Shape) {
207   Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
208   return Error::success();
209 }
210
211 Error TypeNameComputer::visitKnownRecord(
212     CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
213   return Error::success();
214 }
215
216 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
217                                          UdtSourceLineRecord &SourceLine) {
218   return Error::success();
219 }
220
221 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
222   return Error::success();
223 }
224
225 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
226                                          MethodOverloadListRecord &Overloads) {
227   return Error::success();
228 }
229
230 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
231   return Error::success();
232 }
233
234 Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
235   return Error::success();
236 }
237
238 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
239                                          PrecompRecord &Precomp) {
240   return Error::success();
241 }
242
243 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
244                                          EndPrecompRecord &EndPrecomp) {
245   return Error::success();
246 }
247
248 std::string llvm::codeview::computeTypeName(TypeCollection &Types,
249                                             TypeIndex Index) {
250   TypeNameComputer Computer(Types);
251   CVType Record = Types.getType(Index);
252   if (auto EC = visitTypeRecord(Record, Index, Computer)) {
253     consumeError(std::move(EC));
254     return "<unknown UDT>";
255   }
256   return Computer.name();
257 }
258
259 static int getSymbolNameOffset(CVSymbol Sym) {
260   switch (Sym.kind()) {
261   // See ProcSym
262   case SymbolKind::S_GPROC32:
263   case SymbolKind::S_LPROC32:
264   case SymbolKind::S_GPROC32_ID:
265   case SymbolKind::S_LPROC32_ID:
266   case SymbolKind::S_LPROC32_DPC:
267   case SymbolKind::S_LPROC32_DPC_ID:
268     return 35;
269   // See Thunk32Sym
270   case SymbolKind::S_THUNK32:
271     return 21;
272   // See SectionSym
273   case SymbolKind::S_SECTION:
274     return 16;
275   // See CoffGroupSym
276   case SymbolKind::S_COFFGROUP:
277     return 14;
278   // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
279   case SymbolKind::S_PUB32:
280   case SymbolKind::S_FILESTATIC:
281   case SymbolKind::S_REGREL32:
282   case SymbolKind::S_GDATA32:
283   case SymbolKind::S_LDATA32:
284   case SymbolKind::S_LMANDATA:
285   case SymbolKind::S_GMANDATA:
286   case SymbolKind::S_LTHREAD32:
287   case SymbolKind::S_GTHREAD32:
288   case SymbolKind::S_PROCREF:
289   case SymbolKind::S_LPROCREF:
290     return 10;
291   // See RegisterSym and LocalSym
292   case SymbolKind::S_REGISTER:
293   case SymbolKind::S_LOCAL:
294     return 6;
295   // See BlockSym
296   case SymbolKind::S_BLOCK32:
297     return 18;
298   // See LabelSym
299   case SymbolKind::S_LABEL32:
300     return 7;
301   // See ObjNameSym, ExportSym, and UDTSym
302   case SymbolKind::S_OBJNAME:
303   case SymbolKind::S_EXPORT:
304   case SymbolKind::S_UDT:
305     return 4;
306   // See BPRelativeSym
307   case SymbolKind::S_BPREL32:
308     return 8;
309   // See UsingNamespaceSym
310   case SymbolKind::S_UNAMESPACE:
311     return 0;
312   default:
313     return -1;
314   }
315 }
316
317 StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
318   if (Sym.kind() == SymbolKind::S_CONSTANT) {
319     // S_CONSTANT is preceded by an APSInt, which has a variable length.  So we
320     // have to do a full deserialization.
321     BinaryStreamReader Reader(Sym.content(), llvm::support::little);
322     // The container doesn't matter for single records.
323     SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
324     ConstantSym Const(SymbolKind::S_CONSTANT);
325     cantFail(Mapping.visitSymbolBegin(Sym));
326     cantFail(Mapping.visitKnownRecord(Sym, Const));
327     cantFail(Mapping.visitSymbolEnd(Sym));
328     return Const.Name;
329   }
330
331   int Offset = getSymbolNameOffset(Sym);
332   if (Offset == -1)
333     return StringRef();
334
335   StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
336   return StringData.split('\0').first;
337 }