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
14#include "lldb/lldb-forward.h"
15#include "llvm/ADT/APSInt.h"
16#include "llvm/ADT/SmallPtrSet.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/Support/DataExtractor.h"
20#include "llvm/Support/Error.h"
21#include "llvm/Support/ErrorExtras.h"
22#include "llvm/Support/Format.h"
23#include "llvm/Support/FormatProviders.h"
24#include "llvm/Support/FormatVariadicDetails.h"
25#include <type_traits>
26
27using namespace lldb;
28namespace lldb_private {
29
31 switch (op) {
32#define DEFINE_OPCODE(OP, MNEMONIC, NAME) \
33 case OP: { \
34 const char *s = MNEMONIC; \
35 return s ? s : #NAME; \
36 }
37#include "lldb/DataFormatters/FormatterBytecode.def"
38#undef DEFINE_OPCODE
39 }
40 return llvm::utostr(op);
41}
42
44 switch (sel) {
45#define DEFINE_SELECTOR(ID, NAME) \
46 case ID: \
47 return "@" #NAME;
48#include "lldb/DataFormatters/FormatterBytecode.def"
49#undef DEFINE_SELECTOR
50 }
51 return "@" + llvm::utostr(sel);
52}
53
55 switch (sig) {
56#define DEFINE_SIGNATURE(ID, NAME) \
57 case ID: \
58 return "@" #NAME;
59#include "lldb/DataFormatters/FormatterBytecode.def"
60#undef DEFINE_SIGNATURE
61 }
62 return llvm::utostr(sig);
63}
64
65std::string toString(const FormatterBytecode::DataStack &data) {
66 std::string s;
67 llvm::raw_string_ostream os(s);
68 os << "[ ";
69 for (auto &d : data) {
70 if (auto s = std::get_if<std::string>(&d))
71 os << '"' << *s << '"';
72 else if (auto u = std::get_if<uint64_t>(&d))
73 os << *u << 'u';
74 else if (auto i = std::get_if<int64_t>(&d))
75 os << *i;
76 else if (auto ap = std::get_if<llvm::APSInt>(&d))
77 os << *ap;
78 else if (auto valobj = std::get_if<ValueObjectSP>(&d)) {
79 if (!valobj->get())
80 os << "null";
81 else
82 os << "object(" << valobj->get()->GetValueAsCString() << ')';
83 } else if (auto type = std::get_if<CompilerType>(&d)) {
84 os << '(' << type->GetTypeName(true) << ')';
85 } else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
86 os << toString(*sel);
87 } else if (auto *dict =
88 std::get_if<std::shared_ptr<FormatterBytecode::Dictionary>>(
89 &d)) {
90 os << "dict(" << (*dict ? (*dict)->size() : 0) << ')';
91 }
92 os << ' ';
93 }
94 os << ']';
95 return s;
96}
97
98namespace FormatterBytecode {
99
100/// Check a format string, and remove the layout and options of each
101/// replacement. The format string may contain literal text, escaped braces
102/// ("{{"), and automatically indexed replacements:
103///
104/// "{" [ "," layout ] [ ":" options ] "}"
105///
106/// Explicit indexes are not supported. Layouts and options are accepted, so
107/// that support for them can be added without changing the ABI, but they are
108/// currently ignored. The result contains only literal text, escaped braces,
109/// and "{}", so malformed format strings never reach formatv.
110static llvm::Expected<std::string> SanitizeFormatString(llvm::StringRef fmt) {
111 const llvm::StringRef original = fmt;
112 std::string result;
113 while (!fmt.empty()) {
114 // Copy the literal text up to the next brace.
115 llvm::StringRef literal = fmt.take_front(fmt.find('{'));
116 result += literal;
117 fmt = fmt.drop_front(literal.size());
118 if (fmt.empty())
119 break;
120 if (fmt.consume_front("{{")) {
121 result += "{{";
122 continue;
123 }
124 llvm::StringRef replacement = fmt;
125 fmt = fmt.drop_front();
126 // Skip the layout, which ends at the options or the closing brace.
127 if (fmt.consume_front(","))
128 fmt = fmt.substr(fmt.find_first_of("{}:"));
129 // Skip the options, which end at the closing brace.
130 if (fmt.consume_front(":"))
131 fmt = fmt.substr(fmt.find_first_of("{}"));
132 if (!fmt.consume_front("}"))
133 return llvm::createStringErrorV(
134 "invalid replacement in format string at offset {0}",
135 original.size() - replacement.size());
136 replacement = replacement.drop_back(fmt.size());
137 if (replacement != "{}")
139 "ignoring unsupported layout or options in format replacement "
140 "'{0}'",
141 replacement);
142 result += "{}";
143 }
144 return result;
145}
146
147/// Implement the @format function.
148static llvm::Error FormatImpl(DataStack &data, uint32_t version) {
149 auto fmt = data.Pop<std::string>();
150 if (version >= 2) {
151 auto sanitized = SanitizeFormatString(fmt);
152 if (!sanitized)
153 return sanitized.takeError();
154 fmt = std::move(*sanitized);
155 }
156 auto replacements =
157 llvm::formatv_object_base::parseFormatString(fmt, 0, false);
158 std::string s;
159 llvm::raw_string_ostream os(s);
160 unsigned num_args = 0;
161 for (const auto &r : replacements)
162 if (r.Type == llvm::ReplacementType::Format)
163 num_args = std::max(num_args, r.Index + 1);
164
165 if (data.size() < num_args)
166 return llvm::createStringError("not enough arguments");
167
168 for (const auto &r : replacements) {
169 if (r.Type == llvm::ReplacementType::Literal) {
170 os << r.Spec;
171 continue;
172 }
173 using namespace llvm::support::detail;
174 auto arg = data[data.size() - num_args + r.Index];
175 auto format = [&](FormatFunctorRef &&adapter) {
176 llvm::FmtAlign Align(adapter, r.Where, r.Width, r.Pad);
177 Align.format(os, r.Options);
178 };
179
180 if (auto s = std::get_if<std::string>(&arg))
181 format(FormatFunctor(s->c_str()));
182 else if (auto u = std::get_if<uint64_t>(&arg))
183 format(FormatFunctor(u));
184 else if (auto i = std::get_if<int64_t>(&arg))
185 format(FormatFunctor(i));
186 else if (auto ap = std::get_if<llvm::APSInt>(&arg))
187 format(FormatFunctor(*ap));
188 else if (auto valobj = std::get_if<ValueObjectSP>(&arg)) {
189 if (!valobj->get())
190 format(FormatFunctor("null object"));
191 else
192 format(FormatFunctor(valobj->get()->GetValueAsCString()));
193 } else if (auto type = std::get_if<CompilerType>(&arg))
194 format(FormatFunctor(type->GetDisplayTypeName()));
195 else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
196 format(FormatFunctor(toString(*sel)));
197 else if (std::holds_alternative<DictionarySP>(arg))
198 format(FormatFunctor("dict"));
199 }
200 // Consume the arguments, leaving only the result.
201 data.erase(data.end() - num_args, data.end());
202 data.Push(s);
203 return llvm::Error::success();
204}
205
206static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
207 DataType type) {
208 if (data.size() < 1)
209 return llvm::createStringError("not enough elements on data stack");
210
211 auto &elem = data.back();
212 switch (type) {
213 case Any:
214 break;
215 case String:
216 if (!std::holds_alternative<std::string>(elem))
217 return llvm::createStringError("expected String");
218 break;
219 case UInt:
220 if (!std::holds_alternative<uint64_t>(elem))
221 return llvm::createStringError("expected UInt");
222 break;
223 case Int:
224 if (!std::holds_alternative<int64_t>(elem))
225 return llvm::createStringError("expected Int");
226 break;
227 case Object:
228 if (!std::holds_alternative<ValueObjectSP>(elem))
229 return llvm::createStringError("expected Object");
230 break;
231 case Type:
232 if (!std::holds_alternative<CompilerType>(elem))
233 return llvm::createStringError("expected Type");
234 break;
235 case Selector:
236 if (!std::holds_alternative<Selectors>(elem))
237 return llvm::createStringError("expected Selector");
238 break;
239 case Integer:
240 if (!std::holds_alternative<llvm::APSInt>(elem))
241 return llvm::createStringError("expected Integer");
242 break;
243 case Dict:
244 if (!std::holds_alternative<std::shared_ptr<FormatterBytecode::Dictionary>>(
245 elem))
246 return llvm::createStringError("expected Dictionary");
247 break;
248 }
249 return llvm::Error::success();
250}
251
252static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
253 DataType type1, DataType type2) {
254 if (auto error = TypeCheck(data, type2))
255 return error;
256 return TypeCheck(data.drop_back(), type1);
257}
258
259static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
260 DataType type1, DataType type2, DataType type3) {
261 if (auto error = TypeCheck(data, type3))
262 return error;
263 return TypeCheck(data.drop_back(), type1, type2);
264}
265
266static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
267 DataType type1, DataType type2, DataType type3,
268 DataType type4) {
269 if (auto error = TypeCheck(data, type4))
270 return error;
271 return TypeCheck(data.drop_back(), type1, type2, type3);
272}
273
274/// Wrap the result of a binary operator applied to two APSInts back into a
275/// DataStackElement. Comparison operators yield bool and need bit_width/
276/// is_unsigned to construct the boolean's APSInt representation; arithmetic
277/// operators already yield a correctly-tagged APSInt and ignore them.
278template <typename T>
279static DataStackElement WrapAPSIntResult(T result, unsigned bit_width,
280 bool is_unsigned) {
281 if constexpr (std::is_same_v<T, bool>)
282 return llvm::APSInt(llvm::APInt(bit_width, result), is_unsigned);
283 else
284 return DataStackElement(std::move(result));
285}
286
287/// Returns true if `target` is transitively reachable via `from`. Likewise,
288/// returns true if they are the same dictionary. This is used to prevent memory
289/// leaks caused by retain cycles. Dictionaries can be shared by multiple
290/// parents, so each one is visited only once to prevent exponential running
291/// time.
292static bool Reaches(const Dictionary *from, const Dictionary *target) {
293 llvm::SmallPtrSet<const Dictionary *, 8> visited;
294 llvm::SmallVector<const Dictionary *, 8> worklist = {from};
295 while (!worklist.empty()) {
296 const Dictionary *dict = worklist.pop_back_val();
297 if (dict == target)
298 return true;
299 if (!visited.insert(dict).second)
300 continue;
301 for (const auto &entry : *dict)
302 if (auto *nested = std::get_if<DictionarySP>(&entry.second))
303 worklist.push_back(nested->get());
304 }
305 return false;
306}
307
308template <typename T>
310 std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, int>;
311template <typename T>
313 std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T> &&
314 !std::is_same_v<T, bool>,
315 int>;
316
317template <typename T, EnableIfSigned<T> = 0>
318static DataStackElement MakeInt(T value, uint32_t version) {
319 if (version < 2)
320 return int64_t(value);
321 return llvm::APSInt::get(value);
322}
323
324template <typename T, EnableIfUnsigned<T> = 0>
325static DataStackElement MakeInt(T value, uint32_t version) {
326 if (version < 2)
327 return uint64_t(value);
328 unsigned width = uint64_t(value) > uint64_t(INT64_MAX) ? 65 : 64;
329 return llvm::APSInt(llvm::APInt(width, value), /*isUnsigned=*/false);
330}
331
332llvm::Error Interpret(ControlStack &control, DataStack &data, Signatures sig,
333 uint32_t version) {
334 if (control.empty())
335 return llvm::Error::success();
336 // Since the only data types are single endian and ULEBs, the
337 // endianness should not matter.
338 llvm::DataExtractor cur_block(control.back(), true);
339 llvm::DataExtractor::Cursor pc(0);
340
341 while (!control.empty()) {
342 /// Activate the top most block from the control stack.
343 auto activate_block = [&]() {
344 // Save the return address.
345 if (control.size() > 1)
346 control[control.size() - 2] = cur_block.getData().drop_front(pc.tell());
347 cur_block = llvm::DataExtractor(control.back(), true);
348 if (pc)
349 pc = llvm::DataExtractor::Cursor(0);
350 };
351
352 /// Fetch the next byte in the instruction stream.
353 auto next_byte = [&]() -> uint8_t {
354 // At the end of the current block?
355 while (pc.tell() >= cur_block.size() && !control.empty()) {
356 if (control.size() == 1) {
357 control.pop_back();
358 return 0;
359 }
360 control.pop_back();
361 activate_block();
362 }
363
364 // Fetch the next instruction.
365 return cur_block.getU8(pc);
366 };
367
368 // Fetch the next opcode.
369 OpCodes opcode = (OpCodes)next_byte();
370 if (control.empty() || !pc)
371 return pc.takeError();
372
374 "[eval {0}] opcode={1}, control={2}, data={3}",
375 toString(sig), toString(opcode), control.size(),
376 toString(data));
377
378 // Various shorthands to improve the readability of error handling.
379#define TYPE_CHECK(...) \
380 if (auto error = TypeCheck(data, __VA_ARGS__)) \
381 return error;
382
383 auto error = [&](llvm::Twine msg) {
384 return llvm::createStringError(msg + "(opcode=" + toString(opcode) + ")");
385 };
386
387 switch (opcode) {
388 // Data stack manipulation.
389 case op_dup:
391 data.Push(data.back());
392 continue;
393 case op_drop:
395 data.pop_back();
396 continue;
397 case op_pick: {
399 uint64_t idx = data.Pop<uint64_t>();
400 if (idx >= data.size())
401 return error("index out of bounds");
402 data.Push(data[idx]);
403 continue;
404 }
405 case op_over:
407 data.Push(data[data.size() - 2]);
408 continue;
409 case op_swap: {
411 auto x = data.PopAny();
412 auto y = data.PopAny();
413 data.Push(x);
414 data.Push(y);
415 continue;
416 }
417 case op_rot: {
419 auto z = data.PopAny();
420 auto y = data.PopAny();
421 auto x = data.PopAny();
422 data.Push(z);
423 data.Push(x);
424 data.Push(y);
425 continue;
426 }
427
428 // Control stack manipulation.
429 case op_begin: {
430 uint64_t length = cur_block.getULEB128(pc);
431 if (!pc)
432 return pc.takeError();
433 llvm::StringRef block = cur_block.getBytes(pc, length);
434 if (!pc)
435 return pc.takeError();
436 control.push_back(block);
437 continue;
438 }
439 case op_if: {
440 auto cond = data.PopAny();
441 bool truthy;
442 if (auto *ap = std::get_if<llvm::APSInt>(&cond))
443 truthy = !ap->isZero();
444 else if (auto *u = std::get_if<uint64_t>(&cond))
445 // Deprecated.
446 truthy = *u != 0;
447 else
448 return error("expected Integer or UInt");
449 if (truthy) {
450 if (!cur_block.size())
451 return error("empty control stack");
452 activate_block();
453 } else
454 control.pop_back();
455 continue;
456 }
457 case op_ifelse: {
458 if (cur_block.size() < 2)
459 return error("empty control stack");
460 auto cond = data.PopAny();
461 bool truthy;
462 if (auto *ap = std::get_if<llvm::APSInt>(&cond))
463 truthy = !ap->isZero();
464 else if (auto *u = std::get_if<uint64_t>(&cond))
465 // Deprecated.
466 truthy = *u != 0;
467 else
468 return error("expected Integer or UInt");
469 if (!truthy)
470 control[control.size() - 2] = control.back();
471 control.pop_back();
472 activate_block();
473 continue;
474 }
475 case op_return:
476 control.clear();
477 return pc.takeError();
478
479 // Literals.
480 case op_lit_uint:
481 data.Push(cur_block.getULEB128(pc));
482 continue;
483 case op_lit_int:
484 data.Push(cur_block.getSLEB128(pc));
485 continue;
486 case op_lit_integer:
487 data.Push(cur_block.getSLEB128APSInt(pc));
488 continue;
489 case op_lit_selector:
490 data.Push(Selectors(cur_block.getU8(pc)));
491 continue;
492 case op_lit_null:
493 data.Push(ValueObjectSP());
494 continue;
495 case op_lit_string: {
496 uint64_t length = cur_block.getULEB128(pc);
497 llvm::StringRef bytes = cur_block.getBytes(pc, length);
498 data.Push(bytes.str());
499 continue;
500 }
501 case op_as_uint: {
503 uint64_t casted;
504 int64_t val = data.Pop<int64_t>();
505 memcpy(&casted, &val, sizeof(val));
506 data.Push(casted);
507 continue;
508 }
509 case op_as_int: {
511 int64_t casted;
512 uint64_t val = data.Pop<uint64_t>();
513 memcpy(&casted, &val, sizeof(val));
514 data.Push(casted);
515 continue;
516 }
517 case op_is_null: {
519 data.Push(data.Pop<ValueObjectSP>() ? (uint64_t)0 : (uint64_t)1);
520 continue;
521 }
522
523// Arithmetic operations.
524#define BINOP_IMPL(OP, CHECK_ZERO) \
525 { \
526 TYPE_CHECK(Any, Any); \
527 auto y = data.PopAny(); \
528 if (std::holds_alternative<uint64_t>(y)) { \
529 if (CHECK_ZERO && !std::get<uint64_t>(y)) \
530 return error(#OP " by zero"); \
531 TYPE_CHECK(UInt); \
532 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
533 } else if (std::holds_alternative<int64_t>(y)) { \
534 if (CHECK_ZERO && !std::get<int64_t>(y)) \
535 return error(#OP " by zero"); \
536 TYPE_CHECK(Int); \
537 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
538 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
539 TYPE_CHECK(Integer); \
540 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
541 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
542 if (lhs.isUnsigned() || rhs.isUnsigned()) \
543 return error("unsupported unsigned value"); \
544 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
545 lhs = lhs.extend(width); \
546 rhs = rhs.extend(width); \
547 if (CHECK_ZERO && rhs.isZero()) \
548 return error(#OP " by zero"); \
549 data.Push(WrapAPSIntResult(lhs OP rhs, width, lhs.isUnsigned())); \
550 } else \
551 return error("unsupported data types"); \
552 }
553#define BINOP(OP) BINOP_IMPL(OP, false)
554#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
555
556// Comparison operations.
557#define CMPOP(OP) \
558 { \
559 TYPE_CHECK(Any, Any); \
560 auto y = data.PopAny(); \
561 if (std::holds_alternative<uint64_t>(y)) { \
562 TYPE_CHECK(UInt); \
563 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
564 } else if (std::holds_alternative<int64_t>(y)) { \
565 TYPE_CHECK(Int); \
566 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
567 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
568 TYPE_CHECK(Integer); \
569 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
570 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
571 if (lhs.isUnsigned() || rhs.isUnsigned()) \
572 return error("unsupported unsigned value"); \
573 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
574 lhs = lhs.extend(width); \
575 rhs = rhs.extend(width); \
576 data.Push(WrapAPSIntResult(lhs OP rhs, width, lhs.isUnsigned())); \
577 } else \
578 return error("unsupported data types"); \
579 }
580
581// Bitwise operations use an Integer's underlying bit pattern, not its
582// mathematical value (ie signed-ness is ignored). This means >> is always a
583// logical (zero-filling) shift, never an arithmetic shift. Mismatched bit
584// widths are implicitly zero-extended (not sign-extended).
585#define BITOP(OP) \
586 { \
587 TYPE_CHECK(Any, Any); \
588 auto y = data.PopAny(); \
589 if (std::holds_alternative<uint64_t>(y)) { \
590 TYPE_CHECK(UInt); \
591 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
592 } else if (std::holds_alternative<int64_t>(y)) { \
593 TYPE_CHECK(Int); \
594 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
595 } else if (std::holds_alternative<llvm::APSInt>(y)) { \
596 TYPE_CHECK(Integer); \
597 llvm::APSInt rhs = std::get<llvm::APSInt>(y); \
598 llvm::APSInt lhs = data.Pop<llvm::APSInt>(); \
599 unsigned width = std::max(lhs.getBitWidth(), rhs.getBitWidth()); \
600 llvm::APInt lhs_bits = \
601 static_cast<const llvm::APInt &>(lhs).zext(width); \
602 llvm::APInt rhs_bits = \
603 static_cast<const llvm::APInt &>(rhs).zext(width); \
604 llvm::APInt bits = lhs_bits OP rhs_bits; \
605 data.Push(llvm::APSInt(std::move(bits), /*isUnsigned=*/false)); \
606 } else \
607 return error("unsupported data types"); \
608 }
609
610 case op_plus:
611 BINOP(+);
612 continue;
613 case op_minus:
614 BINOP(-);
615 continue;
616 case op_mul:
617 BINOP(*);
618 continue;
619 case op_div:
621 continue;
622 case op_mod:
624 continue;
625 case op_shl:
626#define SHIFTOP(OP, LEFT) \
627 { \
628 TYPE_CHECK(Any, UInt); \
629 uint64_t y = data.Pop<uint64_t>(); \
630 if (y > 64) \
631 return error("shift out of bounds"); \
632 if (std::holds_alternative<uint64_t>(data.back())) { \
633 uint64_t x = data.Pop<uint64_t>(); \
634 data.Push(x OP y); \
635 } else if (std::holds_alternative<int64_t>(data.back())) { \
636 int64_t x = data.Pop<int64_t>(); \
637 if (x < 0 && LEFT) \
638 return error("left shift of negative value"); \
639 if (y > 64) \
640 return error("shift out of bounds"); \
641 data.Push(x OP y); \
642 } else if (std::holds_alternative<llvm::APSInt>(data.back())) { \
643 llvm::APSInt x = data.Pop<llvm::APSInt>(); \
644 if (y > x.getBitWidth()) \
645 return error("shift out of bounds"); \
646 const llvm::APInt &bits = x; \
647 llvm::APInt shifted = \
648 LEFT ? bits.shl((unsigned)y) : bits.lshr((unsigned)y); \
649 data.Push(llvm::APSInt(std::move(shifted), /*isUnsigned=*/false)); \
650 } else \
651 return error("unsupported data types"); \
652 }
653 SHIFTOP(<<, true);
654 continue;
655 case op_shr:
656 SHIFTOP(>>, false);
657 continue;
658 case op_and:
659 BITOP(&);
660 continue;
661 case op_or:
662 BITOP(|);
663 continue;
664 case op_xor:
665 BITOP(^);
666 continue;
667 case op_not: {
669 auto x = data.PopAny();
670 if (std::holds_alternative<uint64_t>(x))
671 data.Push(~std::get<uint64_t>(x));
672 else if (auto *ap = std::get_if<llvm::APSInt>(&x)) {
673 llvm::APInt bits = ~static_cast<const llvm::APInt &>(*ap);
674 data.Push(llvm::APSInt(std::move(bits), /*isUnsigned=*/false));
675 } else
676 return error("unsupported data types");
677 continue;
678 }
679 case op_eq:
680 CMPOP(==);
681 continue;
682 case op_neq:
683 CMPOP(!=);
684 continue;
685 case op_lt:
686 CMPOP(<);
687 continue;
688 case op_gt:
689 CMPOP(>);
690 continue;
691 case op_le:
692 CMPOP(<=);
693 continue;
694 case op_ge:
695 CMPOP(>=);
696 continue;
697 case op_call: {
699 Selectors sel = data.Pop<Selectors>();
700
701 // Shorthand to improve readability.
702#define POP_VALOBJ(VALOBJ) \
703 auto VALOBJ = data.Pop<ValueObjectSP>(); \
704 if (!VALOBJ) \
705 return error("null object");
706
707 auto sel_error = [&](const char *msg) {
708 return llvm::createStringErrorV("{0} (opcode={1}, selector={2})", msg,
709 toString(opcode).c_str(),
710 toString(sel).c_str());
711 };
712
713 switch (sel) {
714 case sel_summary: {
716 POP_VALOBJ(valobj);
717 const char *summary = valobj->GetSummaryAsCString();
718 data.Push(summary ? std::string(valobj->GetSummaryAsCString())
719 : std::string());
720 break;
721 }
722 case sel_get_num_children: {
724 POP_VALOBJ(valobj);
725 auto result = valobj->GetNumChildren();
726 if (!result)
727 return result.takeError();
728 data.Push(MakeInt(*result, version));
729 break;
730 }
731 case sel_get_child_at_index: {
732 uint64_t index;
733 if (version >= 2) {
735 index = data.Pop<llvm::APSInt>().getLimitedValue(UINT32_MAX);
736 } else {
738 index = data.Pop<uint64_t>();
739 }
740 POP_VALOBJ(valobj);
741 data.Push(valobj->GetChildAtIndex(index));
742 break;
743 }
744 case sel_get_child_with_name: {
746 auto name = data.Pop<std::string>();
747 POP_VALOBJ(valobj);
748 data.Push(valobj->GetChildMemberWithName(name));
749 break;
750 }
751 case sel_get_child_index: {
753 auto name = data.Pop<std::string>();
754 POP_VALOBJ(valobj);
755 if (auto index_or_err = valobj->GetIndexOfChildWithName(name))
756 data.Push(MakeInt(*index_or_err, version));
757 else
758 return index_or_err.takeError();
759 break;
760 }
761 case sel_get_parent: {
763 POP_VALOBJ(valobj);
764 auto *parent = valobj->GetParent();
765 data.Push(parent ? parent->GetSP() : ValueObjectSP());
766 break;
767 }
768 case sel_get_type: {
770 POP_VALOBJ(valobj);
771 // FIXME: do we need to control dynamic type resolution?
772 data.Push(valobj->GetTypeImpl().GetCompilerType(false));
773 break;
774 }
775 case sel_get_template_argument_type: {
776 uint64_t index;
777 if (version >= 2) {
779 index = data.Pop<llvm::APSInt>().getLimitedValue();
780 } else {
782 index = data.Pop<uint64_t>();
783 }
784 auto type = data.Pop<CompilerType>();
785 // FIXME: There is more code in SBType::GetTemplateArgumentType().
786 data.Push(type.GetTypeTemplateArgument(index, true));
787 break;
788 }
789 case sel_get_synthetic_value: {
791 POP_VALOBJ(valobj);
792 data.Push(valobj->GetSyntheticValue());
793 break;
794 }
795 case sel_get_non_synthetic_value: {
797 POP_VALOBJ(valobj);
798 data.Push(valobj->GetNonSyntheticValue());
799 break;
800 }
801 case sel_get_value: {
803 POP_VALOBJ(valobj);
804 data.Push(std::string(valobj->GetValueAsCString()));
805 break;
806 }
807 case sel_get_value_as_unsigned: {
809 POP_VALOBJ(valobj);
810 bool success;
811 uint64_t val = valobj->GetValueAsUnsigned(0, &success);
812 data.Push(MakeInt(val, version));
813 if (!success)
814 return sel_error("failed to get value");
815 break;
816 }
817 case sel_get_value_as_signed: {
819 POP_VALOBJ(valobj);
820 bool success;
821 int64_t val = valobj->GetValueAsSigned(0, &success);
822 data.Push(MakeInt(val, version));
823 if (!success)
824 return sel_error("failed to get value");
825 break;
826 }
827 case sel_get_value_as_address: {
829 POP_VALOBJ(valobj);
830 bool success;
831 uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
832 if (!success)
833 return sel_error("failed to get value");
834 if (auto process_sp = valobj->GetProcessSP())
835 addr = process_sp->FixDataAddress(addr);
836 data.Push(MakeInt(addr, version));
837 break;
838 }
839 case sel_cast: {
841 auto type = data.Pop<CompilerType>();
842 POP_VALOBJ(valobj);
843 data.Push(valobj->Cast(type));
844 break;
845 }
846 case sel_clone: {
848 auto new_name = data.Pop<std::string>();
849 POP_VALOBJ(valobj);
850 data.Push(valobj->Clone(new_name));
851 break;
852 }
853 case sel_get_pointee_type: {
855 auto type = data.Pop<CompilerType>();
856 data.Push(type.GetPointeeType());
857 break;
858 }
859 case sel_get_byte_size: {
861 auto type = data.Pop<CompilerType>();
862 uint64_t size =
863 llvm::expectedToOptional(type.GetByteSize(nullptr)).value_or(0);
864 data.Push(llvm::APSInt::get(size));
865 break;
866 }
867 case sel_create_child_at_offset: {
869 auto type = data.Pop<CompilerType>();
870 auto offset = data.Pop<llvm::APSInt>().getLimitedValue(UINT32_MAX);
871 ConstString name(data.Pop<std::string>());
872 POP_VALOBJ(valobj);
873 data.Push(valobj->GetSyntheticChildAtOffset(offset, type, true, name));
874 break;
875 }
876 case sel_strlen: {
878 auto size = data.Pop<std::string>().size();
879 data.Push(MakeInt(size, version));
880 break;
881 }
882 case sel_fmt: {
884 if (auto error = FormatImpl(data, version))
885 return error;
886 break;
887 }
888 default:
889 return sel_error("selector not implemented");
890 }
891 continue;
892 }
893
894 // Dictionary operations.
895 case op_dict:
896 data.Push(std::make_shared<Dictionary>());
897 continue;
898 case op_dict_set: {
900 auto value = data.PopAny();
901 auto key = data.Pop<std::string>();
902 auto dict_sp = data.Pop<DictionarySP>();
903 if (auto *nested_sp = std::get_if<DictionarySP>(&value))
904 if (Reaches(nested_sp->get(), dict_sp.get()))
905 return error("dict_set would create a reference cycle");
906 (*dict_sp)[key] = std::move(value);
907 continue;
908 }
909 case op_dict_get: {
911 auto key = data.Pop<std::string>();
912 auto dict_sp = data.Pop<DictionarySP>();
913 auto it = dict_sp->find(key);
914 if (it == dict_sp->end())
915 return error("key not found in dictionary");
916 data.Push(it->second);
917 continue;
918 }
919 case op_dict_has: {
921 auto key = data.Pop<std::string>();
922 auto dict_sp = data.Pop<DictionarySP>();
923 bool found = dict_sp->find(key) != dict_sp->end();
924 data.Push(llvm::APSInt::get(found));
925 continue;
926 }
927 }
928 return error("opcode not implemented");
929 }
930 return pc.takeError();
931}
932} // namespace FormatterBytecode
933
934} // namespace lldb_private
static llvm::raw_ostream & error(Stream &strm)
#define BINOP(OP)
#define CMPOP(OP)
#define SHIFTOP(OP, LEFT)
#define BITOP(OP)
#define TYPE_CHECK(...)
#define POP_VALOBJ(VALOBJ)
#define BINOP_CHECKZERO(OP)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOG_VERBOSE(log,...)
Definition Log.h:382
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
#define UINT32_MAX
llvm::Error Interpret(ControlStack &control, DataStack &data, Signatures sig, uint32_t version)
Interpret the bytecode on control.
std::vector< ControlStackElement > ControlStack
std::variant< std::string, uint64_t, int64_t, lldb::ValueObjectSP, CompilerType, Selectors, llvm::APSInt, DictionarySP > DataStackElement
static DataStackElement MakeInt(T value, uint32_t version)
std::enable_if_t< std::is_integral_v< T > &&std::is_signed_v< T >, int > EnableIfSigned
static llvm::Error FormatImpl(DataStack &data, uint32_t version)
Implement the @format function.
static bool Reaches(const Dictionary *from, const Dictionary *target)
Returns true if target is transitively reachable via from.
static llvm::Error TypeCheck(llvm::ArrayRef< DataStackElement > data, DataType type)
std::shared_ptr< Dictionary > DictionarySP
static DataStackElement WrapAPSIntResult(T result, unsigned bit_width, bool is_unsigned)
Wrap the result of a binary operator applied to two APSInts back into a DataStackElement.
std::enable_if_t< std::is_integral_v< T > &&std::is_unsigned_v< T > && !std::is_same_v< T, bool >, int > EnableIfUnsigned
static llvm::Expected< std::string > SanitizeFormatString(llvm::StringRef fmt)
Check a format string, and remove the layout and options of each replacement.
@ Int
Deprecated: use Integer.
@ UInt
Deprecated: use Integer.
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
static uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
Definition ARMUtils.h:265
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP