LLDB mainline
DWARFLocationExpression.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "lldb/Core/Module.h"
12#include "lldb/Core/Section.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"
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)
38
40}
41
42static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
43 llvm::codeview::RegisterId register_id,
44 RegisterKind &register_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 llvm::Expected<std::pair<size_t, bool>>
78GetIntegralTypeInfo(TypeIndex ti, TpiStream &tpi) {
79 if (ti.isSimple()) {
80 SimpleTypeKind stk = ti.getSimpleKind();
81 return std::make_pair(GetTypeSizeForSimpleKind(stk),
83 }
84
85 CVType cvt = tpi.getType(ti);
86 switch (cvt.kind()) {
87 case LF_MODIFIER: {
88 ModifierRecord mfr;
89 if (auto err = TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr))
90 return std::move(err);
91 return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
92 }
93 case LF_POINTER: {
94 PointerRecord pr;
95 if (auto err = TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr))
96 return std::move(err);
97 return std::make_pair(pr.getSize(), false);
98 }
99 case LF_ENUM: {
100 EnumRecord er;
101 if (auto err = TypeDeserializer::deserializeAs<EnumRecord>(cvt, er))
102 return std::move(err);
103 return GetIntegralTypeInfo(er.UnderlyingType, tpi);
104 }
105 default:
106 return llvm::make_error<llvm::StringError>("Type is not integral",
107 llvm::inconvertibleErrorCode());
108 }
109}
110
111template <typename StreamWriter>
113 StreamWriter &&writer) {
114 const ArchSpec &architecture = module->GetArchitecture();
115 ByteOrder byte_order = architecture.GetByteOrder();
116 uint32_t address_size = architecture.GetAddressByteSize();
117 if (byte_order == eByteOrderInvalid || address_size == 0)
118 return DWARFExpression();
119
120 RegisterKind register_kind = eRegisterKindDWARF;
121 StreamBuffer<32> stream(Stream::eBinary, byte_order);
122
123 if (!writer(stream, register_kind))
124 return DWARFExpression();
125
126 DataBufferSP buffer =
127 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
128 DataExtractor extractor(buffer, byte_order, address_size);
129 DWARFExpression result(extractor);
130 result.SetRegisterKind(register_kind);
131
132 return result;
133}
134
136 Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
137 std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
138 uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
139 reg, register_kind);
140 if (reg_num == LLDB_INVALID_REGNUM)
141 return false;
142
143 if (reg_num > 31) {
144 llvm::dwarf::LocationAtom base =
145 relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
146 stream.PutHex8(base);
147 stream.PutULEB128(reg_num);
148 } else {
149 llvm::dwarf::LocationAtom base =
150 relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
151 stream.PutHex8(base + reg_num);
152 }
153
154 if (relative_offset)
155 stream.PutSLEB128(*relative_offset);
156
157 return true;
158}
159
160/// *(reg + indir_offset) + offset
162 Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
163 int32_t indir_offset, int32_t offset, lldb::ModuleSP module) {
164 if (!MakeRegisterBasedLocationExpressionInternal(stream, reg, register_kind,
165 indir_offset, module))
166 return false;
167
168 stream.PutHex8(llvm::dwarf::DW_OP_deref);
169 stream.PutHex8(llvm::dwarf::DW_OP_consts);
170 stream.PutSLEB128(offset);
171 stream.PutHex8(llvm::dwarf::DW_OP_plus);
172
173 return true;
174}
175
177 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
178 lldb::ModuleSP module) {
180 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
182 stream, reg, register_kind, relative_offset, module);
183 });
184}
185
187 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
188 return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
189}
190
192 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
193 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
194}
195
197 llvm::codeview::RegisterId reg, int32_t offset, int32_t offset_in_udt,
198 lldb::ModuleSP module) {
200 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
202 stream, reg, register_kind, offset, offset_in_udt, module);
203 });
204}
205
207 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
208 // VFrame value always stored in $TO pseudo-register
209 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
210 stream);
211}
212
214 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
216 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
217 const ArchSpec &architecture = module->GetArchitecture();
218
219 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
220 stream))
221 return false;
222
223 stream.PutHex8(llvm::dwarf::DW_OP_consts);
224 stream.PutSLEB128(offset);
225 stream.PutHex8(llvm::dwarf::DW_OP_plus);
226
227 register_kind = eRegisterKindLLDB;
228
229 return true;
230 });
231}
232
234 llvm::StringRef fpo_program, int32_t offset, int32_t offset_in_udt,
235 lldb::ModuleSP module) {
237 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
238 const ArchSpec &architecture = module->GetArchitecture();
239
241 fpo_program, architecture.GetMachine(), stream))
242 return false;
243
244 stream.PutHex8(llvm::dwarf::DW_OP_consts);
245 stream.PutSLEB128(offset);
246 stream.PutHex8(llvm::dwarf::DW_OP_plus);
247 stream.PutHex8(llvm::dwarf::DW_OP_deref);
248 stream.PutHex8(llvm::dwarf::DW_OP_consts);
249 stream.PutSLEB128(offset_in_udt);
250 stream.PutHex8(llvm::dwarf::DW_OP_plus);
251
252 register_kind = eRegisterKindLLDB;
253
254 return true;
255 });
256}
257
259 uint16_t section, uint32_t offset, ModuleSP module) {
260 assert(section > 0);
261 assert(module);
262
264 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
265 stream.PutHex8(llvm::dwarf::DW_OP_addr);
266
267 SectionList *section_list = module->GetSectionList();
268 assert(section_list);
269
270 auto section_ptr = section_list->FindSectionByID(section);
271 if (!section_ptr)
272 return false;
273
274 const ArchSpec &arch = module->GetArchitecture();
275 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
276 arch.GetAddressByteSize(), arch.GetByteOrder());
277
278 return true;
279 });
280}
281
282llvm::Expected<DWARFExpression>
284 TpiStream &tpi,
285 const llvm::APSInt &constant,
286 ModuleSP module) {
287 const ArchSpec &architecture = module->GetArchitecture();
288 uint32_t address_size = architecture.GetAddressByteSize();
289
290 auto type_info = GetIntegralTypeInfo(underlying_ti, tpi);
291 if (!type_info)
292 return type_info.takeError();
293 auto [size, is_signed] = *type_info;
294
295 union {
296 llvm::support::little64_t I;
297 llvm::support::ulittle64_t U;
298 } Value;
299
300 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
301 buffer->SetByteSize(size);
302
303 llvm::ArrayRef<uint8_t> bytes;
304 if (is_signed) {
305 Value.I = constant.getSExtValue();
306 } else {
307 Value.U = constant.getZExtValue();
308 }
309
310 bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
311 .take_front(size);
312 buffer->CopyData(bytes.data(), size);
313 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
314 DWARFExpression result(extractor);
315 return result;
316}
317
320 const std::map<uint64_t, MemberValLocation> &offset_to_location,
321 std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
322 lldb::ModuleSP module) {
324 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
325 size_t cur_offset = 0;
326 bool is_simple_type = offset_to_size.empty();
327 // Iterate through offset_to_location because offset_to_size might be
328 // empty if the variable is a simple type.
329 for (const auto &offset_loc : offset_to_location) {
330 if (cur_offset < offset_loc.first) {
331 stream.PutHex8(llvm::dwarf::DW_OP_piece);
332 stream.PutULEB128(offset_loc.first - cur_offset);
333 cur_offset = offset_loc.first;
334 }
335 MemberValLocation loc = offset_loc.second;
336 std::optional<int32_t> offset =
337 loc.is_at_reg ? std::nullopt
338 : std::optional<int32_t>(loc.reg_offset);
340 stream, (RegisterId)loc.reg_id, register_kind, offset,
341 module))
342 return false;
343 if (!is_simple_type) {
344 stream.PutHex8(llvm::dwarf::DW_OP_piece);
345 stream.PutULEB128(offset_to_size[offset_loc.first]);
346 cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
347 }
348 }
349 // For simple type, it specifies the byte size of the value described by
350 // the previous dwarf expr. For udt, it's the remaining byte size at end
351 // of a struct.
352 if (total_size > cur_offset) {
353 stream.PutHex8(llvm::dwarf::DW_OP_piece);
354 stream.PutULEB128(total_size - cur_offset);
355 }
356 return true;
357 });
358}
static bool EmitVFrameEvaluationDWARFExpression(llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream)
uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)
static bool MakeRegisterBasedLocationExpressionInternal(Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind, std::optional< int32_t > relative_offset, lldb::ModuleSP module)
static llvm::Expected< std::pair< size_t, bool > > GetIntegralTypeInfo(TypeIndex ti, TpiStream &tpi)
static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id, RegisterKind &register_kind)
static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind)
static bool MakeRegisterBasedIndirectLocationExpressionInternal(Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind, int32_t indir_offset, int32_t offset, lldb::ModuleSP module)
*(reg + indir_offset) + offset
static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module, StreamWriter &&writer)
An architecture specification class.
Definition ArchSpec.h:32
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition ArchSpec.cpp:681
lldb::ByteOrder GetByteOrder() const
Returns the byte order for the architecture specification.
Definition ArchSpec.cpp:730
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition ArchSpec.cpp:673
"lldb/Expression/DWARFExpression.h" Encapsulates a DWARF location expression and interprets it.
void SetRegisterKind(lldb::RegisterKind reg_kind)
Set the call-frame-info style register kind.
An data extractor class.
lldb::SectionSP FindSectionByID(lldb::user_id_t sect_id) const
Definition Section.cpp:578
const char * GetData() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t size_t PutHex8(uint8_t uvalue)
Append an uint8_t value in the hexadecimal format to the stream.
Definition Stream.cpp:267
@ eBinary
Get and put data as binary instead of as the default string mode.
Definition Stream.h:32
size_t PutULEB128(uint64_t uval)
Output a ULEB128 number to the stream.
Definition Stream.cpp:55
size_t PutSLEB128(int64_t uval)
Output a SLEB128 number to the stream.
Definition Stream.cpp:47
size_t PutMaxHex64(uint64_t uvalue, size_t byte_size, lldb::ByteOrder byte_order=lldb::eByteOrderInvalid)
Definition Stream.cpp:321
#define LLDB_INVALID_REGNUM
#define LLDB_REGNUM_GENERIC_FP
DWARFExpression MakeRegRelIndirLocationExpression(llvm::codeview::RegisterId reg, int32_t offset, int32_t offset_in_udt, lldb::ModuleSP module)
DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module)
size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind)
DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module)
DWARFExpression MakeVFrameRelIndirLocationExpression(llvm::StringRef fpo_program, int32_t offset, int32_t offset_in_udt, lldb::ModuleSP module)
llvm::Expected< DWARFExpression > MakeConstantLocationExpression(llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi, const llvm::APSInt &constant, lldb::ModuleSP module)
bool TranslateFPOProgramToDWARFExpression(llvm::StringRef program, llvm::StringRef register_name, llvm::Triple::ArchType arch_type, lldb_private::Stream &stream)
DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset, lldb::ModuleSP module)
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)
DWARFExpression MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg, lldb::ModuleSP module)
uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id)
A class that represents a running process on the host machine.
ByteOrder
Byte ordering definitions.
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Module > ModuleSP
RegisterKind
Register numbering types.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
@ eRegisterKindLLDB
lldb's internal register numbers
@ eRegisterKindDWARF
the register numbers seen DWARF