15ffd83dbSDimitry Andric //===-- PDBLocationToDWARFExpression.cpp ----------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "PDBLocationToDWARFExpression.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Core/Section.h"
120b57cec5SDimitry Andric #include "lldb/Core/dwarf.h"
130b57cec5SDimitry Andric #include "lldb/Expression/DWARFExpression.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Variable.h"
150b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
16*5f757f3fSDimitry Andric #include "lldb/Utility/StreamBuffer.h"
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBSession.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric #include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
230b57cec5SDimitry Andric #include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric using namespace lldb_private;
270b57cec5SDimitry Andric using namespace lldb_private::npdb;
2881ad6265SDimitry Andric using namespace lldb_private::dwarf;
290b57cec5SDimitry Andric using namespace llvm::pdb;
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric static std::unique_ptr<IPDBFrameData>
GetCorrespondingFrameData(const IPDBSession & session,const Variable::RangeList & ranges)320b57cec5SDimitry Andric GetCorrespondingFrameData(const IPDBSession &session,
330b57cec5SDimitry Andric const Variable::RangeList &ranges) {
340b57cec5SDimitry Andric auto enumFrameData = session.getFrameData();
350b57cec5SDimitry Andric if (!enumFrameData)
360b57cec5SDimitry Andric return nullptr;
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric std::unique_ptr<IPDBFrameData> found;
390b57cec5SDimitry Andric while (auto fd = enumFrameData->getNext()) {
400b57cec5SDimitry Andric Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
410b57cec5SDimitry Andric fd->getLengthBlock());
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric for (size_t i = 0; i < ranges.GetSize(); i++) {
440b57cec5SDimitry Andric auto range = ranges.GetEntryAtIndex(i);
450b57cec5SDimitry Andric if (!range)
460b57cec5SDimitry Andric continue;
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric if (!range->DoesIntersect(fdRange))
490b57cec5SDimitry Andric continue;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric found = std::move(fd);
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric break;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric return found;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)600b57cec5SDimitry Andric static bool EmitVFrameEvaluationDWARFExpression(
610b57cec5SDimitry Andric llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
620b57cec5SDimitry Andric // VFrame value always stored in $TO pseudo-register
630b57cec5SDimitry Andric return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
640b57cec5SDimitry Andric stream);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric
ConvertPDBLocationToDWARFExpression(ModuleSP module,const PDBSymbolData & symbol,const Variable::RangeList & ranges,bool & is_constant)670b57cec5SDimitry Andric DWARFExpression ConvertPDBLocationToDWARFExpression(
680b57cec5SDimitry Andric ModuleSP module, const PDBSymbolData &symbol,
690b57cec5SDimitry Andric const Variable::RangeList &ranges, bool &is_constant) {
700b57cec5SDimitry Andric is_constant = true;
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric if (!module)
730b57cec5SDimitry Andric return DWARFExpression();
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric const ArchSpec &architecture = module->GetArchitecture();
760b57cec5SDimitry Andric llvm::Triple::ArchType arch_type = architecture.GetMachine();
770b57cec5SDimitry Andric ByteOrder byte_order = architecture.GetByteOrder();
780b57cec5SDimitry Andric uint32_t address_size = architecture.GetAddressByteSize();
790b57cec5SDimitry Andric uint32_t byte_size = architecture.GetDataByteSize();
800b57cec5SDimitry Andric if (byte_order == eByteOrderInvalid || address_size == 0)
810b57cec5SDimitry Andric return DWARFExpression();
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric RegisterKind register_kind = eRegisterKindDWARF;
840b57cec5SDimitry Andric StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
850b57cec5SDimitry Andric switch (symbol.getLocationType()) {
860b57cec5SDimitry Andric case PDB_LocType::Static:
870b57cec5SDimitry Andric case PDB_LocType::TLS: {
880b57cec5SDimitry Andric stream.PutHex8(DW_OP_addr);
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric SectionList *section_list = module->GetSectionList();
910b57cec5SDimitry Andric if (!section_list)
920b57cec5SDimitry Andric return DWARFExpression();
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric uint32_t section_id = symbol.getAddressSection();
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric auto section = section_list->FindSectionByID(section_id);
970b57cec5SDimitry Andric if (!section)
980b57cec5SDimitry Andric return DWARFExpression();
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric uint32_t offset = symbol.getAddressOffset();
1010b57cec5SDimitry Andric stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
1020b57cec5SDimitry Andric byte_order);
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric is_constant = false;
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric break;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric case PDB_LocType::RegRel: {
1090b57cec5SDimitry Andric uint32_t reg_num;
1100b57cec5SDimitry Andric auto reg_id = symbol.getRegisterId();
1110b57cec5SDimitry Andric if (reg_id == llvm::codeview::RegisterId::VFRAME) {
1120b57cec5SDimitry Andric if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
1130b57cec5SDimitry Andric if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
1140b57cec5SDimitry Andric stream)) {
1150b57cec5SDimitry Andric int32_t offset = symbol.getOffset();
1160b57cec5SDimitry Andric stream.PutHex8(DW_OP_consts);
1170b57cec5SDimitry Andric stream.PutSLEB128(offset);
1180b57cec5SDimitry Andric stream.PutHex8(DW_OP_plus);
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric register_kind = eRegisterKindLLDB;
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric is_constant = false;
1230b57cec5SDimitry Andric break;
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric register_kind = eRegisterKindGeneric;
1280b57cec5SDimitry Andric reg_num = LLDB_REGNUM_GENERIC_FP;
1290b57cec5SDimitry Andric } else {
1300b57cec5SDimitry Andric register_kind = eRegisterKindLLDB;
1310b57cec5SDimitry Andric reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
1320b57cec5SDimitry Andric if (reg_num == LLDB_INVALID_REGNUM)
1330b57cec5SDimitry Andric return DWARFExpression();
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric if (reg_num > 31) {
1370b57cec5SDimitry Andric stream.PutHex8(DW_OP_bregx);
1380b57cec5SDimitry Andric stream.PutULEB128(reg_num);
1390b57cec5SDimitry Andric } else
1400b57cec5SDimitry Andric stream.PutHex8(DW_OP_breg0 + reg_num);
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric int32_t offset = symbol.getOffset();
1430b57cec5SDimitry Andric stream.PutSLEB128(offset);
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric is_constant = false;
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric break;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric case PDB_LocType::Enregistered: {
1500b57cec5SDimitry Andric register_kind = eRegisterKindLLDB;
1510b57cec5SDimitry Andric uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
1520b57cec5SDimitry Andric if (reg_num == LLDB_INVALID_REGNUM)
1530b57cec5SDimitry Andric return DWARFExpression();
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric if (reg_num > 31) {
1560b57cec5SDimitry Andric stream.PutHex8(DW_OP_regx);
1570b57cec5SDimitry Andric stream.PutULEB128(reg_num);
1580b57cec5SDimitry Andric } else
1590b57cec5SDimitry Andric stream.PutHex8(DW_OP_reg0 + reg_num);
1600b57cec5SDimitry Andric
1610b57cec5SDimitry Andric is_constant = false;
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric break;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric case PDB_LocType::Constant: {
1660b57cec5SDimitry Andric Variant value = symbol.getValue();
1670b57cec5SDimitry Andric stream.PutRawBytes(&value.Value, sizeof(value.Value),
1680b57cec5SDimitry Andric endian::InlHostByteOrder());
1690b57cec5SDimitry Andric break;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric default:
1720b57cec5SDimitry Andric return DWARFExpression();
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric DataBufferSP buffer =
1760b57cec5SDimitry Andric std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
1770b57cec5SDimitry Andric DataExtractor extractor(buffer, byte_order, address_size, byte_size);
178753f127fSDimitry Andric DWARFExpression result(extractor);
1790b57cec5SDimitry Andric result.SetRegisterKind(register_kind);
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric return result;
1820b57cec5SDimitry Andric }
183