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