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