//===-- PDBLocationToDWARFExpression.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "PDBLocationToDWARFExpression.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamBuffer.h" #include "lldb/Core/dwarf.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Variable.h" #include "lldb/Utility/DataBufferHeap.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h" #include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::npdb; using namespace llvm::pdb; static std::unique_ptr GetCorrespondingFrameData(const IPDBSession &session, const Variable::RangeList &ranges) { auto enumFrameData = session.getFrameData(); if (!enumFrameData) return nullptr; std::unique_ptr found; while (auto fd = enumFrameData->getNext()) { Range fdRange(fd->getVirtualAddress(), fd->getLengthBlock()); for (size_t i = 0; i < ranges.GetSize(); i++) { auto range = ranges.GetEntryAtIndex(i); if (!range) continue; if (!range->DoesIntersect(fdRange)) continue; found = std::move(fd); break; } } return found; } static bool EmitVFrameEvaluationDWARFExpression( llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) { // VFrame value always stored in $TO pseudo-register return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type, stream); } DWARFExpression ConvertPDBLocationToDWARFExpression( ModuleSP module, const PDBSymbolData &symbol, const Variable::RangeList &ranges, bool &is_constant) { is_constant = true; if (!module) return DWARFExpression(); const ArchSpec &architecture = module->GetArchitecture(); llvm::Triple::ArchType arch_type = architecture.GetMachine(); ByteOrder byte_order = architecture.GetByteOrder(); uint32_t address_size = architecture.GetAddressByteSize(); uint32_t byte_size = architecture.GetDataByteSize(); if (byte_order == eByteOrderInvalid || address_size == 0) return DWARFExpression(); RegisterKind register_kind = eRegisterKindDWARF; StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order); switch (symbol.getLocationType()) { case PDB_LocType::Static: case PDB_LocType::TLS: { stream.PutHex8(DW_OP_addr); SectionList *section_list = module->GetSectionList(); if (!section_list) return DWARFExpression(); uint32_t section_id = symbol.getAddressSection(); auto section = section_list->FindSectionByID(section_id); if (!section) return DWARFExpression(); uint32_t offset = symbol.getAddressOffset(); stream.PutMaxHex64(section->GetFileAddress() + offset, address_size, byte_order); is_constant = false; break; } case PDB_LocType::RegRel: { uint32_t reg_num; auto reg_id = symbol.getRegisterId(); if (reg_id == llvm::codeview::RegisterId::VFRAME) { if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) { if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type, stream)) { int32_t offset = symbol.getOffset(); stream.PutHex8(DW_OP_consts); stream.PutSLEB128(offset); stream.PutHex8(DW_OP_plus); register_kind = eRegisterKindLLDB; is_constant = false; break; } } register_kind = eRegisterKindGeneric; reg_num = LLDB_REGNUM_GENERIC_FP; } else { register_kind = eRegisterKindLLDB; reg_num = GetLLDBRegisterNumber(arch_type, reg_id); if (reg_num == LLDB_INVALID_REGNUM) return DWARFExpression(); } if (reg_num > 31) { stream.PutHex8(DW_OP_bregx); stream.PutULEB128(reg_num); } else stream.PutHex8(DW_OP_breg0 + reg_num); int32_t offset = symbol.getOffset(); stream.PutSLEB128(offset); is_constant = false; break; } case PDB_LocType::Enregistered: { register_kind = eRegisterKindLLDB; uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId()); if (reg_num == LLDB_INVALID_REGNUM) return DWARFExpression(); if (reg_num > 31) { stream.PutHex8(DW_OP_regx); stream.PutULEB128(reg_num); } else stream.PutHex8(DW_OP_reg0 + reg_num); is_constant = false; break; } case PDB_LocType::Constant: { Variant value = symbol.getValue(); stream.PutRawBytes(&value.Value, sizeof(value.Value), endian::InlHostByteOrder()); break; } default: return DWARFExpression(); } DataBufferSP buffer = std::make_shared(stream.GetData(), stream.GetSize()); DataExtractor extractor(buffer, byte_order, address_size, byte_size); DWARFExpression result(module, extractor, nullptr); result.SetRegisterKind(register_kind); return result; }