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