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 }