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