15ffd83dbSDimitry Andric //===-- DWARFLocationExpression.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 "DWARFLocationExpression.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "lldb/Core/Module.h" 120b57cec5SDimitry Andric #include "lldb/Core/Section.h" 130b57cec5SDimitry Andric #include "lldb/Expression/DWARFExpression.h" 140b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h" 150b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 16*5f757f3fSDimitry Andric #include "lldb/Utility/StreamBuffer.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 190b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 200b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h" 210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 220b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #include "PdbUtil.h" 250b57cec5SDimitry Andric #include "CodeViewRegisterMapping.h" 260b57cec5SDimitry Andric #include "PdbFPOProgramToDWARFExpression.h" 27bdd1243dSDimitry Andric #include <optional> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace lldb; 300b57cec5SDimitry Andric using namespace lldb_private; 310b57cec5SDimitry Andric using namespace lldb_private::npdb; 320b57cec5SDimitry Andric using namespace llvm::codeview; 330b57cec5SDimitry Andric using namespace llvm::pdb; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { 360b57cec5SDimitry Andric if (register_id == llvm::codeview::RegisterId::VFRAME) 370b57cec5SDimitry Andric return LLDB_REGNUM_GENERIC_FP; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric return LLDB_INVALID_REGNUM; 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, 430b57cec5SDimitry Andric llvm::codeview::RegisterId register_id, 440b57cec5SDimitry Andric RegisterKind ®ister_kind) { 450b57cec5SDimitry Andric register_kind = eRegisterKindLLDB; 460b57cec5SDimitry Andric uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id); 470b57cec5SDimitry Andric if (reg_num != LLDB_INVALID_REGNUM) 480b57cec5SDimitry Andric return reg_num; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric register_kind = eRegisterKindGeneric; 510b57cec5SDimitry Andric return GetGenericRegisterNumber(register_id); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) { 550b57cec5SDimitry Andric switch (kind) { 560b57cec5SDimitry Andric case SimpleTypeKind::Int128: 570b57cec5SDimitry Andric case SimpleTypeKind::Int64: 580b57cec5SDimitry Andric case SimpleTypeKind::Int64Quad: 590b57cec5SDimitry Andric case SimpleTypeKind::Int32: 600b57cec5SDimitry Andric case SimpleTypeKind::Int32Long: 610b57cec5SDimitry Andric case SimpleTypeKind::Int16: 620b57cec5SDimitry Andric case SimpleTypeKind::Int16Short: 630b57cec5SDimitry Andric case SimpleTypeKind::Float128: 640b57cec5SDimitry Andric case SimpleTypeKind::Float80: 650b57cec5SDimitry Andric case SimpleTypeKind::Float64: 660b57cec5SDimitry Andric case SimpleTypeKind::Float32: 670b57cec5SDimitry Andric case SimpleTypeKind::Float16: 680b57cec5SDimitry Andric case SimpleTypeKind::NarrowCharacter: 690b57cec5SDimitry Andric case SimpleTypeKind::SignedCharacter: 700b57cec5SDimitry Andric case SimpleTypeKind::SByte: 710b57cec5SDimitry Andric return true; 720b57cec5SDimitry Andric default: 730b57cec5SDimitry Andric return false; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti, 780b57cec5SDimitry Andric TpiStream &tpi) { 790b57cec5SDimitry Andric if (ti.isSimple()) { 800b57cec5SDimitry Andric SimpleTypeKind stk = ti.getSimpleKind(); 810b57cec5SDimitry Andric return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)}; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric CVType cvt = tpi.getType(ti); 850b57cec5SDimitry Andric switch (cvt.kind()) { 860b57cec5SDimitry Andric case LF_MODIFIER: { 870b57cec5SDimitry Andric ModifierRecord mfr; 880b57cec5SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr)); 890b57cec5SDimitry Andric return GetIntegralTypeInfo(mfr.ModifiedType, tpi); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric case LF_POINTER: { 920b57cec5SDimitry Andric PointerRecord pr; 930b57cec5SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr)); 940b57cec5SDimitry Andric return GetIntegralTypeInfo(pr.ReferentType, tpi); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric case LF_ENUM: { 970b57cec5SDimitry Andric EnumRecord er; 980b57cec5SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); 990b57cec5SDimitry Andric return GetIntegralTypeInfo(er.UnderlyingType, tpi); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric default: 1020b57cec5SDimitry Andric assert(false && "Type is not integral!"); 1030b57cec5SDimitry Andric return {0, false}; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric template <typename StreamWriter> 1080b57cec5SDimitry Andric static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module, 1090b57cec5SDimitry Andric StreamWriter &&writer) { 1100b57cec5SDimitry Andric const ArchSpec &architecture = module->GetArchitecture(); 1110b57cec5SDimitry Andric ByteOrder byte_order = architecture.GetByteOrder(); 1120b57cec5SDimitry Andric uint32_t address_size = architecture.GetAddressByteSize(); 1130b57cec5SDimitry Andric uint32_t byte_size = architecture.GetDataByteSize(); 1140b57cec5SDimitry Andric if (byte_order == eByteOrderInvalid || address_size == 0) 1150b57cec5SDimitry Andric return DWARFExpression(); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric RegisterKind register_kind = eRegisterKindDWARF; 1180b57cec5SDimitry Andric StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric if (!writer(stream, register_kind)) 1210b57cec5SDimitry Andric return DWARFExpression(); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric DataBufferSP buffer = 1240b57cec5SDimitry Andric std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize()); 1250b57cec5SDimitry Andric DataExtractor extractor(buffer, byte_order, address_size, byte_size); 126753f127fSDimitry Andric DWARFExpression result(extractor); 1270b57cec5SDimitry Andric result.SetRegisterKind(register_kind); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric return result; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 132bdd1243dSDimitry Andric static bool MakeRegisterBasedLocationExpressionInternal( 133bdd1243dSDimitry Andric Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind, 134bdd1243dSDimitry Andric std::optional<int32_t> relative_offset, lldb::ModuleSP module) { 135bdd1243dSDimitry Andric uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(), 136bdd1243dSDimitry Andric reg, register_kind); 1370b57cec5SDimitry Andric if (reg_num == LLDB_INVALID_REGNUM) 1380b57cec5SDimitry Andric return false; 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric if (reg_num > 31) { 141bdd1243dSDimitry Andric llvm::dwarf::LocationAtom base = 142bdd1243dSDimitry Andric relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx; 1430b57cec5SDimitry Andric stream.PutHex8(base); 1440b57cec5SDimitry Andric stream.PutULEB128(reg_num); 1450b57cec5SDimitry Andric } else { 146bdd1243dSDimitry Andric llvm::dwarf::LocationAtom base = 147bdd1243dSDimitry Andric relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0; 1480b57cec5SDimitry Andric stream.PutHex8(base + reg_num); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric if (relative_offset) 1520b57cec5SDimitry Andric stream.PutSLEB128(*relative_offset); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric return true; 155bdd1243dSDimitry Andric } 156bdd1243dSDimitry Andric 157bdd1243dSDimitry Andric static DWARFExpression MakeRegisterBasedLocationExpressionInternal( 158bdd1243dSDimitry Andric llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset, 159bdd1243dSDimitry Andric lldb::ModuleSP module) { 160bdd1243dSDimitry Andric return MakeLocationExpressionInternal( 161bdd1243dSDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 162bdd1243dSDimitry Andric return MakeRegisterBasedLocationExpressionInternal( 163bdd1243dSDimitry Andric stream, reg, register_kind, relative_offset, module); 1640b57cec5SDimitry Andric }); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression( 1680b57cec5SDimitry Andric llvm::codeview::RegisterId reg, lldb::ModuleSP module) { 169bdd1243dSDimitry Andric return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression( 1730b57cec5SDimitry Andric llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) { 1740b57cec5SDimitry Andric return MakeRegisterBasedLocationExpressionInternal(reg, offset, module); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric static bool EmitVFrameEvaluationDWARFExpression( 1780b57cec5SDimitry Andric llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) { 1790b57cec5SDimitry Andric // VFrame value always stored in $TO pseudo-register 1800b57cec5SDimitry Andric return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type, 1810b57cec5SDimitry Andric stream); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression( 1850b57cec5SDimitry Andric llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) { 1860b57cec5SDimitry Andric return MakeLocationExpressionInternal( 1870b57cec5SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 1880b57cec5SDimitry Andric const ArchSpec &architecture = module->GetArchitecture(); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(), 1910b57cec5SDimitry Andric stream)) 1920b57cec5SDimitry Andric return false; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_consts); 1950b57cec5SDimitry Andric stream.PutSLEB128(offset); 1960b57cec5SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_plus); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric register_kind = eRegisterKindLLDB; 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric return true; 2010b57cec5SDimitry Andric }); 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression( 2050b57cec5SDimitry Andric uint16_t section, uint32_t offset, ModuleSP module) { 2060b57cec5SDimitry Andric assert(section > 0); 2070b57cec5SDimitry Andric assert(module); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric return MakeLocationExpressionInternal( 2100b57cec5SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 2110b57cec5SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_addr); 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric SectionList *section_list = module->GetSectionList(); 2140b57cec5SDimitry Andric assert(section_list); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric auto section_ptr = section_list->FindSectionByID(section); 2170b57cec5SDimitry Andric if (!section_ptr) 2180b57cec5SDimitry Andric return false; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric stream.PutMaxHex64(section_ptr->GetFileAddress() + offset, 2210b57cec5SDimitry Andric stream.GetAddressByteSize(), stream.GetByteOrder()); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric return true; 2240b57cec5SDimitry Andric }); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric DWARFExpression lldb_private::npdb::MakeConstantLocationExpression( 2280b57cec5SDimitry Andric TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant, 2290b57cec5SDimitry Andric ModuleSP module) { 2300b57cec5SDimitry Andric const ArchSpec &architecture = module->GetArchitecture(); 2310b57cec5SDimitry Andric uint32_t address_size = architecture.GetAddressByteSize(); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric size_t size = 0; 2340b57cec5SDimitry Andric bool is_signed = false; 2350b57cec5SDimitry Andric std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric union { 2380b57cec5SDimitry Andric llvm::support::little64_t I; 2390b57cec5SDimitry Andric llvm::support::ulittle64_t U; 2400b57cec5SDimitry Andric } Value; 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>(); 2430b57cec5SDimitry Andric buffer->SetByteSize(size); 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric llvm::ArrayRef<uint8_t> bytes; 2460b57cec5SDimitry Andric if (is_signed) { 2470b57cec5SDimitry Andric Value.I = constant.getSExtValue(); 2480b57cec5SDimitry Andric } else { 2490b57cec5SDimitry Andric Value.U = constant.getZExtValue(); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 252bdd1243dSDimitry Andric bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8) 2530b57cec5SDimitry Andric .take_front(size); 2540b57cec5SDimitry Andric buffer->CopyData(bytes.data(), size); 2550b57cec5SDimitry Andric DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size); 256753f127fSDimitry Andric DWARFExpression result(extractor); 2570b57cec5SDimitry Andric return result; 2580b57cec5SDimitry Andric } 25981ad6265SDimitry Andric 260bdd1243dSDimitry Andric DWARFExpression 261bdd1243dSDimitry Andric lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite( 262bdd1243dSDimitry Andric const std::map<uint64_t, MemberValLocation> &offset_to_location, 263bdd1243dSDimitry Andric std::map<uint64_t, size_t> &offset_to_size, size_t total_size, 26481ad6265SDimitry Andric lldb::ModuleSP module) { 26581ad6265SDimitry Andric return MakeLocationExpressionInternal( 26681ad6265SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { 267bdd1243dSDimitry Andric size_t cur_offset = 0; 268bdd1243dSDimitry Andric bool is_simple_type = offset_to_size.empty(); 269bdd1243dSDimitry Andric // Iterate through offset_to_location because offset_to_size might be 270bdd1243dSDimitry Andric // empty if the variable is a simple type. 271bdd1243dSDimitry Andric for (const auto &offset_loc : offset_to_location) { 272bdd1243dSDimitry Andric if (cur_offset < offset_loc.first) { 27381ad6265SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece); 274bdd1243dSDimitry Andric stream.PutULEB128(offset_loc.first - cur_offset); 275bdd1243dSDimitry Andric cur_offset = offset_loc.first; 276bdd1243dSDimitry Andric } 277bdd1243dSDimitry Andric MemberValLocation loc = offset_loc.second; 278bdd1243dSDimitry Andric std::optional<int32_t> offset = 279bdd1243dSDimitry Andric loc.is_at_reg ? std::nullopt 280bdd1243dSDimitry Andric : std::optional<int32_t>(loc.reg_offset); 281bdd1243dSDimitry Andric if (!MakeRegisterBasedLocationExpressionInternal( 282bdd1243dSDimitry Andric stream, (RegisterId)loc.reg_id, register_kind, offset, 283bdd1243dSDimitry Andric module)) 284bdd1243dSDimitry Andric return false; 285bdd1243dSDimitry Andric if (!is_simple_type) { 286bdd1243dSDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece); 287bdd1243dSDimitry Andric stream.PutULEB128(offset_to_size[offset_loc.first]); 288bdd1243dSDimitry Andric cur_offset = offset_loc.first + offset_to_size[offset_loc.first]; 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric } 291bdd1243dSDimitry Andric // For simple type, it specifies the byte size of the value described by 292bdd1243dSDimitry Andric // the previous dwarf expr. For udt, it's the remaining byte size at end 293bdd1243dSDimitry Andric // of a struct. 294bdd1243dSDimitry Andric if (total_size > cur_offset) { 295bdd1243dSDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece); 296bdd1243dSDimitry Andric stream.PutULEB128(total_size - cur_offset); 29781ad6265SDimitry Andric } 29881ad6265SDimitry Andric return true; 29981ad6265SDimitry Andric }); 30081ad6265SDimitry Andric } 301