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, address_size, 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_plus_uconst);
170 stream.PutSLEB128(offset);
171
172 return true;
173}
174
176 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
177 lldb::ModuleSP module) {
179 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
181 stream, reg, register_kind, relative_offset, module);
182 });
183}
184
186 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
187 return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
188}
189
191 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
192 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
193}
194
196 llvm::codeview::RegisterId reg, int32_t offset, int32_t offset_in_udt,
197 lldb::ModuleSP module) {
199 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
201 stream, reg, register_kind, offset, offset_in_udt, module);
202 });
203}
204
206 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
207 // VFrame value always stored in $TO pseudo-register
208 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
209 stream);
210}
211
213 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
215 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
216 const ArchSpec &architecture = module->GetArchitecture();
217
218 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
219 stream))
220 return false;
221
222 stream.PutHex8(llvm::dwarf::DW_OP_consts);
223 stream.PutSLEB128(offset);
224 stream.PutHex8(llvm::dwarf::DW_OP_plus);
225
226 register_kind = eRegisterKindLLDB;
227
228 return true;
229 });
230}
231
233 uint16_t section, uint32_t offset, ModuleSP module) {
234 assert(section > 0);
235 assert(module);
236
238 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
239 stream.PutHex8(llvm::dwarf::DW_OP_addr);
240
241 SectionList *section_list = module->GetSectionList();
242 assert(section_list);
243
244 auto section_ptr = section_list->FindSectionByID(section);
245 if (!section_ptr)
246 return false;
247
248 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
249 stream.GetAddressByteSize(), stream.GetByteOrder());
250
251 return true;
252 });
253}
254
255llvm::Expected<DWARFExpression>
257 TpiStream &tpi,
258 const llvm::APSInt &constant,
259 ModuleSP module) {
260 const ArchSpec &architecture = module->GetArchitecture();
261 uint32_t address_size = architecture.GetAddressByteSize();
262
263 auto type_info = GetIntegralTypeInfo(underlying_ti, tpi);
264 if (!type_info)
265 return type_info.takeError();
266 auto [size, is_signed] = *type_info;
267
268 union {
269 llvm::support::little64_t I;
270 llvm::support::ulittle64_t U;
271 } Value;
272
273 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
274 buffer->SetByteSize(size);
275
276 llvm::ArrayRef<uint8_t> bytes;
277 if (is_signed) {
278 Value.I = constant.getSExtValue();
279 } else {
280 Value.U = constant.getZExtValue();
281 }
282
283 bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
284 .take_front(size);
285 buffer->CopyData(bytes.data(), size);
286 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
287 DWARFExpression result(extractor);
288 return result;
289}
290
293 const std::map<uint64_t, MemberValLocation> &offset_to_location,
294 std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
295 lldb::ModuleSP module) {
297 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
298 size_t cur_offset = 0;
299 bool is_simple_type = offset_to_size.empty();
300 // Iterate through offset_to_location because offset_to_size might be
301 // empty if the variable is a simple type.
302 for (const auto &offset_loc : offset_to_location) {
303 if (cur_offset < offset_loc.first) {
304 stream.PutHex8(llvm::dwarf::DW_OP_piece);
305 stream.PutULEB128(offset_loc.first - cur_offset);
306 cur_offset = offset_loc.first;
307 }
308 MemberValLocation loc = offset_loc.second;
309 std::optional<int32_t> offset =
310 loc.is_at_reg ? std::nullopt
311 : std::optional<int32_t>(loc.reg_offset);
313 stream, (RegisterId)loc.reg_id, register_kind, offset,
314 module))
315 return false;
316 if (!is_simple_type) {
317 stream.PutHex8(llvm::dwarf::DW_OP_piece);
318 stream.PutULEB128(offset_to_size[offset_loc.first]);
319 cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
320 }
321 }
322 // For simple type, it specifies the byte size of the value described by
323 // the previous dwarf expr. For udt, it's the remaining byte size at end
324 // of a struct.
325 if (total_size > cur_offset) {
326 stream.PutHex8(llvm::dwarf::DW_OP_piece);
327 stream.PutULEB128(total_size - cur_offset);
328 }
329 return true;
330 });
331}
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:581
const char * GetData() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
lldb::ByteOrder GetByteOrder() const
Definition Stream.cpp:233
uint32_t GetAddressByteSize() const
Get the address size in bytes.
Definition Stream.cpp:220
size_t size_t PutHex8(uint8_t uvalue)
Append an uint8_t value in the hexadecimal format to the stream.
Definition Stream.cpp:275
@ 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:57
size_t PutSLEB128(int64_t uval)
Output a SLEB128 number to the stream.
Definition Stream.cpp:49
size_t PutMaxHex64(uint64_t uvalue, size_t byte_size, lldb::ByteOrder byte_order=lldb::eByteOrderInvalid)
Definition Stream.cpp:329
#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)
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