brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.7 KiB · 714de74 Raw
583 lines · cpp
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-exception6//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 19using namespace lldb;20namespace lldb_private {21 22std::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_SIGNATURE31  }32  return llvm::utostr(op);33}34 35std::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_SIGNATURE42  }43  return "@" + llvm::utostr(sel);44}45 46std::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_SIGNATURE53  }54  return llvm::utostr(sig);55}56 57std::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      else72        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 84namespace FormatterBytecode {85 86/// Implement the @format function.87static 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      else123        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 133static 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 170static 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 177static 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 184llvm::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, the189  // 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      } else297        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        else496          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 FormatterBytecode581 582} // namespace lldb_private583