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