| //===-- 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<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(); |
| 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<DataBufferHeap>(stream.GetData(), stream.GetSize()); |
| DataExtractor extractor(buffer, byte_order, address_size, byte_size); |
| DWARFExpression result(module, extractor, nullptr); |
| result.SetRegisterKind(register_kind); |
| |
| return result; |
| } |