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:
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     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 
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 
105 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
106   Name = Class.getName();
107   return Error::success();
108 }
109 
110 Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
111   Name = Union.getName();
112   return Error::success();
113 }
114 
115 Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
116   Name = Enum.getName();
117   return Error::success();
118 }
119 
120 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
121   Name = AT.getName();
122   return Error::success();
123 }
124 
125 Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
126   Name = VFT.getName();
127   return Error::success();
128 }
129 
130 Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
131   Name = Id.getName();
132   return Error::success();
133 }
134 
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 
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 
151 Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
152   Name = Func.getName();
153   return Error::success();
154 }
155 
156 Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
157   Name = TS.getName();
158   return Error::success();
159 }
160 
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     if (Ptr.isConst())
171       Name.append("const ");
172     if (Ptr.isVolatile())
173       Name.append("volatile ");
174     if (Ptr.isUnaligned())
175       Name.append("__unaligned ");
176 
177     Name.append(Types.getTypeName(Ptr.getReferentType()));
178 
179     if (Ptr.getMode() == PointerMode::LValueReference)
180       Name.append("&");
181     else if (Ptr.getMode() == PointerMode::RValueReference)
182       Name.append("&&");
183     else if (Ptr.getMode() == PointerMode::Pointer)
184       Name.append("*");
185   }
186   return Error::success();
187 }
188 
189 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
190   uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
191 
192   if (Mods & uint16_t(ModifierOptions::Const))
193     Name.append("const ");
194   if (Mods & uint16_t(ModifierOptions::Volatile))
195     Name.append("volatile ");
196   if (Mods & uint16_t(ModifierOptions::Unaligned))
197     Name.append("__unaligned ");
198   Name.append(Types.getTypeName(Mod.getModifiedType()));
199   return Error::success();
200 }
201 
202 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
203                                          VFTableShapeRecord &Shape) {
204   Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
205   return Error::success();
206 }
207 
208 Error TypeNameComputer::visitKnownRecord(
209     CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
210   return Error::success();
211 }
212 
213 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
214                                          UdtSourceLineRecord &SourceLine) {
215   return Error::success();
216 }
217 
218 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
219   return Error::success();
220 }
221 
222 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
223                                          MethodOverloadListRecord &Overloads) {
224   return Error::success();
225 }
226 
227 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
228   return Error::success();
229 }
230 
231 Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
232   return Error::success();
233 }
234 
235 std::string llvm::codeview::computeTypeName(TypeCollection &Types,
236                                             TypeIndex Index) {
237   TypeNameComputer Computer(Types);
238   CVType Record = Types.getType(Index);
239   if (auto EC = visitTypeRecord(Record, Index, Computer)) {
240     consumeError(std::move(EC));
241     return "<unknown UDT>";
242   }
243   return Computer.name();
244 }
245 
246 static int getSymbolNameOffset(CVSymbol Sym) {
247   switch (Sym.kind()) {
248   // See ProcSym
249   case SymbolKind::S_GPROC32:
250   case SymbolKind::S_LPROC32:
251   case SymbolKind::S_GPROC32_ID:
252   case SymbolKind::S_LPROC32_ID:
253   case SymbolKind::S_LPROC32_DPC:
254   case SymbolKind::S_LPROC32_DPC_ID:
255     return 35;
256   // See Thunk32Sym
257   case SymbolKind::S_THUNK32:
258     return 21;
259   // See SectionSym
260   case SymbolKind::S_SECTION:
261     return 16;
262   // See CoffGroupSym
263   case SymbolKind::S_COFFGROUP:
264     return 14;
265   // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
266   case SymbolKind::S_PUB32:
267   case SymbolKind::S_FILESTATIC:
268   case SymbolKind::S_REGREL32:
269   case SymbolKind::S_GDATA32:
270   case SymbolKind::S_LDATA32:
271   case SymbolKind::S_LMANDATA:
272   case SymbolKind::S_GMANDATA:
273   case SymbolKind::S_LTHREAD32:
274   case SymbolKind::S_GTHREAD32:
275     return 10;
276   // See RegisterSym and LocalSym
277   case SymbolKind::S_REGISTER:
278   case SymbolKind::S_LOCAL:
279     return 6;
280   // See BlockSym
281   case SymbolKind::S_BLOCK32:
282     return 18;
283   // See LabelSym
284   case SymbolKind::S_LABEL32:
285     return 7;
286   // See ObjNameSym, ExportSym, and UDTSym
287   case SymbolKind::S_OBJNAME:
288   case SymbolKind::S_EXPORT:
289   case SymbolKind::S_UDT:
290     return 4;
291   // See BPRelativeSym
292   case SymbolKind::S_BPREL32:
293     return 8;
294   default:
295     return -1;
296   }
297 }
298 
299 StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
300   if (Sym.kind() == SymbolKind::S_CONSTANT) {
301     // S_CONSTANT is preceded by an APSInt, which has a variable length.  So we
302     // have to do a full deserialization.
303     BinaryStreamReader Reader(Sym.content(), llvm::support::little);
304     // The container doesn't matter for single records.
305     SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
306     ConstantSym Const(SymbolKind::S_CONSTANT);
307     cantFail(Mapping.visitSymbolBegin(Sym));
308     cantFail(Mapping.visitKnownRecord(Sym, Const));
309     cantFail(Mapping.visitSymbolEnd(Sym));
310     return Const.Name;
311   }
312 
313   int Offset = getSymbolNameOffset(Sym);
314   if (Offset == -1)
315     return StringRef();
316 
317   StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
318   return StringData.split('\0').first;
319 }
320