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   case LF_PROCEDURE:
96     return PDB_SymType::FunctionSig;
97   default:
98     lldbassert(false && "Invalid type record kind!");
99   }
100   return PDB_SymType::None;
101 }
102 
103 bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
104   switch (sym.kind()) {
105   case S_GPROC32:
106   case S_LPROC32:
107   case S_GPROC32_ID:
108   case S_LPROC32_ID:
109   case S_LPROC32_DPC:
110   case S_LPROC32_DPC_ID:
111   case S_THUNK32:
112   case S_TRAMPOLINE:
113   case S_COFFGROUP:
114   case S_BLOCK32:
115   case S_LABEL32:
116   case S_CALLSITEINFO:
117   case S_HEAPALLOCSITE:
118   case S_LDATA32:
119   case S_GDATA32:
120   case S_LMANDATA:
121   case S_GMANDATA:
122   case S_LTHREAD32:
123   case S_GTHREAD32:
124     return true;
125   default:
126     return false;
127   }
128 }
129 
130 bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
131   switch (sym.kind()) {
132   case S_GPROC32:
133   case S_LPROC32:
134   case S_GPROC32_ID:
135   case S_LPROC32_ID:
136   case S_LPROC32_DPC:
137   case S_LPROC32_DPC_ID:
138   case S_THUNK32:
139   case S_TRAMPOLINE:
140   case S_COFFGROUP:
141   case S_BLOCK32:
142     return true;
143   default:
144     return false;
145   }
146 }
147 
148 template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
149   RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
150   cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
151   return record;
152 }
153 
154 template <typename RecordT>
155 static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
156   RecordT record = createRecord<RecordT>(sym);
157   return {record.Segment, record.CodeOffset};
158 }
159 
160 template <>
161 SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
162   TrampolineSym record = createRecord<TrampolineSym>(sym);
163   return {record.ThunkSection, record.ThunkOffset};
164 }
165 
166 template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
167   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
168   return {record.Segment, record.Offset};
169 }
170 
171 template <>
172 SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
173   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
174   return {record.Segment, record.Offset};
175 }
176 
177 template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
178   DataSym record = createRecord<DataSym>(sym);
179   return {record.Segment, record.DataOffset};
180 }
181 
182 template <>
183 SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
184   ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
185   return {record.Segment, record.DataOffset};
186 }
187 
188 SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
189   switch (sym.kind()) {
190   case S_GPROC32:
191   case S_LPROC32:
192   case S_GPROC32_ID:
193   case S_LPROC32_ID:
194   case S_LPROC32_DPC:
195   case S_LPROC32_DPC_ID:
196     return ::GetSegmentAndOffset<ProcSym>(sym);
197   case S_THUNK32:
198     return ::GetSegmentAndOffset<Thunk32Sym>(sym);
199     break;
200   case S_TRAMPOLINE:
201     return ::GetSegmentAndOffset<TrampolineSym>(sym);
202     break;
203   case S_COFFGROUP:
204     return ::GetSegmentAndOffset<CoffGroupSym>(sym);
205     break;
206   case S_BLOCK32:
207     return ::GetSegmentAndOffset<BlockSym>(sym);
208     break;
209   case S_LABEL32:
210     return ::GetSegmentAndOffset<LabelSym>(sym);
211     break;
212   case S_CALLSITEINFO:
213     return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
214     break;
215   case S_HEAPALLOCSITE:
216     return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
217     break;
218   case S_LDATA32:
219   case S_GDATA32:
220   case S_LMANDATA:
221   case S_GMANDATA:
222     return ::GetSegmentAndOffset<DataSym>(sym);
223     break;
224   case S_LTHREAD32:
225   case S_GTHREAD32:
226     return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
227     break;
228   default:
229     lldbassert(false && "Record does not have a segment/offset!");
230   }
231   return {0, 0};
232 }
233 
234 template <typename RecordT>
235 SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
236   RecordT record = createRecord<RecordT>(sym);
237   return {record.Segment, record.CodeOffset, record.CodeSize};
238 }
239 
240 template <>
241 SegmentOffsetLength
242 GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
243   TrampolineSym record = createRecord<TrampolineSym>(sym);
244   return {record.ThunkSection, record.ThunkOffset, record.Size};
245 }
246 
247 template <>
248 SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
249   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
250   return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
251 }
252 
253 template <>
254 SegmentOffsetLength
255 GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
256   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
257   return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
258 }
259 
260 SegmentOffsetLength
261 lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
262   switch (sym.kind()) {
263   case S_GPROC32:
264   case S_LPROC32:
265   case S_GPROC32_ID:
266   case S_LPROC32_ID:
267   case S_LPROC32_DPC:
268   case S_LPROC32_DPC_ID:
269     return ::GetSegmentOffsetAndLength<ProcSym>(sym);
270   case S_THUNK32:
271     return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
272     break;
273   case S_TRAMPOLINE:
274     return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
275     break;
276   case S_COFFGROUP:
277     return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
278     break;
279   case S_BLOCK32:
280     return ::GetSegmentOffsetAndLength<BlockSym>(sym);
281     break;
282   default:
283     lldbassert(false && "Record does not have a segment/offset/length triple!");
284   }
285   return {0, 0, 0};
286 }
287 
288 bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
289   ClassRecord cr;
290   UnionRecord ur;
291   EnumRecord er;
292   switch (cvt.kind()) {
293   case LF_CLASS:
294   case LF_STRUCTURE:
295   case LF_INTERFACE:
296     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
297     return cr.isForwardRef();
298   case LF_UNION:
299     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
300     return ur.isForwardRef();
301   case LF_ENUM:
302     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
303     return er.isForwardRef();
304   default:
305     return false;
306   }
307 }
308 
309 lldb::AccessType
310 lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
311   switch (access) {
312   case MemberAccess::Private:
313     return lldb::eAccessPrivate;
314   case MemberAccess::Protected:
315     return lldb::eAccessProtected;
316   case MemberAccess::Public:
317     return lldb::eAccessPublic;
318   case MemberAccess::None:
319     return lldb::eAccessNone;
320   }
321   llvm_unreachable("unreachable");
322 }
323 
324 TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
325   switch (cvt.kind()) {
326   case LF_CLASS:
327   case LF_STRUCTURE:
328   case LF_INTERFACE: {
329     ClassRecord cr;
330     cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
331     return cr.FieldList;
332   }
333   case LF_UNION: {
334     UnionRecord ur;
335     cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
336     return ur.FieldList;
337   }
338   case LF_ENUM: {
339     EnumRecord er;
340     cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
341     return er.FieldList;
342   }
343   default:
344     llvm_unreachable("Unreachable!");
345   }
346 }
347 
348 TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
349   lldbassert(modifier.kind() == LF_MODIFIER);
350   ModifierRecord mr;
351   llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
352   return mr.ModifiedType;
353 }
354 
355 llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
356   // Not all PDB names can be parsed with CPlusPlusNameParser.
357   // E.g. it fails on names containing `anonymous namespace'.
358   // So we simply drop everything before '::'
359 
360   auto offset = name.rfind("::");
361   if (offset == llvm::StringRef::npos)
362     return name;
363   assert(offset + 2 <= name.size());
364 
365   return name.substr(offset + 2);
366 }
367