summaryrefslogtreecommitdiff
path: root/lldb/source/DataFormatters/FormatterBytecode.cpp
diff options
context:
space:
mode:
authorSylvestre Ledru <sylvestre@debian.org>2024-12-10 23:59:54 +0100
committerSylvestre Ledru <sylvestre@debian.org>2024-12-11 00:00:44 +0100
commita2fb70523ac310af6d8a4d9663dfe7c9cd370c53 (patch)
tree78b2ea08853a809c0ab7e4e0021caf96ee5addd8 /lldb/source/DataFormatters/FormatterBytecode.cpp
parentcf27e8ea04c39a0f20d465563241bdf2872f2bd7 (diff)
Revert "[lldb] Add cast to fix compile error on 32-bit platforms"
This reverts commit f6012a209dca6b1866d00e6b4f96279469884320. Revert "[lldb] Add cast to fix compile error on 32-but platforms" This reverts commit d300337e93da4ed96b044557e4b0a30001967cf0. Revert "[lldb] Improve log message to include missing strings" This reverts commit 0be33484853557bc0fd9dfb94e0b6c15dda136ce. Revert "[lldb] Add comment" This reverts commit e2bb47443d2e5c022c7851dd6029e3869fc8835c. Revert "[lldb] Implement a formatter bytecode interpreter in C++" This reverts commit 9a9c1d4a6155a96ce9be494cec7e25731d36b33e.
Diffstat (limited to 'lldb/source/DataFormatters/FormatterBytecode.cpp')
-rw-r--r--lldb/source/DataFormatters/FormatterBytecode.cpp575
1 files changed, 0 insertions, 575 deletions
diff --git a/lldb/source/DataFormatters/FormatterBytecode.cpp b/lldb/source/DataFormatters/FormatterBytecode.cpp
deleted file mode 100644
index 21e90e75202f..000000000000
--- a/lldb/source/DataFormatters/FormatterBytecode.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-//===-- FormatterBytecode.cpp ---------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "FormatterBytecode.h"
-#include "lldb/Utility/LLDBLog.h"
-#include "lldb/ValueObject/ValueObject.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/FormatProviders.h"
-#include "llvm/Support/FormatVariadicDetails.h"
-
-using namespace lldb;
-namespace lldb_private {
-
-std::string toString(FormatterBytecode::OpCodes op) {
- switch (op) {
-#define DEFINE_OPCODE(OP, MNEMONIC, NAME) \
- case OP: { \
- const char *s = MNEMONIC; \
- return s ? s : #NAME; \
- }
-#include "FormatterBytecode.def"
-#undef DEFINE_SIGNATURE
- }
- return llvm::utostr(op);
-}
-
-std::string toString(FormatterBytecode::Selectors sel) {
- switch (sel) {
-#define DEFINE_SELECTOR(ID, NAME) \
- case ID: \
- return "@" #NAME;
-#include "FormatterBytecode.def"
-#undef DEFINE_SIGNATURE
- }
- return "@" + llvm::utostr(sel);
-}
-
-std::string toString(FormatterBytecode::Signatures sig) {
- switch (sig) {
-#define DEFINE_SIGNATURE(ID, NAME) \
- case ID: \
- return "@" #NAME;
-#include "FormatterBytecode.def"
-#undef DEFINE_SIGNATURE
- }
- return llvm::utostr(sig);
-}
-
-std::string toString(const FormatterBytecode::DataStack &data) {
- std::string s;
- llvm::raw_string_ostream os(s);
- os << "[ ";
- for (auto &d : data) {
- if (auto s = std::get_if<std::string>(&d))
- os << '"' << *s << '"';
- else if (auto u = std::get_if<uint64_t>(&d))
- os << *u << 'u';
- else if (auto i = std::get_if<int64_t>(&d))
- os << *i;
- else if (auto valobj = std::get_if<ValueObjectSP>(&d)) {
- if (!valobj->get())
- os << "null";
- else
- os << "object(" << valobj->get()->GetValueAsCString() << ')';
- } else if (auto type = std::get_if<CompilerType>(&d)) {
- os << '(' << type->GetTypeName(true) << ')';
- } else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
- os << toString(*sel);
- }
- os << ' ';
- }
- os << ']';
- return s;
-}
-
-namespace FormatterBytecode {
-
-/// Implement the @format function.
-static llvm::Error FormatImpl(DataStack &data) {
- auto fmt = data.Pop<std::string>();
- auto replacements =
- llvm::formatv_object_base::parseFormatString(fmt, 0, false);
- std::string s;
- llvm::raw_string_ostream os(s);
- unsigned num_args = 0;
- for (const auto &r : replacements)
- if (r.Type == llvm::ReplacementType::Format)
- num_args = std::max(num_args, r.Index + 1);
-
- if (data.size() < num_args)
- return llvm::createStringError("not enough arguments");
-
- for (const auto &r : replacements) {
- if (r.Type == llvm::ReplacementType::Literal) {
- os << r.Spec;
- continue;
- }
- using namespace llvm::support::detail;
- auto arg = data[data.size() - num_args + r.Index];
- auto format = [&](format_adapter &&adapter) {
- llvm::FmtAlign Align(adapter, r.Where, r.Width, r.Pad);
- Align.format(os, r.Options);
- };
-
- if (auto s = std::get_if<std::string>(&arg))
- format(build_format_adapter(s->c_str()));
- else if (auto u = std::get_if<uint64_t>(&arg))
- format(build_format_adapter(u));
- else if (auto i = std::get_if<int64_t>(&arg))
- format(build_format_adapter(i));
- else if (auto valobj = std::get_if<ValueObjectSP>(&arg)) {
- if (!valobj->get())
- format(build_format_adapter("null object"));
- else
- format(build_format_adapter(valobj->get()->GetValueAsCString()));
- } else if (auto type = std::get_if<CompilerType>(&arg))
- format(build_format_adapter(type->GetDisplayTypeName()));
- else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
- format(build_format_adapter(toString(*sel)));
- }
- data.Push(s);
- return llvm::Error::success();
-}
-
-static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
- DataType type) {
- if (data.size() < 1)
- return llvm::createStringError("not enough elements on data stack");
-
- auto &elem = data.back();
- switch (type) {
- case Any:
- break;
- case String:
- if (!std::holds_alternative<std::string>(elem))
- return llvm::createStringError("expected String");
- break;
- case UInt:
- if (!std::holds_alternative<uint64_t>(elem))
- return llvm::createStringError("expected UInt");
- break;
- case Int:
- if (!std::holds_alternative<int64_t>(elem))
- return llvm::createStringError("expected Int");
- break;
- case Object:
- if (!std::holds_alternative<ValueObjectSP>(elem))
- return llvm::createStringError("expected Object");
- break;
- case Type:
- if (!std::holds_alternative<CompilerType>(elem))
- return llvm::createStringError("expected Type");
- break;
- case Selector:
- if (!std::holds_alternative<Selectors>(elem))
- return llvm::createStringError("expected Selector");
- break;
- }
- return llvm::Error::success();
-}
-
-static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
- DataType type1, DataType type2) {
- if (auto error = TypeCheck(data, type2))
- return error;
- return TypeCheck(data.drop_back(), type1);
-}
-
-static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
- DataType type1, DataType type2, DataType type3) {
- if (auto error = TypeCheck(data, type3))
- return error;
- return TypeCheck(data.drop_back(1), type2, type1);
-}
-
-llvm::Error Interpret(std::vector<ControlStackElement> &control,
- DataStack &data, Selectors sel) {
- if (control.empty())
- return llvm::Error::success();
- // Since the only data types are single endian and ULEBs, the
- // endianness should not matter.
- llvm::DataExtractor cur_block(control.back(), true, 64);
- llvm::DataExtractor::Cursor pc(0);
-
- while (!control.empty()) {
- /// Activate the top most block from the control stack.
- auto activate_block = [&]() {
- // Save the return address.
- if (control.size() > 1)
- control[control.size() - 2] = cur_block.getData().drop_front(pc.tell());
- cur_block = llvm::DataExtractor(control.back(), true, 64);
- if (pc)
- pc = llvm::DataExtractor::Cursor(0);
- };
-
- /// Fetch the next byte in the instruction stream.
- auto next_byte = [&]() -> uint8_t {
- // At the end of the current block?
- while (pc.tell() >= cur_block.size() && !control.empty()) {
- if (control.size() == 1) {
- control.pop_back();
- return 0;
- }
- control.pop_back();
- activate_block();
- }
-
- // Fetch the next instruction.
- return cur_block.getU8(pc);
- };
-
- // Fetch the next opcode.
- OpCodes opcode = (OpCodes)next_byte();
- if (control.empty() || !pc)
- return pc.takeError();
-
- LLDB_LOGV(GetLog(LLDBLog::DataFormatters),
- "[eval {0}] opcode={1}, control={2}, data={3}", toString(sel),
- toString(opcode), control.size(), toString(data));
-
- // Various shorthands to improve the readability of error handling.
-#define TYPE_CHECK(...) \
- if (auto error = TypeCheck(data, __VA_ARGS__)) \
- return error;
-
- auto error = [&](llvm::Twine msg) {
- return llvm::createStringError(msg + "(opcode=" + toString(opcode) + ")");
- };
-
- switch (opcode) {
- // Data stack manipulation.
- case op_dup:
- TYPE_CHECK(Any);
- data.Push(data.back());
- continue;
- case op_drop:
- TYPE_CHECK(Any);
- data.pop_back();
- continue;
- case op_pick: {
- TYPE_CHECK(UInt);
- uint64_t idx = data.Pop<uint64_t>();
- if (idx >= data.size())
- return error("index out of bounds");
- data.Push(data[idx]);
- continue;
- }
- case op_over:
- TYPE_CHECK(Any, Any);
- data.Push(data[data.size() - 2]);
- continue;
- case op_swap: {
- TYPE_CHECK(Any, Any);
- auto x = data.PopAny();
- auto y = data.PopAny();
- data.Push(x);
- data.Push(y);
- continue;
- }
- case op_rot: {
- TYPE_CHECK(Any, Any, Any);
- auto z = data.PopAny();
- auto y = data.PopAny();
- auto x = data.PopAny();
- data.Push(z);
- data.Push(x);
- data.Push(y);
- continue;
- }
-
- // Control stack manipulation.
- case op_begin: {
- uint64_t length = cur_block.getULEB128(pc);
- if (!pc)
- return pc.takeError();
- llvm::StringRef block = cur_block.getBytes(pc, length);
- if (!pc)
- return pc.takeError();
- control.push_back(block);
- continue;
- }
- case op_if:
- TYPE_CHECK(UInt);
- if (data.Pop<uint64_t>() != 0) {
- if (!cur_block.size())
- return error("empty control stack");
- activate_block();
- } else
- control.pop_back();
- continue;
- case op_ifelse:
- TYPE_CHECK(UInt);
- if (cur_block.size() < 2)
- return error("empty control stack");
- if (data.Pop<uint64_t>() == 0)
- control[control.size() - 2] = control.back();
- control.pop_back();
- activate_block();
- continue;
-
- // Literals.
- case op_lit_uint:
- data.Push(cur_block.getULEB128(pc));
- continue;
- case op_lit_int:
- data.Push(cur_block.getSLEB128(pc));
- continue;
- case op_lit_selector:
- data.Push(Selectors(cur_block.getU8(pc)));
- continue;
- case op_lit_string: {
- uint64_t length = cur_block.getULEB128(pc);
- llvm::StringRef bytes = cur_block.getBytes(pc, length);
- data.Push(bytes.str());
- continue;
- }
- case op_as_uint: {
- TYPE_CHECK(Int);
- uint64_t casted;
- int64_t val = data.Pop<int64_t>();
- memcpy(&casted, &val, sizeof(val));
- data.Push(casted);
- continue;
- }
- case op_as_int: {
- TYPE_CHECK(UInt);
- int64_t casted;
- uint64_t val = data.Pop<uint64_t>();
- memcpy(&casted, &val, sizeof(val));
- data.Push(casted);
- continue;
- }
- case op_is_null: {
- TYPE_CHECK(Object);
- data.Push(data.Pop<ValueObjectSP>() ? 0ULL : 1ULL);
- continue;
- }
-
- // Arithmetic, logic, etc.
-#define BINOP_IMPL(OP, CHECK_ZERO) \
- { \
- TYPE_CHECK(Any, Any); \
- auto y = data.PopAny(); \
- if (std::holds_alternative<uint64_t>(y)) { \
- if (CHECK_ZERO && !std::get<uint64_t>(y)) \
- return error(#OP " by zero"); \
- TYPE_CHECK(UInt); \
- data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
- } else if (std::holds_alternative<int64_t>(y)) { \
- if (CHECK_ZERO && !std::get<int64_t>(y)) \
- return error(#OP " by zero"); \
- TYPE_CHECK(Int); \
- data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
- } else \
- return error("unsupported data types"); \
- }
-#define BINOP(OP) BINOP_IMPL(OP, false)
-#define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
- case op_plus:
- BINOP(+);
- continue;
- case op_minus:
- BINOP(-);
- continue;
- case op_mul:
- BINOP(*);
- continue;
- case op_div:
- BINOP_CHECKZERO(/);
- continue;
- case op_mod:
- BINOP_CHECKZERO(%);
- continue;
- case op_shl:
-#define SHIFTOP(OP) \
- { \
- TYPE_CHECK(Any, UInt); \
- uint64_t y = data.Pop<uint64_t>(); \
- if (y > 64) \
- return error("shift out of bounds"); \
- if (std::holds_alternative<uint64_t>(data.back())) { \
- uint64_t x = data.Pop<uint64_t>(); \
- data.Push(x OP y); \
- } else if (std::holds_alternative<int64_t>(data.back())) { \
- int64_t x = data.Pop<int64_t>(); \
- if (y > 64) \
- return error("shift out of bounds"); \
- if (y < 0) \
- return error("shift out of bounds"); \
- data.Push(x OP y); \
- } else \
- return error("unsupported data types"); \
- }
- SHIFTOP(<<);
- continue;
- case op_shr:
- SHIFTOP(<<);
- continue;
- case op_and:
- BINOP(&);
- continue;
- case op_or:
- BINOP(|);
- continue;
- case op_xor:
- BINOP(^);
- continue;
- case op_not:
- TYPE_CHECK(UInt);
- data.Push(~data.Pop<uint64_t>());
- continue;
- case op_eq:
- BINOP(==);
- continue;
- case op_neq:
- BINOP(!=);
- continue;
- case op_lt:
- BINOP(<);
- continue;
- case op_gt:
- BINOP(>);
- continue;
- case op_le:
- BINOP(<=);
- continue;
- case op_ge:
- BINOP(>=);
- continue;
- case op_call: {
- TYPE_CHECK(Selector);
- Selectors sel = data.Pop<Selectors>();
-
- // Shorthand to improve readability.
-#define POP_VALOBJ(VALOBJ) \
- auto VALOBJ = data.Pop<ValueObjectSP>(); \
- if (!VALOBJ) \
- return error("null object");
-
- auto sel_error = [&](const char *msg) {
- return llvm::createStringError("{0} (opcode={1}, selector={2})", msg,
- toString(opcode).c_str(),
- toString(sel).c_str());
- };
-
- switch (sel) {
- case sel_summary: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- const char *summary = valobj->GetSummaryAsCString();
- data.Push(summary ? std::string(valobj->GetSummaryAsCString())
- : std::string());
- break;
- }
- case sel_get_num_children: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- auto result = valobj->GetNumChildren();
- if (!result)
- return result.takeError();
- data.Push((uint64_t)*result);
- break;
- }
- case sel_get_child_at_index: {
- TYPE_CHECK(Object, UInt);
- auto index = data.Pop<uint64_t>();
- POP_VALOBJ(valobj);
- data.Push(valobj->GetChildAtIndex(index));
- break;
- }
- case sel_get_child_with_name: {
- TYPE_CHECK(Object, String);
- auto name = data.Pop<std::string>();
- POP_VALOBJ(valobj);
- data.Push(valobj->GetChildMemberWithName(name));
- break;
- }
- case sel_get_child_index: {
- TYPE_CHECK(Object, String);
- auto name = data.Pop<std::string>();
- POP_VALOBJ(valobj);
- data.Push((uint64_t)valobj->GetIndexOfChildWithName(name));
- break;
- }
- case sel_get_type: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- // FIXME: do we need to control dynamic type resolution?
- data.Push(valobj->GetTypeImpl().GetCompilerType(false));
- break;
- }
- case sel_get_template_argument_type: {
- TYPE_CHECK(Type, UInt);
- auto index = data.Pop<uint64_t>();
- auto type = data.Pop<CompilerType>();
- // FIXME: There is more code in SBType::GetTemplateArgumentType().
- data.Push(type.GetTypeTemplateArgument(index, true));
- break;
- }
- case sel_get_value: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- data.Push(std::string(valobj->GetValueAsCString()));
- break;
- }
- case sel_get_value_as_unsigned: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- bool success;
- uint64_t val = valobj->GetValueAsUnsigned(0, &success);
- data.Push(val);
- if (!success)
- return sel_error("failed to get value");
- break;
- }
- case sel_get_value_as_signed: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- bool success;
- int64_t val = valobj->GetValueAsSigned(0, &success);
- data.Push(val);
- if (!success)
- return sel_error("failed to get value");
- break;
- }
- case sel_get_value_as_address: {
- TYPE_CHECK(Object);
- POP_VALOBJ(valobj);
- bool success;
- uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
- if (!success)
- return sel_error("failed to get value");
- if (auto process_sp = valobj->GetProcessSP())
- addr = process_sp->FixDataAddress(addr);
- data.Push(addr);
- break;
- }
- case sel_cast: {
- TYPE_CHECK(Object, Type);
- auto type = data.Pop<CompilerType>();
- POP_VALOBJ(valobj);
- data.Push(valobj->Cast(type));
- break;
- }
- case sel_strlen: {
- TYPE_CHECK(String);
- data.Push((uint64_t)data.Pop<std::string>().size());
- break;
- }
- case sel_fmt: {
- TYPE_CHECK(String);
- if (auto error = FormatImpl(data))
- return error;
- break;
- }
- default:
- return sel_error("selector not implemented");
- }
- continue;
- }
- }
- return error("opcode not implemented");
- }
- return pc.takeError();
-}
-} // namespace FormatterBytecode
-
-} // namespace lldb_private