301 lines · cpp
1//===-- DWARFLocationExpression.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "DWARFLocationExpression.h"10 11#include "lldb/Core/Module.h"12#include "lldb/Core/Section.h"13#include "lldb/Expression/DWARFExpression.h"14#include "lldb/Utility/ArchSpec.h"15#include "lldb/Utility/DataBufferHeap.h"16#include "lldb/Utility/StreamBuffer.h"17 18#include "llvm/BinaryFormat/Dwarf.h"19#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"20#include "llvm/DebugInfo/CodeView/TypeIndex.h"21#include "llvm/DebugInfo/PDB/Native/TpiStream.h"22#include "llvm/Support/Endian.h"23 24#include "PdbUtil.h"25#include "CodeViewRegisterMapping.h"26#include "PdbFPOProgramToDWARFExpression.h"27#include <optional>28 29using namespace lldb;30using namespace lldb_private;31using namespace lldb_private::npdb;32using namespace llvm::codeview;33using namespace llvm::pdb;34 35uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {36 if (register_id == llvm::codeview::RegisterId::VFRAME)37 return LLDB_REGNUM_GENERIC_FP;38 39 return LLDB_INVALID_REGNUM;40}41 42static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,43 llvm::codeview::RegisterId register_id,44 RegisterKind ®ister_kind) {45 register_kind = eRegisterKindLLDB;46 uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);47 if (reg_num != LLDB_INVALID_REGNUM)48 return reg_num;49 50 register_kind = eRegisterKindGeneric;51 return GetGenericRegisterNumber(register_id);52}53 54static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {55 switch (kind) {56 case SimpleTypeKind::Int128:57 case SimpleTypeKind::Int64:58 case SimpleTypeKind::Int64Quad:59 case SimpleTypeKind::Int32:60 case SimpleTypeKind::Int32Long:61 case SimpleTypeKind::Int16:62 case SimpleTypeKind::Int16Short:63 case SimpleTypeKind::Float128:64 case SimpleTypeKind::Float80:65 case SimpleTypeKind::Float64:66 case SimpleTypeKind::Float32:67 case SimpleTypeKind::Float16:68 case SimpleTypeKind::NarrowCharacter:69 case SimpleTypeKind::SignedCharacter:70 case SimpleTypeKind::SByte:71 return true;72 default:73 return false;74 }75}76 77static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,78 TpiStream &tpi) {79 if (ti.isSimple()) {80 SimpleTypeKind stk = ti.getSimpleKind();81 return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};82 }83 84 CVType cvt = tpi.getType(ti);85 switch (cvt.kind()) {86 case LF_MODIFIER: {87 ModifierRecord mfr;88 llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));89 return GetIntegralTypeInfo(mfr.ModifiedType, tpi);90 }91 case LF_POINTER: {92 PointerRecord pr;93 llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));94 return GetIntegralTypeInfo(pr.ReferentType, tpi);95 }96 case LF_ENUM: {97 EnumRecord er;98 llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));99 return GetIntegralTypeInfo(er.UnderlyingType, tpi);100 }101 default:102 assert(false && "Type is not integral!");103 return {0, false};104 }105}106 107template <typename StreamWriter>108static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,109 StreamWriter &&writer) {110 const ArchSpec &architecture = module->GetArchitecture();111 ByteOrder byte_order = architecture.GetByteOrder();112 uint32_t address_size = architecture.GetAddressByteSize();113 uint32_t byte_size = architecture.GetDataByteSize();114 if (byte_order == eByteOrderInvalid || address_size == 0)115 return DWARFExpression();116 117 RegisterKind register_kind = eRegisterKindDWARF;118 StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);119 120 if (!writer(stream, register_kind))121 return DWARFExpression();122 123 DataBufferSP buffer =124 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());125 DataExtractor extractor(buffer, byte_order, address_size, byte_size);126 DWARFExpression result(extractor);127 result.SetRegisterKind(register_kind);128 129 return result;130}131 132static bool MakeRegisterBasedLocationExpressionInternal(133 Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind,134 std::optional<int32_t> relative_offset, lldb::ModuleSP module) {135 uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),136 reg, register_kind);137 if (reg_num == LLDB_INVALID_REGNUM)138 return false;139 140 if (reg_num > 31) {141 llvm::dwarf::LocationAtom base =142 relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;143 stream.PutHex8(base);144 stream.PutULEB128(reg_num);145 } else {146 llvm::dwarf::LocationAtom base =147 relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;148 stream.PutHex8(base + reg_num);149 }150 151 if (relative_offset)152 stream.PutSLEB128(*relative_offset);153 154 return true;155}156 157static DWARFExpression MakeRegisterBasedLocationExpressionInternal(158 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,159 lldb::ModuleSP module) {160 return MakeLocationExpressionInternal(161 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {162 return MakeRegisterBasedLocationExpressionInternal(163 stream, reg, register_kind, relative_offset, module);164 });165}166 167DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(168 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {169 return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);170}171 172DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(173 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {174 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);175}176 177static bool EmitVFrameEvaluationDWARFExpression(178 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {179 // VFrame value always stored in $TO pseudo-register180 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,181 stream);182}183 184DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(185 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {186 return MakeLocationExpressionInternal(187 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {188 const ArchSpec &architecture = module->GetArchitecture();189 190 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),191 stream))192 return false;193 194 stream.PutHex8(llvm::dwarf::DW_OP_consts);195 stream.PutSLEB128(offset);196 stream.PutHex8(llvm::dwarf::DW_OP_plus);197 198 register_kind = eRegisterKindLLDB;199 200 return true;201 });202}203 204DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(205 uint16_t section, uint32_t offset, ModuleSP module) {206 assert(section > 0);207 assert(module);208 209 return MakeLocationExpressionInternal(210 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {211 stream.PutHex8(llvm::dwarf::DW_OP_addr);212 213 SectionList *section_list = module->GetSectionList();214 assert(section_list);215 216 auto section_ptr = section_list->FindSectionByID(section);217 if (!section_ptr)218 return false;219 220 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,221 stream.GetAddressByteSize(), stream.GetByteOrder());222 223 return true;224 });225}226 227DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(228 TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,229 ModuleSP module) {230 const ArchSpec &architecture = module->GetArchitecture();231 uint32_t address_size = architecture.GetAddressByteSize();232 233 size_t size = 0;234 bool is_signed = false;235 std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);236 237 union {238 llvm::support::little64_t I;239 llvm::support::ulittle64_t U;240 } Value;241 242 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();243 buffer->SetByteSize(size);244 245 llvm::ArrayRef<uint8_t> bytes;246 if (is_signed) {247 Value.I = constant.getSExtValue();248 } else {249 Value.U = constant.getZExtValue();250 }251 252 bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)253 .take_front(size);254 buffer->CopyData(bytes.data(), size);255 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);256 DWARFExpression result(extractor);257 return result;258}259 260DWARFExpression261lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(262 const std::map<uint64_t, MemberValLocation> &offset_to_location,263 std::map<uint64_t, size_t> &offset_to_size, size_t total_size,264 lldb::ModuleSP module) {265 return MakeLocationExpressionInternal(266 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {267 size_t cur_offset = 0;268 bool is_simple_type = offset_to_size.empty();269 // Iterate through offset_to_location because offset_to_size might be270 // empty if the variable is a simple type.271 for (const auto &offset_loc : offset_to_location) {272 if (cur_offset < offset_loc.first) {273 stream.PutHex8(llvm::dwarf::DW_OP_piece);274 stream.PutULEB128(offset_loc.first - cur_offset);275 cur_offset = offset_loc.first;276 }277 MemberValLocation loc = offset_loc.second;278 std::optional<int32_t> offset =279 loc.is_at_reg ? std::nullopt280 : std::optional<int32_t>(loc.reg_offset);281 if (!MakeRegisterBasedLocationExpressionInternal(282 stream, (RegisterId)loc.reg_id, register_kind, offset,283 module))284 return false;285 if (!is_simple_type) {286 stream.PutHex8(llvm::dwarf::DW_OP_piece);287 stream.PutULEB128(offset_to_size[offset_loc.first]);288 cur_offset = offset_loc.first + offset_to_size[offset_loc.first];289 }290 }291 // For simple type, it specifies the byte size of the value described by292 // the previous dwarf expr. For udt, it's the remaining byte size at end293 // of a struct.294 if (total_size > cur_offset) {295 stream.PutHex8(llvm::dwarf::DW_OP_piece);296 stream.PutULEB128(total_size - cur_offset);297 }298 return true;299 });300}301