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