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