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