brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · 170f65a Raw
323 lines · cpp
1//===-- OptionArgParser.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 "lldb/Interpreter/OptionArgParser.h"10#include "lldb/DataFormatters/FormatManager.h"11#include "lldb/Target/ABI.h"12#include "lldb/Target/RegisterContext.h"13#include "lldb/Target/Target.h"14#include "lldb/Utility/RegisterValue.h"15#include "lldb/Utility/Status.h"16#include "lldb/Utility/StreamString.h"17 18using namespace lldb_private;19using namespace lldb;20 21bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,22                                bool *success_ptr) {23  if (success_ptr)24    *success_ptr = true;25  ref = ref.trim();26  if (ref.equals_insensitive("false") || ref.equals_insensitive("off") ||27      ref.equals_insensitive("no") || ref.equals_insensitive("0")) {28    return false;29  } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") ||30             ref.equals_insensitive("yes") || ref.equals_insensitive("1")) {31    return true;32  }33  if (success_ptr)34    *success_ptr = false;35  return fail_value;36}37 38llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name,39                                                llvm::StringRef option_arg) {40  bool parse_success;41  const bool option_value =42      ToBoolean(option_arg, false /* doesn't matter */, &parse_success);43  if (parse_success)44    return option_value;45  else46    return llvm::createStringError(47        "Invalid boolean value for option '%s': '%s'",48        option_name.str().c_str(),49        option_arg.empty() ? "<null>" : option_arg.str().c_str());50}51 52char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,53                             bool *success_ptr) {54  if (success_ptr)55    *success_ptr = false;56  if (s.size() != 1)57    return fail_value;58 59  if (success_ptr)60    *success_ptr = true;61  return s[0];62}63 64int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s,65                                      const OptionEnumValues &enum_values,66                                      int32_t fail_value, Status &error) {67  error.Clear();68  if (enum_values.empty()) {69    error = Status::FromErrorString("invalid enumeration argument");70    return fail_value;71  }72 73  if (s.empty()) {74    error = Status::FromErrorString("empty enumeration string");75    return fail_value;76  }77 78  for (const auto &enum_value : enum_values) {79    llvm::StringRef this_enum(enum_value.string_value);80    if (this_enum.starts_with(s))81      return enum_value.value;82  }83 84  StreamString strm;85  strm.PutCString("invalid enumeration value, valid values are: ");86  bool is_first = true;87  for (const auto &enum_value : enum_values) {88    strm.Printf("%s\"%s\"",89        is_first ? is_first = false,"" : ", ", enum_value.string_value);90  }91  error = Status(strm.GetString().str());92  return fail_value;93}94 95Status OptionArgParser::ToFormat(const char *s, lldb::Format &format,96                                 size_t *byte_size_ptr) {97  format = eFormatInvalid;98  Status error;99 100  if (s && s[0]) {101    if (byte_size_ptr) {102      if (isdigit(s[0])) {103        char *format_char = nullptr;104        unsigned long byte_size = ::strtoul(s, &format_char, 0);105        if (byte_size != ULONG_MAX)106          *byte_size_ptr = byte_size;107        s = format_char;108      } else109        *byte_size_ptr = 0;110    }111 112    if (!FormatManager::GetFormatFromCString(s, format)) {113      StreamString error_strm;114      error_strm.Printf(115          "Invalid format character or name '%s'. Valid values are:\n", s);116      for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) {117        char format_char = FormatManager::GetFormatAsFormatChar(f);118        if (format_char)119          error_strm.Printf("'%c' or ", format_char);120 121        error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f));122        error_strm.EOL();123      }124 125      if (byte_size_ptr)126        error_strm.PutCString(127            "An optional byte size can precede the format character.\n");128      error = Status(error_strm.GetString().str());129    }130 131    if (error.Fail())132      return error;133  } else {134    error = Status::FromErrorStringWithFormat("%s option string",135                                              s ? "empty" : "invalid");136  }137  return error;138}139 140lldb::ScriptLanguage OptionArgParser::ToScriptLanguage(141    llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) {142  if (success_ptr)143    *success_ptr = true;144 145  if (s.equals_insensitive("python"))146    return eScriptLanguagePython;147  if (s.equals_insensitive("lua"))148    return eScriptLanguageLua;149  if (s.equals_insensitive("default"))150    return eScriptLanguageDefault;151  if (s.equals_insensitive("none"))152    return eScriptLanguageNone;153 154  if (success_ptr)155    *success_ptr = false;156  return fail_value;157}158 159lldb::addr_t OptionArgParser::ToRawAddress(const ExecutionContext *exe_ctx,160                                           llvm::StringRef s,161                                           lldb::addr_t fail_value,162                                           Status *error_ptr) {163  std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);164  return maybe_addr.value_or(fail_value);165}166 167lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx,168                                        llvm::StringRef s,169                                        lldb::addr_t fail_value,170                                        Status *error_ptr) {171  std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);172  if (!maybe_addr)173    return fail_value;174 175  lldb::addr_t addr = *maybe_addr;176 177  if (Process *process = exe_ctx->GetProcessPtr())178    addr = process->FixAnyAddress(addr);179 180  return addr;181}182 183std::optional<lldb::addr_t>184OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s,185                             Status *error_ptr) {186  if (s.empty()) {187    if (error_ptr)188      *error_ptr = Status::FromErrorStringWithFormat(189          "invalid address expression \"%s\"", s.str().c_str());190    return {};191  }192 193  llvm::StringRef sref = s;194 195  lldb::addr_t addr = LLDB_INVALID_ADDRESS;196  if (!s.getAsInteger(0, addr)) {197    if (error_ptr)198      error_ptr->Clear();199 200    return addr;201  }202 203  // Try base 16 with no prefix...204  if (!s.getAsInteger(16, addr)) {205    if (error_ptr)206      error_ptr->Clear();207    return addr;208  }209 210  Target *target = nullptr;211  if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) {212    if (error_ptr)213      *error_ptr = Status::FromErrorStringWithFormat(214          "invalid address expression \"%s\"", s.str().c_str());215    return {};216  }217 218  lldb::ValueObjectSP valobj_sp;219  EvaluateExpressionOptions options;220  options.SetCoerceToId(false);221  options.SetUnwindOnError(true);222  options.SetKeepInMemory(false);223  options.SetTryAllThreads(true);224 225  ExpressionResults expr_result =226      target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options);227 228  bool success = false;229  if (expr_result == eExpressionCompleted) {230    if (valobj_sp)231      valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(232          valobj_sp->GetDynamicValueType(), true);233    // Get the address to watch.234    if (valobj_sp)235      addr = valobj_sp->GetValueAsUnsigned(0, &success);236    if (success) {237      if (error_ptr)238        error_ptr->Clear();239      return addr;240    }241    if (error_ptr)242      *error_ptr = Status::FromErrorStringWithFormat(243          "address expression \"%s\" resulted in a value whose type "244          "can't be converted to an address: %s",245          s.str().c_str(), valobj_sp->GetTypeName().GetCString());246    return {};247  }248 249  // Since the compiler can't handle things like "main + 12" we should try to250  // do this for now. The compiler doesn't like adding offsets to function251  // pointer types.252  // Some languages also don't have a natural representation for register253  // values (e.g. swift) so handle simple uses of them here as well.254  // We use a regex to parse these forms, the regex handles:255  // $reg_name256  // $reg_name+offset257  // symbol_name+offset258  //259  // The important matching elements in the regex below are:260  // 1: The reg name if there's no +offset261  // 3: The symbol/reg name if there is an offset262  // 4: +/-263  // 5: The offset value.264  // clang-format off265  static RegularExpression g_symbol_plus_offset_regex(266      "^(\\$[^ +-]+)|(([^ +-]+)[[:space:]]*([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*)$");267  // clang-format on268 269  llvm::SmallVector<llvm::StringRef, 4> matches;270  if (g_symbol_plus_offset_regex.Execute(sref, &matches)) {271    uint64_t offset = 0;272    llvm::StringRef name;273    if (!matches[1].empty())274      name = matches[1];275    else276      name = matches[3];277 278    llvm::StringRef sign = matches[4];279    llvm::StringRef str_offset = matches[5];280 281    // Some languages don't have a natural type for register values, but it282    // is still useful to look them up here:283    std::optional<lldb::addr_t> register_value;284    StackFrame *frame = exe_ctx->GetFramePtr();285    llvm::StringRef reg_name = name;286    if (frame && reg_name.consume_front("$")) {287      RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();288      if (reg_ctx_sp) {289        const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfoByName(reg_name);290        if (reg_info) {291          RegisterValue reg_val;292          bool success = reg_ctx_sp->ReadRegister(reg_info, reg_val);293          if (success && reg_val.GetType() != RegisterValue::eTypeInvalid) {294            register_value = reg_val.GetAsUInt64(0, &success);295            if (!success)296              register_value.reset();297          }298        }299      } 300    }301    if (!str_offset.empty() && !str_offset.getAsInteger(0, offset)) {302      Status error;303      if (register_value)304        addr = register_value.value();305      else306        addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error);307      if (addr != LLDB_INVALID_ADDRESS) {308        if (sign[0] == '+')309          return addr + offset;310        return addr - offset;311      }312    } else if (register_value)313      // In the case of register values, someone might just want to get the 314      // value in a language whose expression parser doesn't support registers.315      return register_value.value();316  }317 318  if (error_ptr)319    *error_ptr = Status::FromErrorStringWithFormat(320        "address expression \"%s\" evaluation failed", s.str().c_str());321  return {};322}323