Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/DataFormatters/FormatterBytecode.cpp
213764 views
1
//===-- FormatterBytecode.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 "FormatterBytecode.h"
10
#include "lldb/Utility/LLDBLog.h"
11
#include "lldb/ValueObject/ValueObject.h"
12
#include "lldb/ValueObject/ValueObjectConstResult.h"
13
#include "llvm/ADT/StringExtras.h"
14
#include "llvm/Support/DataExtractor.h"
15
#include "llvm/Support/Format.h"
16
#include "llvm/Support/FormatProviders.h"
17
#include "llvm/Support/FormatVariadicDetails.h"
18
19
using namespace lldb;
20
namespace lldb_private {
21
22
std::string toString(FormatterBytecode::OpCodes op) {
23
switch (op) {
24
#define DEFINE_OPCODE(OP, MNEMONIC, NAME) \
25
case OP: { \
26
const char *s = MNEMONIC; \
27
return s ? s : #NAME; \
28
}
29
#include "FormatterBytecode.def"
30
#undef DEFINE_SIGNATURE
31
}
32
return llvm::utostr(op);
33
}
34
35
std::string toString(FormatterBytecode::Selectors sel) {
36
switch (sel) {
37
#define DEFINE_SELECTOR(ID, NAME) \
38
case ID: \
39
return "@" #NAME;
40
#include "FormatterBytecode.def"
41
#undef DEFINE_SIGNATURE
42
}
43
return "@" + llvm::utostr(sel);
44
}
45
46
std::string toString(FormatterBytecode::Signatures sig) {
47
switch (sig) {
48
#define DEFINE_SIGNATURE(ID, NAME) \
49
case ID: \
50
return "@" #NAME;
51
#include "FormatterBytecode.def"
52
#undef DEFINE_SIGNATURE
53
}
54
return llvm::utostr(sig);
55
}
56
57
std::string toString(const FormatterBytecode::DataStack &data) {
58
std::string s;
59
llvm::raw_string_ostream os(s);
60
os << "[ ";
61
for (auto &d : data) {
62
if (auto s = std::get_if<std::string>(&d))
63
os << '"' << *s << '"';
64
else if (auto u = std::get_if<uint64_t>(&d))
65
os << *u << 'u';
66
else if (auto i = std::get_if<int64_t>(&d))
67
os << *i;
68
else if (auto valobj = std::get_if<ValueObjectSP>(&d)) {
69
if (!valobj->get())
70
os << "null";
71
else
72
os << "object(" << valobj->get()->GetValueAsCString() << ')';
73
} else if (auto type = std::get_if<CompilerType>(&d)) {
74
os << '(' << type->GetTypeName(true) << ')';
75
} else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
76
os << toString(*sel);
77
}
78
os << ' ';
79
}
80
os << ']';
81
return s;
82
}
83
84
namespace FormatterBytecode {
85
86
/// Implement the @format function.
87
static llvm::Error FormatImpl(DataStack &data) {
88
auto fmt = data.Pop<std::string>();
89
auto replacements =
90
llvm::formatv_object_base::parseFormatString(fmt, 0, false);
91
std::string s;
92
llvm::raw_string_ostream os(s);
93
unsigned num_args = 0;
94
for (const auto &r : replacements)
95
if (r.Type == llvm::ReplacementType::Format)
96
num_args = std::max(num_args, r.Index + 1);
97
98
if (data.size() < num_args)
99
return llvm::createStringError("not enough arguments");
100
101
for (const auto &r : replacements) {
102
if (r.Type == llvm::ReplacementType::Literal) {
103
os << r.Spec;
104
continue;
105
}
106
using namespace llvm::support::detail;
107
auto arg = data[data.size() - num_args + r.Index];
108
auto format = [&](format_adapter &&adapter) {
109
llvm::FmtAlign Align(adapter, r.Where, r.Width, r.Pad);
110
Align.format(os, r.Options);
111
};
112
113
if (auto s = std::get_if<std::string>(&arg))
114
format(build_format_adapter(s->c_str()));
115
else if (auto u = std::get_if<uint64_t>(&arg))
116
format(build_format_adapter(u));
117
else if (auto i = std::get_if<int64_t>(&arg))
118
format(build_format_adapter(i));
119
else if (auto valobj = std::get_if<ValueObjectSP>(&arg)) {
120
if (!valobj->get())
121
format(build_format_adapter("null object"));
122
else
123
format(build_format_adapter(valobj->get()->GetValueAsCString()));
124
} else if (auto type = std::get_if<CompilerType>(&arg))
125
format(build_format_adapter(type->GetDisplayTypeName()));
126
else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
127
format(build_format_adapter(toString(*sel)));
128
}
129
data.Push(s);
130
return llvm::Error::success();
131
}
132
133
static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
134
DataType type) {
135
if (data.size() < 1)
136
return llvm::createStringError("not enough elements on data stack");
137
138
auto &elem = data.back();
139
switch (type) {
140
case Any:
141
break;
142
case String:
143
if (!std::holds_alternative<std::string>(elem))
144
return llvm::createStringError("expected String");
145
break;
146
case UInt:
147
if (!std::holds_alternative<uint64_t>(elem))
148
return llvm::createStringError("expected UInt");
149
break;
150
case Int:
151
if (!std::holds_alternative<int64_t>(elem))
152
return llvm::createStringError("expected Int");
153
break;
154
case Object:
155
if (!std::holds_alternative<ValueObjectSP>(elem))
156
return llvm::createStringError("expected Object");
157
break;
158
case Type:
159
if (!std::holds_alternative<CompilerType>(elem))
160
return llvm::createStringError("expected Type");
161
break;
162
case Selector:
163
if (!std::holds_alternative<Selectors>(elem))
164
return llvm::createStringError("expected Selector");
165
break;
166
}
167
return llvm::Error::success();
168
}
169
170
static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
171
DataType type1, DataType type2) {
172
if (auto error = TypeCheck(data, type2))
173
return error;
174
return TypeCheck(data.drop_back(), type1);
175
}
176
177
static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
178
DataType type1, DataType type2, DataType type3) {
179
if (auto error = TypeCheck(data, type3))
180
return error;
181
return TypeCheck(data.drop_back(1), type2, type1);
182
}
183
184
llvm::Error Interpret(std::vector<ControlStackElement> &control,
185
DataStack &data, Selectors sel) {
186
if (control.empty())
187
return llvm::Error::success();
188
// Since the only data types are single endian and ULEBs, the
189
// endianness should not matter.
190
llvm::DataExtractor cur_block(control.back(), true, 64);
191
llvm::DataExtractor::Cursor pc(0);
192
193
while (!control.empty()) {
194
/// Activate the top most block from the control stack.
195
auto activate_block = [&]() {
196
// Save the return address.
197
if (control.size() > 1)
198
control[control.size() - 2] = cur_block.getData().drop_front(pc.tell());
199
cur_block = llvm::DataExtractor(control.back(), true, 64);
200
if (pc)
201
pc = llvm::DataExtractor::Cursor(0);
202
};
203
204
/// Fetch the next byte in the instruction stream.
205
auto next_byte = [&]() -> uint8_t {
206
// At the end of the current block?
207
while (pc.tell() >= cur_block.size() && !control.empty()) {
208
if (control.size() == 1) {
209
control.pop_back();
210
return 0;
211
}
212
control.pop_back();
213
activate_block();
214
}
215
216
// Fetch the next instruction.
217
return cur_block.getU8(pc);
218
};
219
220
// Fetch the next opcode.
221
OpCodes opcode = (OpCodes)next_byte();
222
if (control.empty() || !pc)
223
return pc.takeError();
224
225
LLDB_LOGV(GetLog(LLDBLog::DataFormatters),
226
"[eval {0}] opcode={1}, control={2}, data={3}", toString(sel),
227
toString(opcode), control.size(), toString(data));
228
229
// Various shorthands to improve the readability of error handling.
230
#define TYPE_CHECK(...) \
231
if (auto error = TypeCheck(data, __VA_ARGS__)) \
232
return error;
233
234
auto error = [&](llvm::Twine msg) {
235
return llvm::createStringError(msg + "(opcode=" + toString(opcode) + ")");
236
};
237
238
switch (opcode) {
239
// Data stack manipulation.
240
case op_dup:
241
TYPE_CHECK(Any);
242
data.Push(data.back());
243
continue;
244
case op_drop:
245
TYPE_CHECK(Any);
246
data.pop_back();
247
continue;
248
case op_pick: {
249
TYPE_CHECK(UInt);
250
uint64_t idx = data.Pop<uint64_t>();
251
if (idx >= data.size())
252
return error("index out of bounds");
253
data.Push(data[idx]);
254
continue;
255
}
256
case op_over:
257
TYPE_CHECK(Any, Any);
258
data.Push(data[data.size() - 2]);
259
continue;
260
case op_swap: {
261
TYPE_CHECK(Any, Any);
262
auto x = data.PopAny();
263
auto y = data.PopAny();
264
data.Push(x);
265
data.Push(y);
266
continue;
267
}
268
case op_rot: {
269
TYPE_CHECK(Any, Any, Any);
270
auto z = data.PopAny();
271
auto y = data.PopAny();
272
auto x = data.PopAny();
273
data.Push(z);
274
data.Push(x);
275
data.Push(y);
276
continue;
277
}
278
279
// Control stack manipulation.
280
case op_begin: {
281
uint64_t length = cur_block.getULEB128(pc);
282
if (!pc)
283
return pc.takeError();
284
llvm::StringRef block = cur_block.getBytes(pc, length);
285
if (!pc)
286
return pc.takeError();
287
control.push_back(block);
288
continue;
289
}
290
case op_if:
291
TYPE_CHECK(UInt);
292
if (data.Pop<uint64_t>() != 0) {
293
if (!cur_block.size())
294
return error("empty control stack");
295
activate_block();
296
} else
297
control.pop_back();
298
continue;
299
case op_ifelse:
300
TYPE_CHECK(UInt);
301
if (cur_block.size() < 2)
302
return error("empty control stack");
303
if (data.Pop<uint64_t>() == 0)
304
control[control.size() - 2] = control.back();
305
control.pop_back();
306
activate_block();
307
continue;
308
case op_return:
309
control.clear();
310
return pc.takeError();
311
312
// Literals.
313
case op_lit_uint:
314
data.Push(cur_block.getULEB128(pc));
315
continue;
316
case op_lit_int:
317
data.Push(cur_block.getSLEB128(pc));
318
continue;
319
case op_lit_selector:
320
data.Push(Selectors(cur_block.getU8(pc)));
321
continue;
322
case op_lit_string: {
323
uint64_t length = cur_block.getULEB128(pc);
324
llvm::StringRef bytes = cur_block.getBytes(pc, length);
325
data.Push(bytes.str());
326
continue;
327
}
328
case op_as_uint: {
329
TYPE_CHECK(Int);
330
uint64_t casted;
331
int64_t val = data.Pop<int64_t>();
332
memcpy(&casted, &val, sizeof(val));
333
data.Push(casted);
334
continue;
335
}
336
case op_as_int: {
337
TYPE_CHECK(UInt);
338
int64_t casted;
339
uint64_t val = data.Pop<uint64_t>();
340
memcpy(&casted, &val, sizeof(val));
341
data.Push(casted);
342
continue;
343
}
344
case op_is_null: {
345
TYPE_CHECK(Object);
346
data.Push(data.Pop<ValueObjectSP>() ? (uint64_t)0 : (uint64_t)1);
347
continue;
348
}
349
350
// Arithmetic, logic, etc.
351
#define BINOP_IMPL(OP, CHECK_ZERO) \
352
{ \
353
TYPE_CHECK(Any, Any); \
354
auto y = data.PopAny(); \
355
if (std::holds_alternative<uint64_t>(y)) { \
356
if (CHECK_ZERO && !std::get<uint64_t>(y)) \
357
return error(#OP " by zero"); \
358
TYPE_CHECK(UInt); \
359
data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
360
} else if (std::holds_alternative<int64_t>(y)) { \
361
if (CHECK_ZERO && !std::get<int64_t>(y)) \
362
return error(#OP " by zero"); \
363
TYPE_CHECK(Int); \
364
data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
365
} else \
366
return error("unsupported data types"); \
367
}
368
#define BINOP(OP) BINOP_IMPL(OP, false)
369
#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
370
case op_plus:
371
BINOP(+);
372
continue;
373
case op_minus:
374
BINOP(-);
375
continue;
376
case op_mul:
377
BINOP(*);
378
continue;
379
case op_div:
380
BINOP_CHECKZERO(/);
381
continue;
382
case op_mod:
383
BINOP_CHECKZERO(%);
384
continue;
385
case op_shl:
386
#define SHIFTOP(OP, LEFT) \
387
{ \
388
TYPE_CHECK(Any, UInt); \
389
uint64_t y = data.Pop<uint64_t>(); \
390
if (y > 64) \
391
return error("shift out of bounds"); \
392
if (std::holds_alternative<uint64_t>(data.back())) { \
393
uint64_t x = data.Pop<uint64_t>(); \
394
data.Push(x OP y); \
395
} else if (std::holds_alternative<int64_t>(data.back())) { \
396
int64_t x = data.Pop<int64_t>(); \
397
if (x < 0 && LEFT) \
398
return error("left shift of negative value"); \
399
if (y > 64) \
400
return error("shift out of bounds"); \
401
data.Push(x OP y); \
402
} else \
403
return error("unsupported data types"); \
404
}
405
SHIFTOP(<<, true);
406
continue;
407
case op_shr:
408
SHIFTOP(>>, false);
409
continue;
410
case op_and:
411
BINOP(&);
412
continue;
413
case op_or:
414
BINOP(|);
415
continue;
416
case op_xor:
417
BINOP(^);
418
continue;
419
case op_not:
420
TYPE_CHECK(UInt);
421
data.Push(~data.Pop<uint64_t>());
422
continue;
423
case op_eq:
424
BINOP(==);
425
continue;
426
case op_neq:
427
BINOP(!=);
428
continue;
429
case op_lt:
430
BINOP(<);
431
continue;
432
case op_gt:
433
BINOP(>);
434
continue;
435
case op_le:
436
BINOP(<=);
437
continue;
438
case op_ge:
439
BINOP(>=);
440
continue;
441
case op_call: {
442
TYPE_CHECK(Selector);
443
Selectors sel = data.Pop<Selectors>();
444
445
// Shorthand to improve readability.
446
#define POP_VALOBJ(VALOBJ) \
447
auto VALOBJ = data.Pop<ValueObjectSP>(); \
448
if (!VALOBJ) \
449
return error("null object");
450
451
auto sel_error = [&](const char *msg) {
452
return llvm::createStringError("{0} (opcode={1}, selector={2})", msg,
453
toString(opcode).c_str(),
454
toString(sel).c_str());
455
};
456
457
switch (sel) {
458
case sel_summary: {
459
TYPE_CHECK(Object);
460
POP_VALOBJ(valobj);
461
const char *summary = valobj->GetSummaryAsCString();
462
data.Push(summary ? std::string(valobj->GetSummaryAsCString())
463
: std::string());
464
break;
465
}
466
case sel_get_num_children: {
467
TYPE_CHECK(Object);
468
POP_VALOBJ(valobj);
469
auto result = valobj->GetNumChildren();
470
if (!result)
471
return result.takeError();
472
data.Push((uint64_t)*result);
473
break;
474
}
475
case sel_get_child_at_index: {
476
TYPE_CHECK(Object, UInt);
477
auto index = data.Pop<uint64_t>();
478
POP_VALOBJ(valobj);
479
data.Push(valobj->GetChildAtIndex(index));
480
break;
481
}
482
case sel_get_child_with_name: {
483
TYPE_CHECK(Object, String);
484
auto name = data.Pop<std::string>();
485
POP_VALOBJ(valobj);
486
data.Push(valobj->GetChildMemberWithName(name));
487
break;
488
}
489
case sel_get_child_index: {
490
TYPE_CHECK(Object, String);
491
auto name = data.Pop<std::string>();
492
POP_VALOBJ(valobj);
493
if (auto index_or_err = valobj->GetIndexOfChildWithName(name))
494
data.Push((uint64_t)*index_or_err);
495
else
496
return index_or_err.takeError();
497
break;
498
}
499
case sel_get_type: {
500
TYPE_CHECK(Object);
501
POP_VALOBJ(valobj);
502
// FIXME: do we need to control dynamic type resolution?
503
data.Push(valobj->GetTypeImpl().GetCompilerType(false));
504
break;
505
}
506
case sel_get_template_argument_type: {
507
TYPE_CHECK(Type, UInt);
508
auto index = data.Pop<uint64_t>();
509
auto type = data.Pop<CompilerType>();
510
// FIXME: There is more code in SBType::GetTemplateArgumentType().
511
data.Push(type.GetTypeTemplateArgument(index, true));
512
break;
513
}
514
case sel_get_value: {
515
TYPE_CHECK(Object);
516
POP_VALOBJ(valobj);
517
data.Push(std::string(valobj->GetValueAsCString()));
518
break;
519
}
520
case sel_get_value_as_unsigned: {
521
TYPE_CHECK(Object);
522
POP_VALOBJ(valobj);
523
bool success;
524
uint64_t val = valobj->GetValueAsUnsigned(0, &success);
525
data.Push(val);
526
if (!success)
527
return sel_error("failed to get value");
528
break;
529
}
530
case sel_get_value_as_signed: {
531
TYPE_CHECK(Object);
532
POP_VALOBJ(valobj);
533
bool success;
534
int64_t val = valobj->GetValueAsSigned(0, &success);
535
data.Push(val);
536
if (!success)
537
return sel_error("failed to get value");
538
break;
539
}
540
case sel_get_value_as_address: {
541
TYPE_CHECK(Object);
542
POP_VALOBJ(valobj);
543
bool success;
544
uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
545
if (!success)
546
return sel_error("failed to get value");
547
if (auto process_sp = valobj->GetProcessSP())
548
addr = process_sp->FixDataAddress(addr);
549
data.Push(addr);
550
break;
551
}
552
case sel_cast: {
553
TYPE_CHECK(Object, Type);
554
auto type = data.Pop<CompilerType>();
555
POP_VALOBJ(valobj);
556
data.Push(valobj->Cast(type));
557
break;
558
}
559
case sel_strlen: {
560
TYPE_CHECK(String);
561
data.Push((uint64_t)data.Pop<std::string>().size());
562
break;
563
}
564
case sel_fmt: {
565
TYPE_CHECK(String);
566
if (auto error = FormatImpl(data))
567
return error;
568
break;
569
}
570
default:
571
return sel_error("selector not implemented");
572
}
573
continue;
574
}
575
}
576
return error("opcode not implemented");
577
}
578
return pc.takeError();
579
}
580
} // namespace FormatterBytecode
581
582
} // namespace lldb_private
583
584