diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp new file mode 100644 index 000000000000..95add31385df --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -0,0 +1,182 @@ +//===-- 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 lldb_private::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(); + 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(extractor); + result.SetRegisterKind(register_kind); + + return result; +} |