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 std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78 TpiStream &tpi) {
79 if (ti.isSimple()) {
80 SimpleTypeKind stk = ti.getSimpleKind();
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 {pr.getSize(), false};
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>
109 StreamWriter &&writer) {
110 const ArchSpec &architecture = module->GetArchitecture();
111 ByteOrder byte_order = architecture.GetByteOrder();
112 uint32_t address_size = architecture.GetAddressByteSize();
113 if (byte_order == eByteOrderInvalid || address_size == 0)
114 return DWARFExpression();
115
116 RegisterKind register_kind = eRegisterKindDWARF;
117 StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
118
119 if (!writer(stream, register_kind))
120 return DWARFExpression();
121
122 DataBufferSP buffer =
123 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
124 DataExtractor extractor(buffer, byte_order, address_size);
125 DWARFExpression result(extractor);
126 result.SetRegisterKind(register_kind);
127
128 return result;
129}
130
132 Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
133 std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
134 uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
135 reg, register_kind);
136 if (reg_num == LLDB_INVALID_REGNUM)
137 return false;
138
139 if (reg_num > 31) {
140 llvm::dwarf::LocationAtom base =
141 relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
142 stream.PutHex8(base);
143 stream.PutULEB128(reg_num);
144 } else {
145 llvm::dwarf::LocationAtom base =
146 relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
147 stream.PutHex8(base + reg_num);
148 }
149
150 if (relative_offset)
151 stream.PutSLEB128(*relative_offset);
152
153 return true;
154}
155
157 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
158 lldb::ModuleSP module) {
160 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
162 stream, reg, register_kind, relative_offset, module);
163 });
164}
165
167 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
168 return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
169}
170
172 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
173 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
174}
175
177 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
178 // VFrame value always stored in $TO pseudo-register
179 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
180 stream);
181}
182
184 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
187 const ArchSpec &architecture = module->GetArchitecture();
188
189 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
190 stream))
191 return false;
192
193 stream.PutHex8(llvm::dwarf::DW_OP_consts);
194 stream.PutSLEB128(offset);
195 stream.PutHex8(llvm::dwarf::DW_OP_plus);
196
197 register_kind = eRegisterKindLLDB;
198
199 return true;
200 });
201}
202
204 uint16_t section, uint32_t offset, ModuleSP module) {
205 assert(section > 0);
206 assert(module);
207
209 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
210 stream.PutHex8(llvm::dwarf::DW_OP_addr);
211
212 SectionList *section_list = module->GetSectionList();
213 assert(section_list);
214
215 auto section_ptr = section_list->FindSectionByID(section);
216 if (!section_ptr)
217 return false;
218
219 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
220 stream.GetAddressByteSize(), stream.GetByteOrder());
221
222 return true;
223 });
224}
225
227 TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
228 ModuleSP module) {
229 const ArchSpec &architecture = module->GetArchitecture();
230 uint32_t address_size = architecture.GetAddressByteSize();
231
232 size_t size = 0;
233 bool is_signed = false;
234 std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
235
236 union {
237 llvm::support::little64_t I;
238 llvm::support::ulittle64_t U;
239 } Value;
240
241 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
242 buffer->SetByteSize(size);
243
244 llvm::ArrayRef<uint8_t> bytes;
245 if (is_signed) {
246 Value.I = constant.getSExtValue();
247 } else {
248 Value.U = constant.getZExtValue();
249 }
250
251 bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
252 .take_front(size);
253 buffer->CopyData(bytes.data(), size);
254 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
255 DWARFExpression result(extractor);
256 return result;
257}
258
261 const std::map<uint64_t, MemberValLocation> &offset_to_location,
262 std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
263 lldb::ModuleSP module) {
265 module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
266 size_t cur_offset = 0;
267 bool is_simple_type = offset_to_size.empty();
268 // Iterate through offset_to_location because offset_to_size might be
269 // empty if the variable is a simple type.
270 for (const auto &offset_loc : offset_to_location) {
271 if (cur_offset < offset_loc.first) {
272 stream.PutHex8(llvm::dwarf::DW_OP_piece);
273 stream.PutULEB128(offset_loc.first - cur_offset);
274 cur_offset = offset_loc.first;
275 }
276 MemberValLocation loc = offset_loc.second;
277 std::optional<int32_t> offset =
278 loc.is_at_reg ? std::nullopt
279 : std::optional<int32_t>(loc.reg_offset);
281 stream, (RegisterId)loc.reg_id, register_kind, offset,
282 module))
283 return false;
284 if (!is_simple_type) {
285 stream.PutHex8(llvm::dwarf::DW_OP_piece);
286 stream.PutULEB128(offset_to_size[offset_loc.first]);
287 cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
288 }
289 }
290 // For simple type, it specifies the byte size of the value described by
291 // the previous dwarf expr. For udt, it's the remaining byte size at end
292 // of a struct.
293 if (total_size > cur_offset) {
294 stream.PutHex8(llvm::dwarf::DW_OP_piece);
295 stream.PutULEB128(total_size - cur_offset);
296 }
297 return true;
298 });
299}
static bool EmitVFrameEvaluationDWARFExpression(llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream)
uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)
static std::pair< size_t, bool > GetIntegralTypeInfo(TypeIndex ti, TpiStream &tpi)
static bool MakeRegisterBasedLocationExpressionInternal(Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind, std::optional< int32_t > relative_offset, lldb::ModuleSP module)
static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id, RegisterKind &register_kind)
static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind)
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:582
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:227
uint32_t GetAddressByteSize() const
Get the address size in bytes.
Definition Stream.cpp:214
size_t size_t PutHex8(uint8_t uvalue)
Append an uint8_t value in the hexadecimal format to the stream.
Definition Stream.cpp:269
@ 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:323
#define LLDB_INVALID_REGNUM
#define LLDB_REGNUM_GENERIC_FP
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)
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)
DWARFExpression MakeConstantLocationExpression(llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi, const llvm::APSInt &constant, lldb::ModuleSP module)
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