12#include "llvm/ADT/StringExtras.h"
13#include "llvm/Support/DataExtractor.h"
14#include "llvm/Support/Format.h"
15#include "llvm/Support/FormatProviders.h"
16#include "llvm/Support/FormatVariadicDetails.h"
23#define DEFINE_OPCODE(OP, MNEMONIC, NAME) \
25 const char *s = MNEMONIC; \
26 return s ? s : #NAME; \
28#include "FormatterBytecode.def"
29#undef DEFINE_SIGNATURE
31 return llvm::utostr(op);
36#define DEFINE_SELECTOR(ID, NAME) \
39#include "FormatterBytecode.def"
40#undef DEFINE_SIGNATURE
42 return "@" + llvm::utostr(sel);
47#define DEFINE_SIGNATURE(ID, NAME) \
50#include "FormatterBytecode.def"
51#undef DEFINE_SIGNATURE
53 return llvm::utostr(sig);
58 llvm::raw_string_ostream os(s);
60 for (
auto &d : data) {
61 if (
auto s = std::get_if<std::string>(&d))
62 os <<
'"' << *s <<
'"';
63 else if (
auto u = std::get_if<uint64_t>(&d))
65 else if (
auto i = std::get_if<int64_t>(&d))
67 else if (
auto valobj = std::get_if<ValueObjectSP>(&d)) {
71 os <<
"object(" << valobj->get()->GetValueAsCString() <<
')';
72 }
else if (
auto type = std::get_if<CompilerType>(&d)) {
73 os <<
'(' << type->GetTypeName(
true) <<
')';
74 }
else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
83namespace FormatterBytecode {
87 auto fmt = data.
Pop<std::string>();
89 llvm::formatv_object_base::parseFormatString(fmt, 0,
false);
91 llvm::raw_string_ostream os(s);
92 unsigned num_args = 0;
93 for (
const auto &r : replacements)
94 if (r.Type == llvm::ReplacementType::Format)
95 num_args = std::max(num_args, r.Index + 1);
97 if (data.size() < num_args)
98 return llvm::createStringError(
"not enough arguments");
100 for (
const auto &r : replacements) {
101 if (r.Type == llvm::ReplacementType::Literal) {
105 using namespace llvm::support::detail;
106 auto arg = data[data.size() - num_args + r.Index];
107 auto format = [&](format_adapter &&adapter) {
108 llvm::FmtAlign
Align(adapter, r.Where, r.Width, r.Pad);
109 Align.format(os, r.Options);
112 if (
auto s = std::get_if<std::string>(&arg))
113 format(build_format_adapter(s->c_str()));
114 else if (
auto u = std::get_if<uint64_t>(&arg))
115 format(build_format_adapter(u));
116 else if (
auto i = std::get_if<int64_t>(&arg))
117 format(build_format_adapter(i));
118 else if (
auto valobj = std::get_if<ValueObjectSP>(&arg)) {
120 format(build_format_adapter(
"null object"));
122 format(build_format_adapter(valobj->get()->GetValueAsCString()));
123 }
else if (
auto type = std::get_if<CompilerType>(&arg))
124 format(build_format_adapter(type->GetDisplayTypeName()));
125 else if (
auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
126 format(build_format_adapter(
toString(*sel)));
129 return llvm::Error::success();
132static llvm::Error
TypeCheck(llvm::ArrayRef<DataStackElement> data,
135 return llvm::createStringError(
"not enough elements on data stack");
137 auto &elem = data.back();
142 if (!std::holds_alternative<std::string>(elem))
143 return llvm::createStringError(
"expected String");
146 if (!std::holds_alternative<uint64_t>(elem))
147 return llvm::createStringError(
"expected UInt");
150 if (!std::holds_alternative<int64_t>(elem))
151 return llvm::createStringError(
"expected Int");
154 if (!std::holds_alternative<ValueObjectSP>(elem))
155 return llvm::createStringError(
"expected Object");
158 if (!std::holds_alternative<CompilerType>(elem))
159 return llvm::createStringError(
"expected Type");
162 if (!std::holds_alternative<Selectors>(elem))
163 return llvm::createStringError(
"expected Selector");
166 return llvm::Error::success();
169static llvm::Error
TypeCheck(llvm::ArrayRef<DataStackElement> data,
173 return TypeCheck(data.drop_back(), type1);
176static llvm::Error
TypeCheck(llvm::ArrayRef<DataStackElement> data,
180 return TypeCheck(data.drop_back(1), type2, type1);
183llvm::Error
Interpret(std::vector<ControlStackElement> &control,
186 return llvm::Error::success();
189 llvm::DataExtractor cur_block(control.back(),
true, 64);
190 llvm::DataExtractor::Cursor
pc(0);
192 while (!control.empty()) {
194 auto activate_block = [&]() {
196 if (control.size() > 1)
197 control[control.size() - 2] = cur_block.getData().drop_front(
pc.tell());
198 cur_block = llvm::DataExtractor(control.back(),
true, 64);
200 pc = llvm::DataExtractor::Cursor(0);
204 auto next_byte = [&]() -> uint8_t {
206 while (
pc.tell() >= cur_block.size() && !control.empty()) {
207 if (control.size() == 1) {
216 return cur_block.getU8(
pc);
221 if (control.empty() || !
pc)
222 return pc.takeError();
225 "[eval {0}] opcode={1}, control={2}, data={3}",
toString(sel),
229#define TYPE_CHECK(...) \
230 if (auto error = TypeCheck(data, __VA_ARGS__)) \
233 auto error = [&](llvm::Twine msg) {
234 return llvm::createStringError(msg +
"(opcode=" +
toString(opcode) +
")");
241 data.
Push(data.back());
249 uint64_t idx = data.
Pop<uint64_t>();
250 if (idx >= data.size())
251 return error(
"index out of bounds");
252 data.
Push(data[idx]);
257 data.
Push(data[data.size() - 2]);
280 uint64_t length = cur_block.getULEB128(
pc);
282 return pc.takeError();
283 llvm::StringRef block = cur_block.getBytes(
pc, length);
285 return pc.takeError();
286 control.push_back(block);
291 if (data.
Pop<uint64_t>() != 0) {
292 if (!cur_block.size())
293 return error(
"empty control stack");
300 if (cur_block.size() < 2)
301 return error(
"empty control stack");
302 if (data.
Pop<uint64_t>() == 0)
303 control[control.size() - 2] = control.back();
310 data.
Push(cur_block.getULEB128(
pc));
313 data.
Push(cur_block.getSLEB128(
pc));
315 case op_lit_selector:
318 case op_lit_string: {
319 uint64_t length = cur_block.getULEB128(
pc);
320 llvm::StringRef bytes = cur_block.getBytes(
pc, length);
321 data.
Push(bytes.str());
327 int64_t val = data.
Pop<int64_t>();
328 memcpy(&casted, &val,
sizeof(val));
335 uint64_t val = data.
Pop<uint64_t>();
336 memcpy(&casted, &val,
sizeof(val));
347#define BINOP_IMPL(OP, CHECK_ZERO) \
349 TYPE_CHECK(Any, Any); \
350 auto y = data.PopAny(); \
351 if (std::holds_alternative<uint64_t>(y)) { \
352 if (CHECK_ZERO && !std::get<uint64_t>(y)) \
353 return error(#OP " by zero"); \
355 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
356 } else if (std::holds_alternative<int64_t>(y)) { \
357 if (CHECK_ZERO && !std::get<int64_t>(y)) \
358 return error(#OP " by zero"); \
360 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
362 return error("unsupported data types"); \
364#define BINOP(OP) BINOP_IMPL(OP, false)
365#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
382#define SHIFTOP(OP, LEFT) \
384 TYPE_CHECK(Any, UInt); \
385 uint64_t y = data.Pop<uint64_t>(); \
387 return error("shift out of bounds"); \
388 if (std::holds_alternative<uint64_t>(data.back())) { \
389 uint64_t x = data.Pop<uint64_t>(); \
391 } else if (std::holds_alternative<int64_t>(data.back())) { \
392 int64_t x = data.Pop<int64_t>(); \
394 return error("left shift of negative value"); \
396 return error("shift out of bounds"); \
399 return error("unsupported data types"); \
417 data.
Push(~data.
Pop<uint64_t>());
442#define POP_VALOBJ(VALOBJ) \
443 auto VALOBJ = data.Pop<ValueObjectSP>(); \
445 return error("null object");
447 auto sel_error = [&](
const char *msg) {
448 return llvm::createStringError(
"{0} (opcode={1}, selector={2})", msg,
457 const char *summary = valobj->GetSummaryAsCString();
458 data.
Push(summary ? std::string(valobj->GetSummaryAsCString())
462 case sel_get_num_children: {
465 auto result = valobj->GetNumChildren();
467 return result.takeError();
468 data.
Push((uint64_t)*result);
471 case sel_get_child_at_index: {
473 auto index = data.
Pop<uint64_t>();
475 data.
Push(valobj->GetChildAtIndex(index));
478 case sel_get_child_with_name: {
480 auto name = data.
Pop<std::string>();
482 data.
Push(valobj->GetChildMemberWithName(name));
485 case sel_get_child_index: {
487 auto name = data.
Pop<std::string>();
489 data.
Push((uint64_t)valobj->GetIndexOfChildWithName(name));
496 data.
Push(valobj->GetTypeImpl().GetCompilerType(
false));
499 case sel_get_template_argument_type: {
501 auto index = data.
Pop<uint64_t>();
504 data.
Push(type.GetTypeTemplateArgument(index,
true));
507 case sel_get_value: {
510 data.
Push(std::string(valobj->GetValueAsCString()));
513 case sel_get_value_as_unsigned: {
517 uint64_t val = valobj->GetValueAsUnsigned(0, &success);
520 return sel_error(
"failed to get value");
523 case sel_get_value_as_signed: {
527 int64_t val = valobj->GetValueAsSigned(0, &success);
530 return sel_error(
"failed to get value");
533 case sel_get_value_as_address: {
537 uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
539 return sel_error(
"failed to get value");
540 if (
auto process_sp = valobj->GetProcessSP())
541 addr = process_sp->FixDataAddress(addr);
549 data.
Push(valobj->Cast(type));
554 data.
Push((uint64_t)data.
Pop<std::string>().size());
564 return sel_error(
"selector not implemented");
569 return error(
"opcode not implemented");
571 return pc.takeError();
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGV(log,...)
Generic representation of a type in a programming language.
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.
static uint32_t Align(uint32_t val, uint32_t alignment)
const char * toString(AppleArm64ExceptionClass EC)
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP