1 //===-- PdbUtil.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 "PdbUtil.h"
11 
12 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
14 
15 #include "lldb/Utility/LLDBAssert.h"
16 
17 #include "lldb/lldb-enumerations.h"
18 
19 using namespace lldb_private;
20 using namespace lldb_private::npdb;
21 using namespace llvm::codeview;
22 using namespace llvm::pdb;
23 
24 PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
25   switch (kind) {
26   case S_COMPILE3:
27   case S_OBJNAME:
28     return PDB_SymType::CompilandDetails;
29   case S_ENVBLOCK:
30     return PDB_SymType::CompilandEnv;
31   case S_THUNK32:
32   case S_TRAMPOLINE:
33     return PDB_SymType::Thunk;
34   case S_COFFGROUP:
35     return PDB_SymType::CoffGroup;
36   case S_EXPORT:
37     return PDB_SymType::Export;
38   case S_LPROC32:
39   case S_GPROC32:
40   case S_LPROC32_DPC:
41     return PDB_SymType::Function;
42   case S_PUB32:
43     return PDB_SymType::PublicSymbol;
44   case S_INLINESITE:
45     return PDB_SymType::InlineSite;
46   case S_LOCAL:
47   case S_BPREL32:
48   case S_REGREL32:
49   case S_MANCONSTANT:
50   case S_CONSTANT:
51   case S_LDATA32:
52   case S_GDATA32:
53   case S_LMANDATA:
54   case S_GMANDATA:
55   case S_LTHREAD32:
56   case S_GTHREAD32:
57     return PDB_SymType::Data;
58   case S_BLOCK32:
59     return PDB_SymType::Block;
60   case S_LABEL32:
61     return PDB_SymType::Label;
62   case S_CALLSITEINFO:
63     return PDB_SymType::CallSite;
64   case S_HEAPALLOCSITE:
65     return PDB_SymType::HeapAllocationSite;
66   case S_CALLEES:
67     return PDB_SymType::Callee;
68   case S_CALLERS:
69     return PDB_SymType::Caller;
70   default:
71     lldbassert(false && "Invalid symbol record kind!");
72   }
73   return PDB_SymType::None;
74 }
75 
76 PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {
77   switch (kind) {
78   case LF_ARRAY:
79     return PDB_SymType::ArrayType;
80   case LF_ARGLIST:
81     return PDB_SymType::FunctionSig;
82   case LF_BCLASS:
83     return PDB_SymType::BaseClass;
84   case LF_BINTERFACE:
85     return PDB_SymType::BaseInterface;
86   case LF_CLASS:
87   case LF_STRUCTURE:
88   case LF_INTERFACE:
89   case LF_UNION:
90     return PDB_SymType::UDT;
91   case LF_POINTER:
92     return PDB_SymType::PointerType;
93   case LF_ENUM:
94     return PDB_SymType::Enum;
95   default:
96     lldbassert(false && "Invalid type record kind!");
97   }
98   return PDB_SymType::None;
99 }
100 
101 bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
102   switch (sym.kind()) {
103   case S_GPROC32:
104   case S_LPROC32:
105   case S_GPROC32_ID:
106   case S_LPROC32_ID:
107   case S_LPROC32_DPC:
108   case S_LPROC32_DPC_ID:
109   case S_THUNK32:
110   case S_TRAMPOLINE:
111   case S_COFFGROUP:
112   case S_BLOCK32:
113   case S_LABEL32:
114   case S_CALLSITEINFO:
115   case S_HEAPALLOCSITE:
116   case S_LDATA32:
117   case S_GDATA32:
118   case S_LMANDATA:
119   case S_GMANDATA:
120   case S_LTHREAD32:
121   case S_GTHREAD32:
122     return true;
123   default:
124     return false;
125   }
126 }
127 
128 bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
129   switch (sym.kind()) {
130   case S_GPROC32:
131   case S_LPROC32:
132   case S_GPROC32_ID:
133   case S_LPROC32_ID:
134   case S_LPROC32_DPC:
135   case S_LPROC32_DPC_ID:
136   case S_THUNK32:
137   case S_TRAMPOLINE:
138   case S_COFFGROUP:
139   case S_BLOCK32:
140     return true;
141   default:
142     return false;
143   }
144 }
145 
146 template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
147   RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
148   cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
149   return record;
150 }
151 
152 template <typename RecordT>
153 static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
154   RecordT record = createRecord<RecordT>(sym);
155   return {record.Segment, record.CodeOffset};
156 }
157 
158 template <>
159 SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
160   TrampolineSym record = createRecord<TrampolineSym>(sym);
161   return {record.ThunkSection, record.ThunkOffset};
162 }
163 
164 template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
165   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
166   return {record.Segment, record.Offset};
167 }
168 
169 template <>
170 SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
171   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
172   return {record.Segment, record.Offset};
173 }
174 
175 template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
176   DataSym record = createRecord<DataSym>(sym);
177   return {record.Segment, record.DataOffset};
178 }
179 
180 template <>
181 SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
182   ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
183   return {record.Segment, record.DataOffset};
184 }
185 
186 SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
187   switch (sym.kind()) {
188   case S_GPROC32:
189   case S_LPROC32:
190   case S_GPROC32_ID:
191   case S_LPROC32_ID:
192   case S_LPROC32_DPC:
193   case S_LPROC32_DPC_ID:
194     return ::GetSegmentAndOffset<ProcSym>(sym);
195   case S_THUNK32:
196     return ::GetSegmentAndOffset<Thunk32Sym>(sym);
197     break;
198   case S_TRAMPOLINE:
199     return ::GetSegmentAndOffset<TrampolineSym>(sym);
200     break;
201   case S_COFFGROUP:
202     return ::GetSegmentAndOffset<CoffGroupSym>(sym);
203     break;
204   case S_BLOCK32:
205     return ::GetSegmentAndOffset<BlockSym>(sym);
206     break;
207   case S_LABEL32:
208     return ::GetSegmentAndOffset<LabelSym>(sym);
209     break;
210   case S_CALLSITEINFO:
211     return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
212     break;
213   case S_HEAPALLOCSITE:
214     return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
215     break;
216   case S_LDATA32:
217   case S_GDATA32:
218   case S_LMANDATA:
219   case S_GMANDATA:
220     return ::GetSegmentAndOffset<DataSym>(sym);
221     break;
222   case S_LTHREAD32:
223   case S_GTHREAD32:
224     return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
225     break;
226   default:
227     lldbassert(false && "Record does not have a segment/offset!");
228   }
229   return {0, 0};
230 }
231 
232 template <typename RecordT>
233 SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
234   RecordT record = createRecord<RecordT>(sym);
235   return {record.Segment, record.CodeOffset, record.CodeSize};
236 }
237 
238 template <>
239 SegmentOffsetLength
240 GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
241   TrampolineSym record = createRecord<TrampolineSym>(sym);
242   return {record.ThunkSection, record.ThunkOffset, record.Size};
243 }
244 
245 template <>
246 SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
247   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
248   return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
249 }
250 
251 template <>
252 SegmentOffsetLength
253 GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
254   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
255   return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
256 }
257 
258 SegmentOffsetLength
259 lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
260   switch (sym.kind()) {
261   case S_GPROC32:
262   case S_LPROC32:
263   case S_GPROC32_ID:
264   case S_LPROC32_ID:
265   case S_LPROC32_DPC:
266   case S_LPROC32_DPC_ID:
267     return ::GetSegmentOffsetAndLength<ProcSym>(sym);
268   case S_THUNK32:
269     return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
270     break;
271   case S_TRAMPOLINE:
272     return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
273     break;
274   case S_COFFGROUP:
275     return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
276     break;
277   case S_BLOCK32:
278     return ::GetSegmentOffsetAndLength<BlockSym>(sym);
279     break;
280   default:
281     lldbassert(false && "Record does not have a segment/offset/length triple!");
282   }
283   return {0, 0, 0};
284 }
285 
286 bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
287   ClassRecord cr;
288   UnionRecord ur;
289   EnumRecord er;
290   switch (cvt.kind()) {
291   case LF_CLASS:
292   case LF_STRUCTURE:
293   case LF_INTERFACE:
294     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
295     return cr.isForwardRef();
296   case LF_UNION:
297     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
298     return ur.isForwardRef();
299   case LF_ENUM:
300     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
301     return er.isForwardRef();
302   default:
303     return false;
304   }
305 }
306 
307 lldb::AccessType
308 lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
309   switch (access) {
310   case MemberAccess::Private:
311     return lldb::eAccessPrivate;
312   case MemberAccess::Protected:
313     return lldb::eAccessProtected;
314   case MemberAccess::Public:
315     return lldb::eAccessPublic;
316   case MemberAccess::None:
317     return lldb::eAccessNone;
318   }
319   llvm_unreachable("unreachable");
320 }
321 
322 TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
323   switch (cvt.kind()) {
324   case LF_CLASS:
325   case LF_STRUCTURE:
326   case LF_INTERFACE: {
327     ClassRecord cr;
328     cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
329     return cr.FieldList;
330   }
331   case LF_UNION: {
332     UnionRecord ur;
333     cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
334     return ur.FieldList;
335   }
336   case LF_ENUM: {
337     EnumRecord er;
338     cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
339     return er.FieldList;
340   }
341   default:
342     llvm_unreachable("Unreachable!");
343   }
344 }
345 
346 llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
347   // Not all PDB names can be parsed with CPlusPlusNameParser.
348   // E.g. it fails on names containing `anonymous namespace'.
349   // So we simply drop everything before '::'
350 
351   auto offset = name.rfind("::");
352   if (offset == llvm::StringRef::npos)
353     return name;
354   assert(offset + 2 <= name.size());
355 
356   return name.substr(offset + 2);
357 }