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