Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
39644 views
//===-- PdbUtil.cpp -------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "PdbUtil.h"910#include "DWARFLocationExpression.h"11#include "PdbIndex.h"12#include "PdbSymUid.h"1314#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"15#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"16#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"17#include "llvm/DebugInfo/PDB/Native/DbiStream.h"18#include "llvm/DebugInfo/PDB/Native/TpiStream.h"1920#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"21#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"22#include "lldb/Symbol/Block.h"23#include "lldb/Utility/LLDBAssert.h"24#include "lldb/Utility/LLDBLog.h"25#include "lldb/lldb-enumerations.h"2627using namespace lldb_private;28using namespace lldb_private::npdb;29using namespace llvm::codeview;30using namespace llvm::pdb;3132// The returned range list is guaranteed to be sorted and no overlaps between33// adjacent ranges because fields in LocalVariableAddrGap are unsigned integers.34static Variable::RangeList35MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,36llvm::ArrayRef<LocalVariableAddrGap> gaps) {37lldb::addr_t start =38index.MakeVirtualAddress(range.ISectStart, range.OffsetStart);39if (start == LLDB_INVALID_ADDRESS)40return {};41lldb::addr_t end = start + range.Range;4243Variable::RangeList result;44while (!gaps.empty()) {45const LocalVariableAddrGap &gap = gaps.front();46lldb::addr_t gap_start = start + gap.GapStartOffset;47result.Append(start, gap_start - start);48start = gap_start + gap.Range;49gaps = gaps.drop_front();50}5152result.Append(start, end - start);53return result;54}5556namespace {57struct MemberLocations {58std::map<uint64_t, MemberValLocation> offset_to_location;59DWARFExpression expr;60bool is_dwarf = false;6162MemberLocations() = default;63MemberLocations(const DWARFExpression &expr) : expr(expr), is_dwarf(true) {}64MemberLocations(uint64_t offset, const MemberValLocation &member_loc) {65insert(offset, member_loc);66}6768void insert(uint64_t offset, const MemberValLocation &member_loc) {69offset_to_location[offset] = member_loc;70}7172struct Comparator {73public:74bool operator()(const MemberLocations &, const MemberLocations &) const {75return false;76}77};78};7980// A range map with address ranges to a map of pair of offset and locaitons.81typedef RangeDataVector<lldb::addr_t, lldb::addr_t, MemberLocations, 0,82MemberLocations::Comparator>83RangeMap;8485void AddMemberLocationRanges(RangeMap &location_map, uint64_t offset,86MemberValLocation member_loc,87const Variable::RangeList &ranges) {88RangeMap new_location_map;89auto add_overlap_region = [&](lldb::addr_t base, lldb::addr_t end,90RangeMap::Entry *entry) {91RangeMap::Entry overlap_region = {base, end - base, entry->data};92overlap_region.data.insert(offset, member_loc);93new_location_map.Append(overlap_region);94};9596for (const auto &range : ranges) {97lldb::addr_t base = range.GetRangeBase();98lldb::addr_t end = range.GetRangeEnd();99uint32_t base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);100while (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {101if (base >= end || entry->base >= end)102break;103if (entry->data.is_dwarf)104base = entry->GetRangeEnd();105else {106lldb::addr_t entry_end = entry->GetRangeEnd();107if (base > entry->base) {108if (end < entry_end)109new_location_map.Append({end, entry_end - end, entry->data});110add_overlap_region(base, end < entry_end ? end : entry_end, entry);111entry->SetRangeEnd(base);112} else if (base < entry->base) {113new_location_map.Append(114{base, entry->base - base, {offset, member_loc}});115if (entry_end == end)116entry->data.insert(offset, member_loc);117else {118add_overlap_region(entry->base, end, entry);119entry->ShrinkFront(end - entry->base);120}121} else {122if (end < entry_end) {123new_location_map.Append({end, entry_end, entry->data});124entry->SetRangeEnd(end);125}126entry->data.insert(offset, member_loc);127}128base = entry_end;129}130++base_idx;131}132if (base >= end)133continue;134new_location_map.Append({base, end - base, {offset, member_loc}});135}136for (const auto &entry : new_location_map)137location_map.Append(entry);138if (!new_location_map.IsEmpty())139location_map.Sort();140}141142void AddDwarfRange(RangeMap &location_map, const DWARFExpression &expr,143const Variable::RangeList &ranges) {144if (!expr.IsValid())145return;146RangeMap new_location_map;147for (const auto &range : ranges) {148lldb::addr_t base = range.GetRangeBase();149lldb::addr_t end = range.GetRangeEnd();150uint32_t base_idx = location_map.FindEntryIndexThatContains(base);151uint32_t end_idx = location_map.FindEntryIndexThatContains(end - 1);152// range is within an entry.153if (base_idx == end_idx && base_idx != UINT32_MAX) {154auto *entry = location_map.GetMutableEntryAtIndex(base_idx);155if (base > entry->base) {156new_location_map.Append({entry->base, base - entry->base, entry->data});157entry->ShrinkFront(base - entry->base);158}159if (end == entry->GetRangeEnd())160entry->data = expr;161else {162entry->ShrinkFront(end - base);163new_location_map.Append({base, end - base, expr});164}165continue;166}167base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);168if (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {169if (entry->Contains(base) && entry->base != base) {170entry->SetRangeEnd(base);171++base_idx;172}173}174end_idx = location_map.FindEntryIndexThatContainsOrFollows(end - 1);175if (auto *entry = location_map.GetMutableEntryAtIndex(end_idx)) {176if (entry->Contains(end - 1)) {177if (entry->GetRangeEnd() == end)178++end_idx;179else180entry->ShrinkFront(end - entry->base);181}182}183184if (end_idx == UINT32_MAX)185end_idx = location_map.GetSize();186// Erase existing ranges covered by new range.187location_map.Erase(base_idx, end_idx);188new_location_map.Append({base, end - base, expr});189}190191for (const auto &entry : new_location_map)192location_map.Append(entry);193location_map.Sort();194}195} // namespace196197CVTagRecord CVTagRecord::create(CVType type) {198assert(IsTagRecord(type) && "type is not a tag record!");199switch (type.kind()) {200case LF_CLASS:201case LF_STRUCTURE:202case LF_INTERFACE: {203ClassRecord cr;204llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));205return CVTagRecord(std::move(cr));206}207case LF_UNION: {208UnionRecord ur;209llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));210return CVTagRecord(std::move(ur));211}212case LF_ENUM: {213EnumRecord er;214llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));215return CVTagRecord(std::move(er));216}217default:218llvm_unreachable("Unreachable!");219}220}221222CVTagRecord::CVTagRecord(ClassRecord &&c)223: cvclass(std::move(c)),224m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}225CVTagRecord::CVTagRecord(UnionRecord &&u)226: cvunion(std::move(u)), m_kind(Union) {}227CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}228229PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {230switch (kind) {231case S_COMPILE3:232case S_OBJNAME:233return PDB_SymType::CompilandDetails;234case S_ENVBLOCK:235return PDB_SymType::CompilandEnv;236case S_THUNK32:237case S_TRAMPOLINE:238return PDB_SymType::Thunk;239case S_COFFGROUP:240return PDB_SymType::CoffGroup;241case S_EXPORT:242return PDB_SymType::Export;243case S_LPROC32:244case S_GPROC32:245case S_LPROC32_DPC:246return PDB_SymType::Function;247case S_PUB32:248return PDB_SymType::PublicSymbol;249case S_INLINESITE:250return PDB_SymType::InlineSite;251case S_LOCAL:252case S_BPREL32:253case S_REGREL32:254case S_MANCONSTANT:255case S_CONSTANT:256case S_LDATA32:257case S_GDATA32:258case S_LMANDATA:259case S_GMANDATA:260case S_LTHREAD32:261case S_GTHREAD32:262return PDB_SymType::Data;263case S_BLOCK32:264return PDB_SymType::Block;265case S_LABEL32:266return PDB_SymType::Label;267case S_CALLSITEINFO:268return PDB_SymType::CallSite;269case S_HEAPALLOCSITE:270return PDB_SymType::HeapAllocationSite;271case S_CALLEES:272return PDB_SymType::Callee;273case S_CALLERS:274return PDB_SymType::Caller;275default:276lldbassert(false && "Invalid symbol record kind!");277}278return PDB_SymType::None;279}280281PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {282switch (kind) {283case LF_ARRAY:284return PDB_SymType::ArrayType;285case LF_ARGLIST:286return PDB_SymType::FunctionSig;287case LF_BCLASS:288return PDB_SymType::BaseClass;289case LF_BINTERFACE:290return PDB_SymType::BaseInterface;291case LF_CLASS:292case LF_STRUCTURE:293case LF_INTERFACE:294case LF_UNION:295return PDB_SymType::UDT;296case LF_POINTER:297return PDB_SymType::PointerType;298case LF_ENUM:299return PDB_SymType::Enum;300case LF_PROCEDURE:301return PDB_SymType::FunctionSig;302case LF_BITFIELD:303return PDB_SymType::BuiltinType;304default:305lldbassert(false && "Invalid type record kind!");306}307return PDB_SymType::None;308}309310bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {311switch (sym.kind()) {312case S_GPROC32:313case S_LPROC32:314case S_GPROC32_ID:315case S_LPROC32_ID:316case S_LPROC32_DPC:317case S_LPROC32_DPC_ID:318case S_THUNK32:319case S_TRAMPOLINE:320case S_COFFGROUP:321case S_BLOCK32:322case S_LABEL32:323case S_CALLSITEINFO:324case S_HEAPALLOCSITE:325case S_LDATA32:326case S_GDATA32:327case S_LMANDATA:328case S_GMANDATA:329case S_LTHREAD32:330case S_GTHREAD32:331return true;332default:333return false;334}335}336337bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {338switch (sym.kind()) {339case S_GPROC32:340case S_LPROC32:341case S_GPROC32_ID:342case S_LPROC32_ID:343case S_LPROC32_DPC:344case S_LPROC32_DPC_ID:345case S_THUNK32:346case S_TRAMPOLINE:347case S_COFFGROUP:348case S_BLOCK32:349return true;350default:351return false;352}353}354355template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {356RecordT record(static_cast<SymbolRecordKind>(sym.kind()));357cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));358return record;359}360361template <typename RecordT>362static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {363RecordT record = createRecord<RecordT>(sym);364return {record.Segment, record.CodeOffset};365}366367template <>368SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {369TrampolineSym record = createRecord<TrampolineSym>(sym);370return {record.ThunkSection, record.ThunkOffset};371}372373template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {374Thunk32Sym record = createRecord<Thunk32Sym>(sym);375return {record.Segment, record.Offset};376}377378template <>379SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {380CoffGroupSym record = createRecord<CoffGroupSym>(sym);381return {record.Segment, record.Offset};382}383384template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {385DataSym record = createRecord<DataSym>(sym);386return {record.Segment, record.DataOffset};387}388389template <>390SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {391ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);392return {record.Segment, record.DataOffset};393}394395SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {396switch (sym.kind()) {397case S_GPROC32:398case S_LPROC32:399case S_GPROC32_ID:400case S_LPROC32_ID:401case S_LPROC32_DPC:402case S_LPROC32_DPC_ID:403return ::GetSegmentAndOffset<ProcSym>(sym);404case S_THUNK32:405return ::GetSegmentAndOffset<Thunk32Sym>(sym);406break;407case S_TRAMPOLINE:408return ::GetSegmentAndOffset<TrampolineSym>(sym);409break;410case S_COFFGROUP:411return ::GetSegmentAndOffset<CoffGroupSym>(sym);412break;413case S_BLOCK32:414return ::GetSegmentAndOffset<BlockSym>(sym);415break;416case S_LABEL32:417return ::GetSegmentAndOffset<LabelSym>(sym);418break;419case S_CALLSITEINFO:420return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);421break;422case S_HEAPALLOCSITE:423return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);424break;425case S_LDATA32:426case S_GDATA32:427case S_LMANDATA:428case S_GMANDATA:429return ::GetSegmentAndOffset<DataSym>(sym);430break;431case S_LTHREAD32:432case S_GTHREAD32:433return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);434break;435default:436lldbassert(false && "Record does not have a segment/offset!");437}438return {0, 0};439}440441template <typename RecordT>442SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {443RecordT record = createRecord<RecordT>(sym);444return {record.Segment, record.CodeOffset, record.CodeSize};445}446447template <>448SegmentOffsetLength449GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {450TrampolineSym record = createRecord<TrampolineSym>(sym);451return {record.ThunkSection, record.ThunkOffset, record.Size};452}453454template <>455SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {456Thunk32Sym record = createRecord<Thunk32Sym>(sym);457return SegmentOffsetLength{record.Segment, record.Offset, record.Length};458}459460template <>461SegmentOffsetLength462GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {463CoffGroupSym record = createRecord<CoffGroupSym>(sym);464return SegmentOffsetLength{record.Segment, record.Offset, record.Size};465}466467SegmentOffsetLength468lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {469switch (sym.kind()) {470case S_GPROC32:471case S_LPROC32:472case S_GPROC32_ID:473case S_LPROC32_ID:474case S_LPROC32_DPC:475case S_LPROC32_DPC_ID:476return ::GetSegmentOffsetAndLength<ProcSym>(sym);477case S_THUNK32:478return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);479break;480case S_TRAMPOLINE:481return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);482break;483case S_COFFGROUP:484return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);485break;486case S_BLOCK32:487return ::GetSegmentOffsetAndLength<BlockSym>(sym);488break;489default:490lldbassert(false && "Record does not have a segment/offset/length triple!");491}492return {0, 0, 0};493}494495bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {496ClassRecord cr;497UnionRecord ur;498EnumRecord er;499switch (cvt.kind()) {500case LF_CLASS:501case LF_STRUCTURE:502case LF_INTERFACE:503llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));504return cr.isForwardRef();505case LF_UNION:506llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));507return ur.isForwardRef();508case LF_ENUM:509llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));510return er.isForwardRef();511default:512return false;513}514}515516bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {517switch (cvt.kind()) {518case LF_CLASS:519case LF_STRUCTURE:520case LF_UNION:521case LF_ENUM:522return true;523default:524return false;525}526}527528bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) {529switch (cvt.kind()) {530case LF_CLASS:531case LF_STRUCTURE:532case LF_UNION:533return true;534default:535return false;536}537}538539bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id,540TpiStream &tpi) {541if (id.is_ipi || id.index.isSimple())542return false;543return IsForwardRefUdt(tpi.getType(id.index));544}545546bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) {547if (id.is_ipi || id.index.isSimple())548return false;549return IsTagRecord(tpi.getType(id.index));550}551552lldb::AccessType553lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {554switch (access) {555case MemberAccess::Private:556return lldb::eAccessPrivate;557case MemberAccess::Protected:558return lldb::eAccessProtected;559case MemberAccess::Public:560return lldb::eAccessPublic;561case MemberAccess::None:562return lldb::eAccessNone;563}564llvm_unreachable("unreachable");565}566567TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {568switch (cvt.kind()) {569case LF_CLASS:570case LF_STRUCTURE:571case LF_INTERFACE: {572ClassRecord cr;573cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));574return cr.FieldList;575}576case LF_UNION: {577UnionRecord ur;578cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));579return ur.FieldList;580}581case LF_ENUM: {582EnumRecord er;583cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));584return er.FieldList;585}586default:587llvm_unreachable("Unreachable!");588}589}590591TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {592lldbassert(modifier.kind() == LF_MODIFIER);593ModifierRecord mr;594llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));595return mr.ModifiedType;596}597598llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {599return MSVCUndecoratedNameParser::DropScope(name);600}601602VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {603VariableInfo result = {};604605if (sym.kind() == S_REGREL32) {606RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);607cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));608result.type = reg.Type;609result.name = reg.Name;610return result;611}612613if (sym.kind() == S_REGISTER) {614RegisterSym reg(SymbolRecordKind::RegisterSym);615cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));616result.type = reg.Index;617result.name = reg.Name;618return result;619}620621if (sym.kind() == S_LOCAL) {622LocalSym local(SymbolRecordKind::LocalSym);623cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));624result.type = local.Type;625result.name = local.Name;626result.is_param =627((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None);628return result;629}630631if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) {632DataSym data(SymbolRecordKind::DataSym);633cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data));634result.type = data.Type;635result.name = data.Name;636return result;637}638639if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) {640ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym);641cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data));642result.type = data.Type;643result.name = data.Name;644return result;645}646647if (sym.kind() == S_CONSTANT) {648ConstantSym constant(SymbolRecordKind::ConstantSym);649cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant));650result.type = constant.Type;651result.name = constant.Name;652return result;653}654655lldbassert(false && "Invalid variable record kind!");656return {};657}658659static llvm::FixedStreamArray<FrameData>::Iterator660GetCorrespondingFrameData(lldb::addr_t load_addr,661const DebugFrameDataSubsectionRef &fpo_data,662const Variable::RangeList &ranges) {663lldbassert(!ranges.IsEmpty());664665// assume that all variable ranges correspond to one frame data666using RangeListEntry = Variable::RangeList::Entry;667const RangeListEntry &range = ranges.GetEntryRef(0);668669auto it = fpo_data.begin();670671// start by searching first frame data range containing variable range672for (; it != fpo_data.end(); ++it) {673RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);674675if (fd_range.Contains(range)) {676break;677}678}679680// then first most nested entry that still contains variable range681auto found = it;682for (; it != fpo_data.end(); ++it) {683RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);684685if (!fd_range.Contains(range)) {686break;687}688found = it;689}690691return found;692}693694static bool GetFrameDataProgram(PdbIndex &index,695const Variable::RangeList &ranges,696llvm::StringRef &out_program) {697const DebugFrameDataSubsectionRef &new_fpo_data =698index.dbi().getNewFpoRecords();699700auto frame_data_it =701GetCorrespondingFrameData(index.GetLoadAddress(), new_fpo_data, ranges);702if (frame_data_it == new_fpo_data.end())703return false;704705auto strings = index.pdb().getStringTable();706if (!strings) {707consumeError(strings.takeError());708return false;709}710out_program = cantFail(strings->getStringForID(frame_data_it->FrameFunc));711return true;712}713714static RegisterId GetBaseFrameRegister(PdbIndex &index,715PdbCompilandSymId frame_proc_id,716bool is_parameter) {717CVSymbol frame_proc_cvs = index.ReadSymbolRecord(frame_proc_id);718if (frame_proc_cvs.kind() != S_FRAMEPROC)719return RegisterId::NONE;720721FrameProcSym frame_proc(SymbolRecordKind::FrameProcSym);722cantFail(SymbolDeserializer::deserializeAs<FrameProcSym>(frame_proc_cvs,723frame_proc));724725CPUType cpu_type = index.compilands()726.GetCompiland(frame_proc_id.modi)727->m_compile_opts->Machine;728729return is_parameter ? frame_proc.getParamFramePtrReg(cpu_type)730: frame_proc.getLocalFramePtrReg(cpu_type);731}732733VariableInfo lldb_private::npdb::GetVariableLocationInfo(734PdbIndex &index, PdbCompilandSymId var_id, Block &func_block,735lldb::ModuleSP module) {736737CVSymbol sym = index.ReadSymbolRecord(var_id);738739VariableInfo result = GetVariableNameInfo(sym);740741if (sym.kind() == S_REGREL32) {742RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);743cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));744result.location = DWARFExpressionList(745module, MakeRegRelLocationExpression(reg.Register, reg.Offset, module),746nullptr);747return result;748}749750if (sym.kind() == S_REGISTER) {751RegisterSym reg(SymbolRecordKind::RegisterSym);752cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));753result.location = DWARFExpressionList(754module, MakeEnregisteredLocationExpression(reg.Register, module),755nullptr);756return result;757}758759if (sym.kind() == S_LOCAL) {760LocalSym local(SymbolRecordKind::LocalSym);761if (llvm::Error error =762SymbolDeserializer::deserializeAs<LocalSym>(sym, local)) {763llvm::consumeError(std::move(error));764return result;765}766767PdbCompilandSymId loc_specifier_id(var_id.modi,768var_id.offset + sym.RecordData.size());769CVSymbol loc_specifier_cvs;770// Only used for S_DEFRANGE_FRAMEPOINTER_REL.771RegisterId base_reg = RegisterId::NONE;772size_t type_size = GetSizeOfType(result.type, index.tpi());773// A map from offset of a field in parent to size of the field.774std::map<uint64_t, size_t> offset_to_size;775776// When overlaps happens, always prefer the one that doesn't split the value777// into multiple locations and the location parsed first is perfered.778RangeMap location_map;779780// Iterate through all location records after S_LOCAL. They describe the781// value of this variable at different locations.782bool finished = false;783while (!finished) {784loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);785switch (loc_specifier_cvs.kind()) {786case S_DEFRANGE_FRAMEPOINTER_REL: {787DefRangeFramePointerRelSym loc(788SymbolRecordKind::DefRangeFramePointerRelSym);789if (llvm::Error error =790SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(791loc_specifier_cvs, loc)) {792llvm::consumeError(std::move(error));793return result;794}795Variable::RangeList raw_ranges =796MakeRangeList(index, loc.Range, loc.Gaps);797if (base_reg == RegisterId::NONE) {798PdbCompilandSymId func_scope_id =799PdbSymUid(func_block.GetID()).asCompilandSym();800CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id);801lldbassert(func_block_cvs.kind() == S_GPROC32 ||802func_block_cvs.kind() == S_LPROC32);803PdbCompilandSymId frame_proc_id(func_scope_id.modi,804func_scope_id.offset +805func_block_cvs.length());806base_reg =807GetBaseFrameRegister(index, frame_proc_id, result.is_param);808if (base_reg == RegisterId::NONE)809break;810}811DWARFExpression expr;812if (base_reg == RegisterId::VFRAME) {813llvm::StringRef program;814if (GetFrameDataProgram(index, raw_ranges, program))815expr = MakeVFrameRelLocationExpression(program, loc.Hdr.Offset,816module);817else {818// invalid variable819}820} else821expr = MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module);822AddDwarfRange(location_map, expr, raw_ranges);823break;824}825case S_DEFRANGE_REGISTER: {826DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym);827if (llvm::Error error =828SymbolDeserializer::deserializeAs<DefRangeRegisterSym>(829loc_specifier_cvs, loc)) {830llvm::consumeError(std::move(error));831return result;832}833RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;834Variable::RangeList raw_ranges =835MakeRangeList(index, loc.Range, loc.Gaps);836DWARFExpression expr =837MakeEnregisteredLocationExpression(reg_id, module);838AddDwarfRange(location_map, expr, raw_ranges);839break;840}841case S_DEFRANGE_REGISTER_REL: {842DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym);843if (llvm::Error error =844SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>(845loc_specifier_cvs, loc)) {846llvm::consumeError(std::move(error));847return result;848}849Variable::RangeList raw_ranges =850MakeRangeList(index, loc.Range, loc.Gaps);851RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;852DWARFExpression expr;853if (reg_id == RegisterId::VFRAME) {854llvm::StringRef program;855if (GetFrameDataProgram(index, raw_ranges, program))856expr = MakeVFrameRelLocationExpression(857program, loc.Hdr.BasePointerOffset, module);858else {859// invalid variable860}861} else {862expr = MakeRegRelLocationExpression(reg_id, loc.Hdr.BasePointerOffset,863module);864}865// FIXME: If it's UDT, we need to know the size of the value in byte.866if (!loc.hasSpilledUDTMember())867AddDwarfRange(location_map, expr, raw_ranges);868break;869}870case S_DEFRANGE_SUBFIELD_REGISTER: {871DefRangeSubfieldRegisterSym loc(872SymbolRecordKind::DefRangeSubfieldRegisterSym);873if (llvm::Error error =874SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>(875loc_specifier_cvs, loc)) {876llvm::consumeError(std::move(error));877return result;878}879880Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps);881uint32_t reg_size =882GetRegisterSize((RegisterId)(uint16_t)loc.Hdr.Register);883if (reg_size == 0)884break;885offset_to_size[loc.Hdr.OffsetInParent] = reg_size;886AddMemberLocationRanges(location_map, loc.Hdr.OffsetInParent,887{loc.Hdr.Register, 0, true}, ranges);888break;889}890// FIXME: Handle other kinds. LLVM only generates the 4 types of records891// above. MSVC generates other location types.892case S_DEFRANGE:893case S_DEFRANGE_SUBFIELD:894case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:895break;896default:897finished = true;898break;899}900loc_specifier_id = PdbCompilandSymId(901loc_specifier_id.modi,902loc_specifier_id.offset + loc_specifier_cvs.RecordData.size());903}904for (const auto &entry : location_map) {905DWARFExpression dwarf_expr =906entry.data.is_dwarf ? entry.data.expr907: MakeEnregisteredLocationExpressionForComposite(908entry.data.offset_to_location,909offset_to_size, type_size, module);910911result.location.AddExpression(entry.GetRangeBase(), entry.GetRangeEnd(),912dwarf_expr);913}914return result;915}916llvm_unreachable("Symbol is not a local variable!");917return result;918}919920lldb::BasicType921lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {922switch (kind) {923case SimpleTypeKind::Boolean128:924case SimpleTypeKind::Boolean16:925case SimpleTypeKind::Boolean32:926case SimpleTypeKind::Boolean64:927case SimpleTypeKind::Boolean8:928return lldb::eBasicTypeBool;929case SimpleTypeKind::Byte:930case SimpleTypeKind::UnsignedCharacter:931return lldb::eBasicTypeUnsignedChar;932case SimpleTypeKind::NarrowCharacter:933return lldb::eBasicTypeChar;934case SimpleTypeKind::SignedCharacter:935case SimpleTypeKind::SByte:936return lldb::eBasicTypeSignedChar;937case SimpleTypeKind::Character16:938return lldb::eBasicTypeChar16;939case SimpleTypeKind::Character32:940return lldb::eBasicTypeChar32;941case SimpleTypeKind::Character8:942return lldb::eBasicTypeChar8;943case SimpleTypeKind::Complex80:944return lldb::eBasicTypeLongDoubleComplex;945case SimpleTypeKind::Complex64:946return lldb::eBasicTypeDoubleComplex;947case SimpleTypeKind::Complex32:948return lldb::eBasicTypeFloatComplex;949case SimpleTypeKind::Float128:950case SimpleTypeKind::Float80:951return lldb::eBasicTypeLongDouble;952case SimpleTypeKind::Float64:953return lldb::eBasicTypeDouble;954case SimpleTypeKind::Float32:955return lldb::eBasicTypeFloat;956case SimpleTypeKind::Float16:957return lldb::eBasicTypeHalf;958case SimpleTypeKind::Int128:959return lldb::eBasicTypeInt128;960case SimpleTypeKind::Int64:961case SimpleTypeKind::Int64Quad:962return lldb::eBasicTypeLongLong;963case SimpleTypeKind::Int32:964return lldb::eBasicTypeInt;965case SimpleTypeKind::Int16:966case SimpleTypeKind::Int16Short:967return lldb::eBasicTypeShort;968case SimpleTypeKind::UInt128:969return lldb::eBasicTypeUnsignedInt128;970case SimpleTypeKind::UInt64:971case SimpleTypeKind::UInt64Quad:972return lldb::eBasicTypeUnsignedLongLong;973case SimpleTypeKind::HResult:974case SimpleTypeKind::UInt32:975return lldb::eBasicTypeUnsignedInt;976case SimpleTypeKind::UInt16:977case SimpleTypeKind::UInt16Short:978return lldb::eBasicTypeUnsignedShort;979case SimpleTypeKind::Int32Long:980return lldb::eBasicTypeLong;981case SimpleTypeKind::UInt32Long:982return lldb::eBasicTypeUnsignedLong;983case SimpleTypeKind::Void:984return lldb::eBasicTypeVoid;985case SimpleTypeKind::WideCharacter:986return lldb::eBasicTypeWChar;987default:988return lldb::eBasicTypeInvalid;989}990}991992size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {993switch (kind) {994case SimpleTypeKind::Boolean128:995case SimpleTypeKind::Int128:996case SimpleTypeKind::UInt128:997case SimpleTypeKind::Float128:998return 16;999case SimpleTypeKind::Complex80:1000case SimpleTypeKind::Float80:1001return 10;1002case SimpleTypeKind::Boolean64:1003case SimpleTypeKind::Complex64:1004case SimpleTypeKind::UInt64:1005case SimpleTypeKind::UInt64Quad:1006case SimpleTypeKind::Float64:1007case SimpleTypeKind::Int64:1008case SimpleTypeKind::Int64Quad:1009return 8;1010case SimpleTypeKind::Boolean32:1011case SimpleTypeKind::Character32:1012case SimpleTypeKind::Complex32:1013case SimpleTypeKind::Float32:1014case SimpleTypeKind::Int32:1015case SimpleTypeKind::Int32Long:1016case SimpleTypeKind::UInt32Long:1017case SimpleTypeKind::HResult:1018case SimpleTypeKind::UInt32:1019return 4;1020case SimpleTypeKind::Boolean16:1021case SimpleTypeKind::Character16:1022case SimpleTypeKind::Float16:1023case SimpleTypeKind::Int16:1024case SimpleTypeKind::Int16Short:1025case SimpleTypeKind::UInt16:1026case SimpleTypeKind::UInt16Short:1027case SimpleTypeKind::WideCharacter:1028return 2;1029case SimpleTypeKind::Boolean8:1030case SimpleTypeKind::Byte:1031case SimpleTypeKind::UnsignedCharacter:1032case SimpleTypeKind::NarrowCharacter:1033case SimpleTypeKind::SignedCharacter:1034case SimpleTypeKind::SByte:1035case SimpleTypeKind::Character8:1036return 1;1037case SimpleTypeKind::Void:1038default:1039return 0;1040}1041}10421043PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id,1044TpiStream &tpi) {1045if (id.index.isSimple())1046return id;10471048CVType cvt = tpi.getType(id.index);10491050// Only tag records have a best and a worst record.1051if (!IsTagRecord(cvt))1052return id;10531054// Tag records that are not forward decls are full decls, hence they are the1055// best.1056if (!IsForwardRefUdt(cvt))1057return id;10581059return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index));1060}10611062template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) {1063RecordType record;1064llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record));1065return record.getSize();1066}10671068size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,1069llvm::pdb::TpiStream &tpi) {1070if (id.index.isSimple()) {1071switch (id.index.getSimpleMode()) {1072case SimpleTypeMode::Direct:1073return GetTypeSizeForSimpleKind(id.index.getSimpleKind());1074case SimpleTypeMode::NearPointer32:1075case SimpleTypeMode::FarPointer32:1076return 4;1077case SimpleTypeMode::NearPointer64:1078return 8;1079case SimpleTypeMode::NearPointer128:1080return 16;1081default:1082break;1083}1084return 0;1085}10861087TypeIndex index = id.index;1088if (IsForwardRefUdt(index, tpi))1089index = llvm::cantFail(tpi.findFullDeclForForwardRef(index));10901091CVType cvt = tpi.getType(index);1092switch (cvt.kind()) {1093case LF_MODIFIER:1094return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi);1095case LF_ENUM: {1096EnumRecord record;1097llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record));1098return GetSizeOfType({record.UnderlyingType}, tpi);1099}1100case LF_POINTER:1101return GetSizeOfTypeInternal<PointerRecord>(cvt);1102case LF_ARRAY:1103return GetSizeOfTypeInternal<ArrayRecord>(cvt);1104case LF_CLASS:1105case LF_STRUCTURE:1106case LF_INTERFACE:1107return GetSizeOfTypeInternal<ClassRecord>(cvt);1108case LF_UNION:1109return GetSizeOfTypeInternal<UnionRecord>(cvt);1110case LF_BITFIELD: {1111BitFieldRecord record;1112llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, record));1113return GetSizeOfType({record.Type}, tpi);1114}1115default:1116break;1117}1118return 0;1119}112011211122