Line data Source code
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 3559 : 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 3559 : 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 0 : Error TypeNameComputer::visitTypeBegin(CVType &Record) {
51 0 : llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
52 : return Error::success();
53 : }
54 :
55 3559 : 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 3559 : CurrentTypeIndex = Index;
59 3559 : return Error::success();
60 : }
61 :
62 7118 : Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
63 :
64 388 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
65 : FieldListRecord &FieldList) {
66 : Name = "<field list>";
67 388 : return Error::success();
68 : }
69 :
70 497 : Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
71 : StringIdRecord &String) {
72 : Name = String.getString();
73 497 : return Error::success();
74 : }
75 :
76 319 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
77 : auto Indices = Args.getIndices();
78 319 : uint32_t Size = Indices.size();
79 : Name = "(";
80 707 : for (uint32_t I = 0; I < Size; ++I) {
81 : assert(Indices[I] < CurrentTypeIndex);
82 :
83 776 : Name.append(Types.getTypeName(Indices[I]));
84 388 : if (I + 1 != Size)
85 : Name.append(", ");
86 : }
87 319 : Name.push_back(')');
88 319 : return Error::success();
89 : }
90 :
91 20 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
92 : StringListRecord &Strings) {
93 : auto Indices = Strings.getIndices();
94 20 : uint32_t Size = Indices.size();
95 : Name = "\"";
96 41 : for (uint32_t I = 0; I < Size; ++I) {
97 42 : Name.append(Types.getTypeName(Indices[I]));
98 21 : if (I + 1 != Size)
99 : Name.append("\" \"");
100 : }
101 20 : Name.push_back('\"');
102 20 : return Error::success();
103 : }
104 :
105 635 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
106 : Name = Class.getName();
107 635 : return Error::success();
108 : }
109 :
110 16 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
111 : Name = Union.getName();
112 16 : return Error::success();
113 : }
114 :
115 99 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
116 : Name = Enum.getName();
117 99 : return Error::success();
118 : }
119 :
120 27 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
121 : Name = AT.getName();
122 27 : return Error::success();
123 : }
124 :
125 4 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
126 : Name = VFT.getName();
127 4 : return Error::success();
128 : }
129 :
130 36 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
131 : Name = Id.getName();
132 36 : return Error::success();
133 : }
134 :
135 216 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
136 432 : StringRef Ret = Types.getTypeName(Proc.getReturnType());
137 432 : StringRef Params = Types.getTypeName(Proc.getArgumentList());
138 432 : Name = formatv("{0} {1}", Ret, Params).sstr<256>();
139 216 : return Error::success();
140 : }
141 :
142 417 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
143 : MemberFunctionRecord &MF) {
144 834 : StringRef Ret = Types.getTypeName(MF.getReturnType());
145 834 : StringRef Class = Types.getTypeName(MF.getClassType());
146 834 : StringRef Params = Types.getTypeName(MF.getArgumentList());
147 834 : Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
148 417 : return Error::success();
149 : }
150 :
151 177 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
152 : Name = Func.getName();
153 177 : return Error::success();
154 : }
155 :
156 0 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
157 : Name = TS.getName();
158 0 : return Error::success();
159 : }
160 :
161 422 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
162 :
163 : if (Ptr.isPointerToMember()) {
164 15 : const MemberPointerInfo &MI = Ptr.getMemberInfo();
165 :
166 30 : StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
167 30 : StringRef Class = Types.getTypeName(MI.getContainingType());
168 30 : Name = formatv("{0} {1}::*", Pointee, Class);
169 : } else {
170 814 : Name.append(Types.getTypeName(Ptr.getReferentType()));
171 :
172 814 : if (Ptr.getMode() == PointerMode::LValueReference)
173 : Name.append("&");
174 354 : else if (Ptr.getMode() == PointerMode::RValueReference)
175 : Name.append("&&");
176 347 : 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 814 : if (Ptr.isConst())
182 : Name.append(" const");
183 814 : if (Ptr.isVolatile())
184 : Name.append(" volatile");
185 814 : if (Ptr.isUnaligned())
186 : Name.append(" __unaligned");
187 814 : if (Ptr.isRestrict())
188 : Name.append(" __restrict");
189 : }
190 422 : return Error::success();
191 : }
192 :
193 82 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
194 82 : uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
195 :
196 82 : if (Mods & uint16_t(ModifierOptions::Const))
197 : Name.append("const ");
198 82 : if (Mods & uint16_t(ModifierOptions::Volatile))
199 : Name.append("volatile ");
200 82 : if (Mods & uint16_t(ModifierOptions::Unaligned))
201 : Name.append("__unaligned ");
202 164 : Name.append(Types.getTypeName(Mod.getModifiedType()));
203 82 : return Error::success();
204 : }
205 :
206 18 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
207 : VFTableShapeRecord &Shape) {
208 18 : Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
209 18 : return Error::success();
210 : }
211 :
212 0 : Error TypeNameComputer::visitKnownRecord(
213 : CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
214 0 : return Error::success();
215 : }
216 :
217 0 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
218 : UdtSourceLineRecord &SourceLine) {
219 0 : return Error::success();
220 : }
221 :
222 7 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
223 7 : return Error::success();
224 : }
225 :
226 87 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
227 : MethodOverloadListRecord &Overloads) {
228 87 : return Error::success();
229 : }
230 :
231 92 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
232 92 : return Error::success();
233 : }
234 :
235 0 : Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
236 0 : return Error::success();
237 : }
238 :
239 0 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
240 : PrecompRecord &Precomp) {
241 0 : return Error::success();
242 : }
243 :
244 0 : Error TypeNameComputer::visitKnownRecord(CVType &CVR,
245 : EndPrecompRecord &EndPrecomp) {
246 0 : return Error::success();
247 : }
248 :
249 3559 : std::string llvm::codeview::computeTypeName(TypeCollection &Types,
250 : TypeIndex Index) {
251 : TypeNameComputer Computer(Types);
252 3559 : CVType Record = Types.getType(Index);
253 7118 : if (auto EC = visitTypeRecord(Record, Index, Computer)) {
254 0 : consumeError(std::move(EC));
255 0 : return "<unknown UDT>";
256 : }
257 : return Computer.name();
258 : }
259 :
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 :
318 394 : StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
319 394 : 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 0 : 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 0 : cantFail(Mapping.visitSymbolBegin(Sym));
327 0 : cantFail(Mapping.visitKnownRecord(Sym, Const));
328 0 : cantFail(Mapping.visitSymbolEnd(Sym));
329 0 : return Const.Name;
330 : }
331 :
332 : int Offset = getSymbolNameOffset(Sym);
333 394 : if (Offset == -1)
334 0 : return StringRef();
335 :
336 788 : StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
337 394 : return StringData.split('\0').first;
338 : }
|