| //===-- 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/dwarf.h" | |
| #include "lldb/Expression/DWARFExpression.h" | |
| #include "lldb/Symbol/Variable.h" | |
| #include "lldb/Utility/DataBufferHeap.h" | |
| #include "lldb/Utility/StreamBuffer.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::dwarf; | |
| using namespace llvm::pdb; | |
| static std::unique_ptr<IPDBFrameData> | |
| GetCorrespondingFrameData(const IPDBSession &session, | |
| const Variable::RangeList &ranges) { | |
| auto enumFrameData = session.getFrameData(); | |
| if (!enumFrameData) | |
| return nullptr; | |
| std::unique_ptr<IPDBFrameData> found; | |
| while (auto fd = enumFrameData->getNext()) { | |
| Range<lldb::addr_t, lldb::addr_t> 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(); | |
| if (byte_order == eByteOrderInvalid || address_size == 0) | |
| return DWARFExpression(); | |
| RegisterKind register_kind = eRegisterKindDWARF; | |
| StreamBuffer<32> stream(Stream::eBinary, 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<DataBufferHeap>(stream.GetData(), stream.GetSize()); | |
| DataExtractor extractor(buffer, byte_order, address_size); | |
| DWARFExpression result(extractor); | |
| result.SetRegisterKind(register_kind); | |
| return result; | |
| } |