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   SmallString<256> TypeName;
193   if (Mods & uint16_t(ModifierOptions::Const))
194     Name.append("const ");
195   if (Mods & uint16_t(ModifierOptions::Volatile))
196     Name.append("volatile ");
197   if (Mods & uint16_t(ModifierOptions::Unaligned))
198     Name.append("__unaligned ");
199   Name.append(Types.getTypeName(Mod.getModifiedType()));
200   return Error::success();
201 }
202 
203 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
204                                          VFTableShapeRecord &Shape) {
205   Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
206   return Error::success();
207 }
208 
209 Error TypeNameComputer::visitKnownRecord(
210     CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
211   return Error::success();
212 }
213 
214 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
215                                          UdtSourceLineRecord &SourceLine) {
216   return Error::success();
217 }
218 
219 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
220   return Error::success();
221 }
222 
223 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
224                                          MethodOverloadListRecord &Overloads) {
225   return Error::success();
226 }
227 
228 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
229   return Error::success();
230 }
231 
232 Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
233   return Error::success();
234 }
235 
236 std::string llvm::codeview::computeTypeName(TypeCollection &Types,
237                                             TypeIndex Index) {
238   TypeNameComputer Computer(Types);
239   CVType Record = Types.getType(Index);
240   if (auto EC = visitTypeRecord(Record, Index, Computer)) {
241     consumeError(std::move(EC));
242     return "<unknown UDT>";
243   }
244   return Computer.name();
245 }
246 
247 static int getSymbolNameOffset(CVSymbol Sym) {
248   switch (Sym.kind()) {
249   // See ProcSym
250   case SymbolKind::S_GPROC32:
251   case SymbolKind::S_LPROC32:
252   case SymbolKind::S_GPROC32_ID:
253   case SymbolKind::S_LPROC32_ID:
254   case SymbolKind::S_LPROC32_DPC:
255   case SymbolKind::S_LPROC32_DPC_ID:
256     return 35;
257   // See Thunk32Sym
258   case SymbolKind::S_THUNK32:
259     return 21;
260   // See SectionSym
261   case SymbolKind::S_SECTION:
262     return 16;
263   // See CoffGroupSym
264   case SymbolKind::S_COFFGROUP:
265     return 14;
266   // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
267   case SymbolKind::S_PUB32:
268   case SymbolKind::S_FILESTATIC:
269   case SymbolKind::S_REGREL32:
270   case SymbolKind::S_GDATA32:
271   case SymbolKind::S_LDATA32:
272   case SymbolKind::S_LMANDATA:
273   case SymbolKind::S_GMANDATA:
274   case SymbolKind::S_LTHREAD32:
275   case SymbolKind::S_GTHREAD32:
276     return 10;
277   // See RegisterSym and LocalSym
278   case SymbolKind::S_REGISTER:
279   case SymbolKind::S_LOCAL:
280     return 6;
281   // See BlockSym
282   case SymbolKind::S_BLOCK32:
283     return 18;
284   // See LabelSym
285   case SymbolKind::S_LABEL32:
286     return 7;
287   // See ObjNameSym, ExportSym, and UDTSym
288   case SymbolKind::S_OBJNAME:
289   case SymbolKind::S_EXPORT:
290   case SymbolKind::S_UDT:
291     return 4;
292   // See BPRelativeSym
293   case SymbolKind::S_BPREL32:
294     return 8;
295   default:
296     return -1;
297   }
298 }
299 
300 StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
301   if (Sym.kind() == SymbolKind::S_CONSTANT) {
302     // S_CONSTANT is preceded by an APSInt, which has a variable length.  So we
303     // have to do a full deserialization.
304     BinaryStreamReader Reader(Sym.content(), llvm::support::little);
305     // The container doesn't matter for single records.
306     SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
307     ConstantSym Const(SymbolKind::S_CONSTANT);
308     cantFail(Mapping.visitSymbolBegin(Sym));
309     cantFail(Mapping.visitKnownRecord(Sym, Const));
310     cantFail(Mapping.visitSymbolEnd(Sym));
311     return Const.Name;
312   }
313 
314   int Offset = getSymbolNameOffset(Sym);
315   if (Offset == -1)
316     return StringRef();
317 
318   StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
319   return StringData.split('\0').first;
320 }
321