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 
14 #include "lldb/Utility/LLDBAssert.h"
15 
16 using namespace lldb_private;
17 using namespace lldb_private::npdb;
18 using namespace llvm::codeview;
19 using namespace llvm::pdb;
20 
21 llvm::pdb::PDB_SymType
22 lldb_private::npdb::CVSymToPDBSym(llvm::codeview::SymbolKind kind) {
23   switch (kind) {
24   case S_COMPILE3:
25   case S_OBJNAME:
26     return PDB_SymType::CompilandDetails;
27   case S_ENVBLOCK:
28     return PDB_SymType::CompilandEnv;
29   case S_THUNK32:
30   case S_TRAMPOLINE:
31     return PDB_SymType::Thunk;
32   case S_COFFGROUP:
33     return PDB_SymType::CoffGroup;
34   case S_EXPORT:
35     return PDB_SymType::Export;
36   case S_LPROC32:
37   case S_GPROC32:
38   case S_LPROC32_DPC:
39     return PDB_SymType::Function;
40   case S_PUB32:
41     return PDB_SymType::PublicSymbol;
42   case S_INLINESITE:
43     return PDB_SymType::InlineSite;
44   case S_LOCAL:
45   case S_BPREL32:
46   case S_REGREL32:
47   case S_MANCONSTANT:
48   case S_CONSTANT:
49   case S_LDATA32:
50   case S_GDATA32:
51   case S_LMANDATA:
52   case S_GMANDATA:
53   case S_LTHREAD32:
54   case S_GTHREAD32:
55     return PDB_SymType::Data;
56   case S_BLOCK32:
57     return PDB_SymType::Block;
58   case S_LABEL32:
59     return PDB_SymType::Label;
60   case S_CALLSITEINFO:
61     return PDB_SymType::CallSite;
62   case S_HEAPALLOCSITE:
63     return PDB_SymType::HeapAllocationSite;
64   case S_CALLEES:
65     return PDB_SymType::Callee;
66   case S_CALLERS:
67     return PDB_SymType::Caller;
68   default:
69     lldbassert(false && "Invalid symbol record kind!");
70   }
71   return PDB_SymType::None;
72 }
73 
74 bool lldb_private::npdb::SymbolHasAddress(const llvm::codeview::CVSymbol &sym) {
75   switch (sym.kind()) {
76   case S_GPROC32:
77   case S_LPROC32:
78   case S_GPROC32_ID:
79   case S_LPROC32_ID:
80   case S_LPROC32_DPC:
81   case S_LPROC32_DPC_ID:
82   case S_THUNK32:
83   case S_TRAMPOLINE:
84   case S_COFFGROUP:
85   case S_BLOCK32:
86   case S_LABEL32:
87   case S_CALLSITEINFO:
88   case S_HEAPALLOCSITE:
89   case S_LDATA32:
90   case S_GDATA32:
91   case S_LMANDATA:
92   case S_GMANDATA:
93   case S_LTHREAD32:
94   case S_GTHREAD32:
95     return true;
96   default:
97     return false;
98   }
99 }
100 
101 bool lldb_private::npdb::SymbolIsCode(const llvm::codeview::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     return true;
114   default:
115     return false;
116   }
117 }
118 
119 template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
120   RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
121   cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
122   return record;
123 }
124 
125 template <typename RecordT>
126 static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
127   RecordT record = createRecord<RecordT>(sym);
128   return {record.Segment, record.CodeOffset};
129 }
130 
131 template <>
132 SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
133   TrampolineSym record = createRecord<TrampolineSym>(sym);
134   return {record.ThunkSection, record.ThunkOffset};
135 }
136 
137 template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
138   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
139   return {record.Segment, record.Offset};
140 }
141 
142 template <>
143 SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
144   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
145   return {record.Segment, record.Offset};
146 }
147 
148 template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
149   DataSym record = createRecord<DataSym>(sym);
150   return {record.Segment, record.DataOffset};
151 }
152 
153 template <>
154 SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
155   ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
156   return {record.Segment, record.DataOffset};
157 }
158 
159 SegmentOffset
160 lldb_private::npdb::GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym) {
161   switch (sym.kind()) {
162   case S_GPROC32:
163   case S_LPROC32:
164   case S_GPROC32_ID:
165   case S_LPROC32_ID:
166   case S_LPROC32_DPC:
167   case S_LPROC32_DPC_ID:
168     return ::GetSegmentAndOffset<ProcSym>(sym);
169   case S_THUNK32:
170     return ::GetSegmentAndOffset<Thunk32Sym>(sym);
171     break;
172   case S_TRAMPOLINE:
173     return ::GetSegmentAndOffset<TrampolineSym>(sym);
174     break;
175   case S_COFFGROUP:
176     return ::GetSegmentAndOffset<CoffGroupSym>(sym);
177     break;
178   case S_BLOCK32:
179     return ::GetSegmentAndOffset<BlockSym>(sym);
180     break;
181   case S_LABEL32:
182     return ::GetSegmentAndOffset<LabelSym>(sym);
183     break;
184   case S_CALLSITEINFO:
185     return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
186     break;
187   case S_HEAPALLOCSITE:
188     return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
189     break;
190   case S_LDATA32:
191   case S_GDATA32:
192   case S_LMANDATA:
193   case S_GMANDATA:
194     return ::GetSegmentAndOffset<DataSym>(sym);
195     break;
196   case S_LTHREAD32:
197   case S_GTHREAD32:
198     return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
199     break;
200   default:
201     lldbassert(false && "Record does not have a segment/offset!");
202   }
203   return {0, 0};
204 }
205 
206 template <typename RecordT>
207 SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
208   RecordT record = createRecord<RecordT>(sym);
209   return {record.Segment, record.CodeOffset, record.CodeSize};
210 }
211 
212 template <>
213 SegmentOffsetLength
214 GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
215   TrampolineSym record = createRecord<TrampolineSym>(sym);
216   return {record.ThunkSection, record.ThunkOffset, record.Size};
217 }
218 
219 template <>
220 SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
221   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
222   return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
223 }
224 
225 template <>
226 SegmentOffsetLength
227 GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
228   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
229   return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
230 }
231 
232 SegmentOffsetLength lldb_private::npdb::GetSegmentOffsetAndLength(
233     const llvm::codeview::CVSymbol &sym) {
234   switch (sym.kind()) {
235   case S_GPROC32:
236   case S_LPROC32:
237   case S_GPROC32_ID:
238   case S_LPROC32_ID:
239   case S_LPROC32_DPC:
240   case S_LPROC32_DPC_ID:
241     return ::GetSegmentOffsetAndLength<ProcSym>(sym);
242   case S_THUNK32:
243     return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
244     break;
245   case S_TRAMPOLINE:
246     return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
247     break;
248   case S_COFFGROUP:
249     return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
250     break;
251   case S_BLOCK32:
252     return ::GetSegmentOffsetAndLength<BlockSym>(sym);
253     break;
254   default:
255     lldbassert(false && "Record does not have a segment/offset/length triple!");
256   }
257   return {0, 0, 0};
258 }
259