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