SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { auto Iter = GlobalOffsetToSymbolId.find(Offset); if (Iter != GlobalOffsetToSymbolId.end()) return Iter->second; SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); CVSymbol CVS = SS.readRecord(Offset); SymIndexId Id = 0; switch (CVS.kind()) { case SymbolKind::S_UDT: { UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); Id = createSymbol<NativeTypeTypedef>(std::move(US)); break; } default: Id = createSymbolPlaceholder(); break; } if (Id != 0) { assert(GlobalOffsetToSymbolId.count(Offset) == 0); GlobalOffsetToSymbolId[Offset] = Id; } return Id; }
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { Symbols.push_back(Symbol); // Symbols written to a PDB file are required to be 4 byte aligned. The same // is not true of object files. assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 && "Invalid Symbol alignment!"); SymbolByteSize += Symbol.length(); }
bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) { switch (sym.kind()) { case S_GPROC32: case S_LPROC32: case S_GPROC32_ID: case S_LPROC32_ID: case S_LPROC32_DPC: case S_LPROC32_DPC_ID: case S_THUNK32: case S_TRAMPOLINE: case S_COFFGROUP: case S_BLOCK32: case S_LABEL32: case S_CALLSITEINFO: case S_HEAPALLOCSITE: case S_LDATA32: case S_GDATA32: case S_LMANDATA: case S_GMANDATA: case S_LTHREAD32: case S_GTHREAD32: return true; default: return false; } }
SegmentOffsetLength lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) { switch (sym.kind()) { case S_GPROC32: case S_LPROC32: case S_GPROC32_ID: case S_LPROC32_ID: case S_LPROC32_DPC: case S_LPROC32_DPC_ID: return ::GetSegmentOffsetAndLength<ProcSym>(sym); case S_THUNK32: return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym); break; case S_TRAMPOLINE: return ::GetSegmentOffsetAndLength<TrampolineSym>(sym); break; case S_COFFGROUP: return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym); break; case S_BLOCK32: return ::GetSegmentOffsetAndLength<BlockSym>(sym); break; default: lldbassert(false && "Record does not have a segment/offset/length triple!"); } return {0, 0, 0}; }
Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) { if (RecordBytes) { AutoIndent Indent(P, 7); P.formatBinary("bytes", Record.content(), 0); } P.Unindent(); return Error::success(); }
Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) { if (PrintRecordBytes && ObjDelegate) ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content()); W.unindent(); W.startLine() << "}\n"; return Error::success(); }
void addSymbol(const CVSymbol &Symbol) { if (Symbol.kind() == S_UDT) { auto Iter = UdtHashes.insert(Symbol); if (!Iter.second) return; } Records.push_back(Symbol); }
VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) { VariableInfo result; if (sym.kind() == S_REGREL32) { RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); result.type = reg.Type; result.name = reg.Name; return result; } if (sym.kind() == S_REGISTER) { RegisterSym reg(SymbolRecordKind::RegisterSym); cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); result.type = reg.Index; result.name = reg.Name; return result; } if (sym.kind() == S_LOCAL) { LocalSym local(SymbolRecordKind::LocalSym); cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); result.type = local.Type; result.name = local.Name; return result; } if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) { DataSym data(SymbolRecordKind::DataSym); cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data)); result.type = data.Type; result.name = data.Name; return result; } if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) { ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym); cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data)); result.type = data.Type; result.name = data.Name; return result; } if (sym.kind() == S_CONSTANT) { ConstantSym constant(SymbolRecordKind::ConstantSym); cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant)); result.type = constant.Type; result.name = constant.Name; return result; } lldbassert(false && "Invalid variable record kind!"); return {}; }
static inline Expected<CodeViewYAML::SymbolRecord> fromCodeViewSymbolImpl(CVSymbol Symbol) { CodeViewYAML::SymbolRecord Result; auto Impl = std::make_shared<SymbolType>(Symbol.kind()); if (auto EC = Impl->fromCodeViewSymbol(Symbol)) return std::move(EC); Result.Symbol = Impl; return Result; }
static int getSymbolNameOffset(CVSymbol Sym) { switch (Sym.kind()) { // See ProcSym case SymbolKind::S_GPROC32: case SymbolKind::S_LPROC32: case SymbolKind::S_GPROC32_ID: case SymbolKind::S_LPROC32_ID: case SymbolKind::S_LPROC32_DPC: case SymbolKind::S_LPROC32_DPC_ID: return 35; // See Thunk32Sym case SymbolKind::S_THUNK32: return 21; // See SectionSym case SymbolKind::S_SECTION: return 16; // See CoffGroupSym case SymbolKind::S_COFFGROUP: return 14; // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym case SymbolKind::S_PUB32: case SymbolKind::S_FILESTATIC: case SymbolKind::S_REGREL32: case SymbolKind::S_GDATA32: case SymbolKind::S_LDATA32: case SymbolKind::S_LMANDATA: case SymbolKind::S_GMANDATA: case SymbolKind::S_LTHREAD32: case SymbolKind::S_GTHREAD32: case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: return 10; // See RegisterSym and LocalSym case SymbolKind::S_REGISTER: case SymbolKind::S_LOCAL: return 6; // See BlockSym case SymbolKind::S_BLOCK32: return 18; // See LabelSym case SymbolKind::S_LABEL32: return 7; // See ObjNameSym, ExportSym, and UDTSym case SymbolKind::S_OBJNAME: case SymbolKind::S_EXPORT: case SymbolKind::S_UDT: return 4; // See BPRelativeSym case SymbolKind::S_BPREL32: return 8; default: return -1; } }
StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { if (Sym.kind() == SymbolKind::S_CONSTANT) { // S_CONSTANT is preceded by an APSInt, which has a variable length. So we // have to do a full deserialization. BinaryStreamReader Reader(Sym.content(), llvm::support::little); // The container doesn't matter for single records. SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); ConstantSym Const(SymbolKind::S_CONSTANT); cantFail(Mapping.visitSymbolBegin(Sym)); cantFail(Mapping.visitKnownRecord(Sym, Const)); cantFail(Mapping.visitSymbolEnd(Sym)); return Const.Name; } int Offset = getSymbolNameOffset(Sym); if (Offset == -1) return StringRef(); StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); return StringData.split('\0').first; }
Expected<CodeViewYAML::SymbolRecord> CodeViewYAML::SymbolRecord::fromCodeViewSymbol(CVSymbol Symbol) { #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ case EnumName: \ return fromCodeViewSymbolImpl<SymbolRecordImpl<ClassName>>(Symbol); #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \ SYMBOL_RECORD(EnumName, EnumVal, ClassName) switch (Symbol.kind()) { #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" default: return fromCodeViewSymbolImpl<UnknownSymbolRecord>(Symbol); } return make_error<CodeViewError>(cv_error_code::corrupt_record); }
bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) { switch (sym.kind()) { case S_GPROC32: case S_LPROC32: case S_GPROC32_ID: case S_LPROC32_ID: case S_LPROC32_DPC: case S_LPROC32_DPC_ID: case S_THUNK32: case S_TRAMPOLINE: case S_COFFGROUP: case S_BLOCK32: return true; default: return false; } }
SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) { switch (sym.kind()) { case S_GPROC32: case S_LPROC32: case S_GPROC32_ID: case S_LPROC32_ID: case S_LPROC32_DPC: case S_LPROC32_DPC_ID: return ::GetSegmentAndOffset<ProcSym>(sym); case S_THUNK32: return ::GetSegmentAndOffset<Thunk32Sym>(sym); break; case S_TRAMPOLINE: return ::GetSegmentAndOffset<TrampolineSym>(sym); break; case S_COFFGROUP: return ::GetSegmentAndOffset<CoffGroupSym>(sym); break; case S_BLOCK32: return ::GetSegmentAndOffset<BlockSym>(sym); break; case S_LABEL32: return ::GetSegmentAndOffset<LabelSym>(sym); break; case S_CALLSITEINFO: return ::GetSegmentAndOffset<CallSiteInfoSym>(sym); break; case S_HEAPALLOCSITE: return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym); break; case S_LDATA32: case S_GDATA32: case S_LMANDATA: case S_GMANDATA: return ::GetSegmentAndOffset<DataSym>(sym); break; case S_LTHREAD32: case S_GTHREAD32: return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym); break; default: lldbassert(false && "Record does not have a segment/offset!"); } return {0, 0}; }
/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. /// The object file may not be aligned. static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym, BumpPtrAllocator &Alloc) { size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); assert(Size >= 4 && "record too short"); assert(Size <= MaxRecordLength && "record too long"); void *Mem = Alloc.Allocate(Size, 4); // Copy the symbol record and zero out any padding bytes. MutableArrayRef<uint8_t> NewData(reinterpret_cast<uint8_t *>(Mem), Size); memcpy(NewData.data(), Sym.data().data(), Sym.length()); memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); // Update the record prefix length. It should point to the beginning of the // next record. MSVC does some canonicalization of the record kind, so we do // that as well. auto *Prefix = reinterpret_cast<RecordPrefix *>(Mem); Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind()); Prefix->RecordLen = Size - 2; return NewData; }
bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) { SymbolKind K = Sym.kind(); return ::discoverTypeIndices(Sym.content(), K, Refs); }
Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { W.printNumber("Length", CVR.length()); return Error::success(); }
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); for (auto FuncID : Caller.Indices) printTypeIndex("FuncID", FuncID); return Error::success(); }
Error fromCodeViewSymbol(CVSymbol CVS) override { this->Kind = CVS.kind(); Data = CVS.RecordData.drop_front(sizeof(RecordPrefix)); return Error::success(); }
template <typename RecordT> RecordT createRecord(const CVSymbol &sym) { RecordT record(static_cast<SymbolRecordKind>(sym.kind())); cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record)); return record; }
VariableInfo lldb_private::npdb::GetVariableLocationInfo( PdbIndex &index, PdbCompilandSymId var_id, Block &block, lldb::ModuleSP module) { CVSymbol sym = index.ReadSymbolRecord(var_id); VariableInfo result = GetVariableNameInfo(sym); if (sym.kind() == S_REGREL32) { RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); result.location = MakeRegRelLocationExpression(reg.Register, reg.Offset, module); result.ranges.emplace(); return result; } if (sym.kind() == S_REGISTER) { RegisterSym reg(SymbolRecordKind::RegisterSym); cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); result.location = MakeEnregisteredLocationExpression(reg.Register, module); result.ranges.emplace(); return result; } if (sym.kind() == S_LOCAL) { LocalSym local(SymbolRecordKind::LocalSym); cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); PdbCompilandSymId loc_specifier_id(var_id.modi, var_id.offset + sym.RecordData.size()); CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { DefRangeFramePointerRelSym loc( SymbolRecordKind::DefRangeFramePointerRelSym); cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( loc_specifier_cvs, loc)); Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps); // TODO: may be better to pass function scope and not lookup it every // time? find nearest parent function block Block *cur = █ while (cur->GetParent()) { cur = cur->GetParent(); } PdbCompilandSymId func_scope_id = PdbSymUid(cur->GetID()).asCompilandSym(); CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id); lldbassert(func_block_cvs.kind() == S_GPROC32 || func_block_cvs.kind() == S_LPROC32); PdbCompilandSymId frame_proc_id( func_scope_id.modi, func_scope_id.offset + func_block_cvs.length()); bool is_parameter = ((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None); RegisterId base_reg = GetBaseFrameRegister(index, frame_proc_id, is_parameter); if (base_reg == RegisterId::VFRAME) { llvm::StringRef program; if (GetFrameDataProgram(index, ranges, program)) { result.location = MakeVFrameRelLocationExpression(program, loc.Offset, module); result.ranges = std::move(ranges); } else { // invalid variable } } else { result.location = MakeRegRelLocationExpression(base_reg, loc.Offset, module); result.ranges = std::move(ranges); } } else if (loc_specifier_cvs.kind() == S_DEFRANGE_REGISTER_REL) { DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym); cantFail(SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>( loc_specifier_cvs, loc)); Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps); RegisterId base_reg = (RegisterId)(uint16_t)loc.Hdr.Register; if (base_reg == RegisterId::VFRAME) { llvm::StringRef program; if (GetFrameDataProgram(index, ranges, program)) { result.location = MakeVFrameRelLocationExpression( program, loc.Hdr.BasePointerOffset, module); result.ranges = std::move(ranges); } else { // invalid variable } } else { result.location = MakeRegRelLocationExpression( base_reg, loc.Hdr.BasePointerOffset, module); result.ranges = std::move(ranges); } } // FIXME: Handle other kinds return result; } llvm_unreachable("Symbol is not a local variable!"); return result; }