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