Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
39644 views
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
9
#include "DWARFLocationExpression.h"
10
11
#include "lldb/Core/Module.h"
12
#include "lldb/Core/Section.h"
13
#include "lldb/Expression/DWARFExpression.h"
14
#include "lldb/Utility/ArchSpec.h"
15
#include "lldb/Utility/DataBufferHeap.h"
16
#include "lldb/Utility/StreamBuffer.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"
25
#include "CodeViewRegisterMapping.h"
26
#include "PdbFPOProgramToDWARFExpression.h"
27
#include <optional>
28
29
using namespace lldb;
30
using namespace lldb_private;
31
using namespace lldb_private::npdb;
32
using namespace llvm::codeview;
33
using namespace llvm::pdb;
34
35
uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
36
if (register_id == llvm::codeview::RegisterId::VFRAME)
37
return LLDB_REGNUM_GENERIC_FP;
38
39
return LLDB_INVALID_REGNUM;
40
}
41
42
static 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
54
static 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
77
static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78
TpiStream &tpi) {
79
if (ti.isSimple()) {
80
SimpleTypeKind stk = ti.getSimpleKind();
81
return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
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 GetIntegralTypeInfo(pr.ReferentType, tpi);
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
107
template <typename StreamWriter>
108
static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
109
StreamWriter &&writer) {
110
const ArchSpec &architecture = module->GetArchitecture();
111
ByteOrder byte_order = architecture.GetByteOrder();
112
uint32_t address_size = architecture.GetAddressByteSize();
113
uint32_t byte_size = architecture.GetDataByteSize();
114
if (byte_order == eByteOrderInvalid || address_size == 0)
115
return DWARFExpression();
116
117
RegisterKind register_kind = eRegisterKindDWARF;
118
StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
119
120
if (!writer(stream, register_kind))
121
return DWARFExpression();
122
123
DataBufferSP buffer =
124
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
125
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
126
DWARFExpression result(extractor);
127
result.SetRegisterKind(register_kind);
128
129
return result;
130
}
131
132
static bool MakeRegisterBasedLocationExpressionInternal(
133
Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
134
std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135
uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136
reg, register_kind);
137
if (reg_num == LLDB_INVALID_REGNUM)
138
return false;
139
140
if (reg_num > 31) {
141
llvm::dwarf::LocationAtom base =
142
relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
143
stream.PutHex8(base);
144
stream.PutULEB128(reg_num);
145
} else {
146
llvm::dwarf::LocationAtom base =
147
relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
148
stream.PutHex8(base + reg_num);
149
}
150
151
if (relative_offset)
152
stream.PutSLEB128(*relative_offset);
153
154
return true;
155
}
156
157
static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158
llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159
lldb::ModuleSP module) {
160
return MakeLocationExpressionInternal(
161
module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
162
return MakeRegisterBasedLocationExpressionInternal(
163
stream, reg, register_kind, relative_offset, module);
164
});
165
}
166
167
DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
168
llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169
return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
170
}
171
172
DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
173
llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
174
return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
175
}
176
177
static bool EmitVFrameEvaluationDWARFExpression(
178
llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
179
// VFrame value always stored in $TO pseudo-register
180
return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
181
stream);
182
}
183
184
DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
185
llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186
return MakeLocationExpressionInternal(
187
module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
188
const ArchSpec &architecture = module->GetArchitecture();
189
190
if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
191
stream))
192
return false;
193
194
stream.PutHex8(llvm::dwarf::DW_OP_consts);
195
stream.PutSLEB128(offset);
196
stream.PutHex8(llvm::dwarf::DW_OP_plus);
197
198
register_kind = eRegisterKindLLDB;
199
200
return true;
201
});
202
}
203
204
DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
205
uint16_t section, uint32_t offset, ModuleSP module) {
206
assert(section > 0);
207
assert(module);
208
209
return MakeLocationExpressionInternal(
210
module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
211
stream.PutHex8(llvm::dwarf::DW_OP_addr);
212
213
SectionList *section_list = module->GetSectionList();
214
assert(section_list);
215
216
auto section_ptr = section_list->FindSectionByID(section);
217
if (!section_ptr)
218
return false;
219
220
stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
221
stream.GetAddressByteSize(), stream.GetByteOrder());
222
223
return true;
224
});
225
}
226
227
DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
228
TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
229
ModuleSP module) {
230
const ArchSpec &architecture = module->GetArchitecture();
231
uint32_t address_size = architecture.GetAddressByteSize();
232
233
size_t size = 0;
234
bool is_signed = false;
235
std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
236
237
union {
238
llvm::support::little64_t I;
239
llvm::support::ulittle64_t U;
240
} Value;
241
242
std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
243
buffer->SetByteSize(size);
244
245
llvm::ArrayRef<uint8_t> bytes;
246
if (is_signed) {
247
Value.I = constant.getSExtValue();
248
} else {
249
Value.U = constant.getZExtValue();
250
}
251
252
bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
253
.take_front(size);
254
buffer->CopyData(bytes.data(), size);
255
DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256
DWARFExpression result(extractor);
257
return result;
258
}
259
260
DWARFExpression
261
lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262
const std::map<uint64_t, MemberValLocation> &offset_to_location,
263
std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
264
lldb::ModuleSP module) {
265
return MakeLocationExpressionInternal(
266
module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
267
size_t cur_offset = 0;
268
bool is_simple_type = offset_to_size.empty();
269
// Iterate through offset_to_location because offset_to_size might be
270
// empty if the variable is a simple type.
271
for (const auto &offset_loc : offset_to_location) {
272
if (cur_offset < offset_loc.first) {
273
stream.PutHex8(llvm::dwarf::DW_OP_piece);
274
stream.PutULEB128(offset_loc.first - cur_offset);
275
cur_offset = offset_loc.first;
276
}
277
MemberValLocation loc = offset_loc.second;
278
std::optional<int32_t> offset =
279
loc.is_at_reg ? std::nullopt
280
: std::optional<int32_t>(loc.reg_offset);
281
if (!MakeRegisterBasedLocationExpressionInternal(
282
stream, (RegisterId)loc.reg_id, register_kind, offset,
283
module))
284
return false;
285
if (!is_simple_type) {
286
stream.PutHex8(llvm::dwarf::DW_OP_piece);
287
stream.PutULEB128(offset_to_size[offset_loc.first]);
288
cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289
}
290
}
291
// For simple type, it specifies the byte size of the value described by
292
// the previous dwarf expr. For udt, it's the remaining byte size at end
293
// of a struct.
294
if (total_size > cur_offset) {
295
stream.PutHex8(llvm::dwarf::DW_OP_piece);
296
stream.PutULEB128(total_size - cur_offset);
297
}
298
return true;
299
});
300
}
301
302