1dda28197Spatrick //===-- DWARFLocationExpression.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "DWARFLocationExpression.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/Section.h"
13061da546Spatrick #include "lldb/Core/StreamBuffer.h"
14061da546Spatrick #include "lldb/Expression/DWARFExpression.h"
15061da546Spatrick #include "lldb/Utility/ArchSpec.h"
16061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
17061da546Spatrick
18061da546Spatrick #include "llvm/BinaryFormat/Dwarf.h"
19061da546Spatrick #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20061da546Spatrick #include "llvm/DebugInfo/CodeView/TypeIndex.h"
21061da546Spatrick #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22061da546Spatrick #include "llvm/Support/Endian.h"
23061da546Spatrick
24061da546Spatrick #include "PdbUtil.h"
25061da546Spatrick #include "CodeViewRegisterMapping.h"
26061da546Spatrick #include "PdbFPOProgramToDWARFExpression.h"
27*f6aab3d8Srobert #include <optional>
28061da546Spatrick
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick using namespace lldb_private::npdb;
32061da546Spatrick using namespace llvm::codeview;
33061da546Spatrick using namespace llvm::pdb;
34061da546Spatrick
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)35061da546Spatrick uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
36061da546Spatrick if (register_id == llvm::codeview::RegisterId::VFRAME)
37061da546Spatrick return LLDB_REGNUM_GENERIC_FP;
38061da546Spatrick
39061da546Spatrick return LLDB_INVALID_REGNUM;
40061da546Spatrick }
41061da546Spatrick
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)42061da546Spatrick static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
43061da546Spatrick llvm::codeview::RegisterId register_id,
44061da546Spatrick RegisterKind ®ister_kind) {
45061da546Spatrick register_kind = eRegisterKindLLDB;
46061da546Spatrick uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
47061da546Spatrick if (reg_num != LLDB_INVALID_REGNUM)
48061da546Spatrick return reg_num;
49061da546Spatrick
50061da546Spatrick register_kind = eRegisterKindGeneric;
51061da546Spatrick return GetGenericRegisterNumber(register_id);
52061da546Spatrick }
53061da546Spatrick
IsSimpleTypeSignedInteger(SimpleTypeKind kind)54061da546Spatrick static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
55061da546Spatrick switch (kind) {
56061da546Spatrick case SimpleTypeKind::Int128:
57061da546Spatrick case SimpleTypeKind::Int64:
58061da546Spatrick case SimpleTypeKind::Int64Quad:
59061da546Spatrick case SimpleTypeKind::Int32:
60061da546Spatrick case SimpleTypeKind::Int32Long:
61061da546Spatrick case SimpleTypeKind::Int16:
62061da546Spatrick case SimpleTypeKind::Int16Short:
63061da546Spatrick case SimpleTypeKind::Float128:
64061da546Spatrick case SimpleTypeKind::Float80:
65061da546Spatrick case SimpleTypeKind::Float64:
66061da546Spatrick case SimpleTypeKind::Float32:
67061da546Spatrick case SimpleTypeKind::Float16:
68061da546Spatrick case SimpleTypeKind::NarrowCharacter:
69061da546Spatrick case SimpleTypeKind::SignedCharacter:
70061da546Spatrick case SimpleTypeKind::SByte:
71061da546Spatrick return true;
72061da546Spatrick default:
73061da546Spatrick return false;
74061da546Spatrick }
75061da546Spatrick }
76061da546Spatrick
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)77061da546Spatrick static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78061da546Spatrick TpiStream &tpi) {
79061da546Spatrick if (ti.isSimple()) {
80061da546Spatrick SimpleTypeKind stk = ti.getSimpleKind();
81061da546Spatrick return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
82061da546Spatrick }
83061da546Spatrick
84061da546Spatrick CVType cvt = tpi.getType(ti);
85061da546Spatrick switch (cvt.kind()) {
86061da546Spatrick case LF_MODIFIER: {
87061da546Spatrick ModifierRecord mfr;
88061da546Spatrick llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
89061da546Spatrick return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
90061da546Spatrick }
91061da546Spatrick case LF_POINTER: {
92061da546Spatrick PointerRecord pr;
93061da546Spatrick llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
94061da546Spatrick return GetIntegralTypeInfo(pr.ReferentType, tpi);
95061da546Spatrick }
96061da546Spatrick case LF_ENUM: {
97061da546Spatrick EnumRecord er;
98061da546Spatrick llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
99061da546Spatrick return GetIntegralTypeInfo(er.UnderlyingType, tpi);
100061da546Spatrick }
101061da546Spatrick default:
102061da546Spatrick assert(false && "Type is not integral!");
103061da546Spatrick return {0, false};
104061da546Spatrick }
105061da546Spatrick }
106061da546Spatrick
107061da546Spatrick template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)108061da546Spatrick static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
109061da546Spatrick StreamWriter &&writer) {
110061da546Spatrick const ArchSpec &architecture = module->GetArchitecture();
111061da546Spatrick ByteOrder byte_order = architecture.GetByteOrder();
112061da546Spatrick uint32_t address_size = architecture.GetAddressByteSize();
113061da546Spatrick uint32_t byte_size = architecture.GetDataByteSize();
114061da546Spatrick if (byte_order == eByteOrderInvalid || address_size == 0)
115061da546Spatrick return DWARFExpression();
116061da546Spatrick
117061da546Spatrick RegisterKind register_kind = eRegisterKindDWARF;
118061da546Spatrick StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
119061da546Spatrick
120061da546Spatrick if (!writer(stream, register_kind))
121061da546Spatrick return DWARFExpression();
122061da546Spatrick
123061da546Spatrick DataBufferSP buffer =
124061da546Spatrick std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
125061da546Spatrick DataExtractor extractor(buffer, byte_order, address_size, byte_size);
126*f6aab3d8Srobert DWARFExpression result(extractor);
127061da546Spatrick result.SetRegisterKind(register_kind);
128061da546Spatrick
129061da546Spatrick return result;
130061da546Spatrick }
131061da546Spatrick
MakeRegisterBasedLocationExpressionInternal(Stream & stream,llvm::codeview::RegisterId reg,RegisterKind & register_kind,std::optional<int32_t> relative_offset,lldb::ModuleSP module)132*f6aab3d8Srobert static bool MakeRegisterBasedLocationExpressionInternal(
133*f6aab3d8Srobert Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind,
134*f6aab3d8Srobert std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135*f6aab3d8Srobert uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136*f6aab3d8Srobert reg, register_kind);
137061da546Spatrick if (reg_num == LLDB_INVALID_REGNUM)
138061da546Spatrick return false;
139061da546Spatrick
140061da546Spatrick if (reg_num > 31) {
141*f6aab3d8Srobert llvm::dwarf::LocationAtom base =
142*f6aab3d8Srobert relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
143061da546Spatrick stream.PutHex8(base);
144061da546Spatrick stream.PutULEB128(reg_num);
145061da546Spatrick } else {
146*f6aab3d8Srobert llvm::dwarf::LocationAtom base =
147*f6aab3d8Srobert relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
148061da546Spatrick stream.PutHex8(base + reg_num);
149061da546Spatrick }
150061da546Spatrick
151061da546Spatrick if (relative_offset)
152061da546Spatrick stream.PutSLEB128(*relative_offset);
153061da546Spatrick
154061da546Spatrick return true;
155*f6aab3d8Srobert }
156*f6aab3d8Srobert
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,std::optional<int32_t> relative_offset,lldb::ModuleSP module)157*f6aab3d8Srobert static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158*f6aab3d8Srobert llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159*f6aab3d8Srobert lldb::ModuleSP module) {
160*f6aab3d8Srobert return MakeLocationExpressionInternal(
161*f6aab3d8Srobert module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
162*f6aab3d8Srobert return MakeRegisterBasedLocationExpressionInternal(
163*f6aab3d8Srobert stream, reg, register_kind, relative_offset, module);
164061da546Spatrick });
165061da546Spatrick }
166061da546Spatrick
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)167061da546Spatrick DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
168061da546Spatrick llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169*f6aab3d8Srobert return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
170061da546Spatrick }
171061da546Spatrick
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)172061da546Spatrick DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
173061da546Spatrick llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
174061da546Spatrick return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
175061da546Spatrick }
176061da546Spatrick
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)177061da546Spatrick static bool EmitVFrameEvaluationDWARFExpression(
178061da546Spatrick llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
179061da546Spatrick // VFrame value always stored in $TO pseudo-register
180061da546Spatrick return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
181061da546Spatrick stream);
182061da546Spatrick }
183061da546Spatrick
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)184061da546Spatrick DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
185061da546Spatrick llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186061da546Spatrick return MakeLocationExpressionInternal(
187061da546Spatrick module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
188061da546Spatrick const ArchSpec &architecture = module->GetArchitecture();
189061da546Spatrick
190061da546Spatrick if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
191061da546Spatrick stream))
192061da546Spatrick return false;
193061da546Spatrick
194061da546Spatrick stream.PutHex8(llvm::dwarf::DW_OP_consts);
195061da546Spatrick stream.PutSLEB128(offset);
196061da546Spatrick stream.PutHex8(llvm::dwarf::DW_OP_plus);
197061da546Spatrick
198061da546Spatrick register_kind = eRegisterKindLLDB;
199061da546Spatrick
200061da546Spatrick return true;
201061da546Spatrick });
202061da546Spatrick }
203061da546Spatrick
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)204061da546Spatrick DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
205061da546Spatrick uint16_t section, uint32_t offset, ModuleSP module) {
206061da546Spatrick assert(section > 0);
207061da546Spatrick assert(module);
208061da546Spatrick
209061da546Spatrick return MakeLocationExpressionInternal(
210061da546Spatrick module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
211061da546Spatrick stream.PutHex8(llvm::dwarf::DW_OP_addr);
212061da546Spatrick
213061da546Spatrick SectionList *section_list = module->GetSectionList();
214061da546Spatrick assert(section_list);
215061da546Spatrick
216061da546Spatrick auto section_ptr = section_list->FindSectionByID(section);
217061da546Spatrick if (!section_ptr)
218061da546Spatrick return false;
219061da546Spatrick
220061da546Spatrick stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
221061da546Spatrick stream.GetAddressByteSize(), stream.GetByteOrder());
222061da546Spatrick
223061da546Spatrick return true;
224061da546Spatrick });
225061da546Spatrick }
226061da546Spatrick
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)227061da546Spatrick DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
228061da546Spatrick TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
229061da546Spatrick ModuleSP module) {
230061da546Spatrick const ArchSpec &architecture = module->GetArchitecture();
231061da546Spatrick uint32_t address_size = architecture.GetAddressByteSize();
232061da546Spatrick
233061da546Spatrick size_t size = 0;
234061da546Spatrick bool is_signed = false;
235061da546Spatrick std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
236061da546Spatrick
237061da546Spatrick union {
238061da546Spatrick llvm::support::little64_t I;
239061da546Spatrick llvm::support::ulittle64_t U;
240061da546Spatrick } Value;
241061da546Spatrick
242061da546Spatrick std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
243061da546Spatrick buffer->SetByteSize(size);
244061da546Spatrick
245061da546Spatrick llvm::ArrayRef<uint8_t> bytes;
246061da546Spatrick if (is_signed) {
247061da546Spatrick Value.I = constant.getSExtValue();
248061da546Spatrick } else {
249061da546Spatrick Value.U = constant.getZExtValue();
250061da546Spatrick }
251061da546Spatrick
252*f6aab3d8Srobert bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
253061da546Spatrick .take_front(size);
254061da546Spatrick buffer->CopyData(bytes.data(), size);
255061da546Spatrick DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256*f6aab3d8Srobert DWARFExpression result(extractor);
257061da546Spatrick return result;
258061da546Spatrick }
259*f6aab3d8Srobert
260*f6aab3d8Srobert DWARFExpression
MakeEnregisteredLocationExpressionForComposite(const std::map<uint64_t,MemberValLocation> & offset_to_location,std::map<uint64_t,size_t> & offset_to_size,size_t total_size,lldb::ModuleSP module)261*f6aab3d8Srobert lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262*f6aab3d8Srobert const std::map<uint64_t, MemberValLocation> &offset_to_location,
263*f6aab3d8Srobert std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
264*f6aab3d8Srobert lldb::ModuleSP module) {
265*f6aab3d8Srobert return MakeLocationExpressionInternal(
266*f6aab3d8Srobert module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
267*f6aab3d8Srobert size_t cur_offset = 0;
268*f6aab3d8Srobert bool is_simple_type = offset_to_size.empty();
269*f6aab3d8Srobert // Iterate through offset_to_location because offset_to_size might be
270*f6aab3d8Srobert // empty if the variable is a simple type.
271*f6aab3d8Srobert for (const auto &offset_loc : offset_to_location) {
272*f6aab3d8Srobert if (cur_offset < offset_loc.first) {
273*f6aab3d8Srobert stream.PutHex8(llvm::dwarf::DW_OP_piece);
274*f6aab3d8Srobert stream.PutULEB128(offset_loc.first - cur_offset);
275*f6aab3d8Srobert cur_offset = offset_loc.first;
276*f6aab3d8Srobert }
277*f6aab3d8Srobert MemberValLocation loc = offset_loc.second;
278*f6aab3d8Srobert std::optional<int32_t> offset =
279*f6aab3d8Srobert loc.is_at_reg ? std::nullopt
280*f6aab3d8Srobert : std::optional<int32_t>(loc.reg_offset);
281*f6aab3d8Srobert if (!MakeRegisterBasedLocationExpressionInternal(
282*f6aab3d8Srobert stream, (RegisterId)loc.reg_id, register_kind, offset,
283*f6aab3d8Srobert module))
284*f6aab3d8Srobert return false;
285*f6aab3d8Srobert if (!is_simple_type) {
286*f6aab3d8Srobert stream.PutHex8(llvm::dwarf::DW_OP_piece);
287*f6aab3d8Srobert stream.PutULEB128(offset_to_size[offset_loc.first]);
288*f6aab3d8Srobert cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289*f6aab3d8Srobert }
290*f6aab3d8Srobert }
291*f6aab3d8Srobert // For simple type, it specifies the byte size of the value described by
292*f6aab3d8Srobert // the previous dwarf expr. For udt, it's the remaining byte size at end
293*f6aab3d8Srobert // of a struct.
294*f6aab3d8Srobert if (total_size > cur_offset) {
295*f6aab3d8Srobert stream.PutHex8(llvm::dwarf::DW_OP_piece);
296*f6aab3d8Srobert stream.PutULEB128(total_size - cur_offset);
297*f6aab3d8Srobert }
298*f6aab3d8Srobert return true;
299*f6aab3d8Srobert });
300*f6aab3d8Srobert }
301