diff options
Diffstat (limited to 'lldb/source/Interpreter/OptionArgParser.cpp')
| -rw-r--r-- | lldb/source/Interpreter/OptionArgParser.cpp | 246 | 
1 files changed, 246 insertions, 0 deletions
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp new file mode 100644 index 000000000000..14b81cd7b3d2 --- /dev/null +++ b/lldb/source/Interpreter/OptionArgParser.cpp @@ -0,0 +1,246 @@ +//===-- OptionArgParser.cpp -------------------------------------*- C++ -*-===// +// +// 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 "lldb/Interpreter/OptionArgParser.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb_private; +using namespace lldb; + +bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value, +                                bool *success_ptr) { +  if (success_ptr) +    *success_ptr = true; +  ref = ref.trim(); +  if (ref.equals_lower("false") || ref.equals_lower("off") || +      ref.equals_lower("no") || ref.equals_lower("0")) { +    return false; +  } else if (ref.equals_lower("true") || ref.equals_lower("on") || +             ref.equals_lower("yes") || ref.equals_lower("1")) { +    return true; +  } +  if (success_ptr) +    *success_ptr = false; +  return fail_value; +} + +char OptionArgParser::ToChar(llvm::StringRef s, char fail_value, +                             bool *success_ptr) { +  if (success_ptr) +    *success_ptr = false; +  if (s.size() != 1) +    return fail_value; + +  if (success_ptr) +    *success_ptr = true; +  return s[0]; +} + +int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s, +                                      const OptionEnumValues &enum_values, +                                      int32_t fail_value, Status &error) { +  error.Clear(); +  if (enum_values.empty()) { +    error.SetErrorString("invalid enumeration argument"); +    return fail_value; +  } + +  if (s.empty()) { +    error.SetErrorString("empty enumeration string"); +    return fail_value; +  } + +  for (const auto &enum_value : enum_values) { +    llvm::StringRef this_enum(enum_value.string_value); +    if (this_enum.startswith(s)) +      return enum_value.value; +  } + +  StreamString strm; +  strm.PutCString("invalid enumeration value, valid values are: "); +  bool is_first = true; +  for (const auto &enum_value : enum_values) { +    strm.Printf("%s\"%s\"", +        is_first ? is_first = false,"" : ", ", enum_value.string_value); +  } +  error.SetErrorString(strm.GetString()); +  return fail_value; +} + +Status OptionArgParser::ToFormat(const char *s, lldb::Format &format, +                                 size_t *byte_size_ptr) { +  format = eFormatInvalid; +  Status error; + +  if (s && s[0]) { +    if (byte_size_ptr) { +      if (isdigit(s[0])) { +        char *format_char = nullptr; +        unsigned long byte_size = ::strtoul(s, &format_char, 0); +        if (byte_size != ULONG_MAX) +          *byte_size_ptr = byte_size; +        s = format_char; +      } else +        *byte_size_ptr = 0; +    } + +    const bool partial_match_ok = true; +    if (!FormatManager::GetFormatFromCString(s, partial_match_ok, format)) { +      StreamString error_strm; +      error_strm.Printf( +          "Invalid format character or name '%s'. Valid values are:\n", s); +      for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) { +        char format_char = FormatManager::GetFormatAsFormatChar(f); +        if (format_char) +          error_strm.Printf("'%c' or ", format_char); + +        error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f)); +        error_strm.EOL(); +      } + +      if (byte_size_ptr) +        error_strm.PutCString( +            "An optional byte size can precede the format character.\n"); +      error.SetErrorString(error_strm.GetString()); +    } + +    if (error.Fail()) +      return error; +  } else { +    error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); +  } +  return error; +} + +lldb::ScriptLanguage OptionArgParser::ToScriptLanguage( +    llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) { +  if (success_ptr) +    *success_ptr = true; + +  if (s.equals_lower("python")) +    return eScriptLanguagePython; +  if (s.equals_lower("default")) +    return eScriptLanguageDefault; +  if (s.equals_lower("none")) +    return eScriptLanguageNone; + +  if (success_ptr) +    *success_ptr = false; +  return fail_value; +} + +lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx, +                                        llvm::StringRef s, +                                        lldb::addr_t fail_value, +                                        Status *error_ptr) { +  bool error_set = false; +  if (s.empty()) { +    if (error_ptr) +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str()); +    return fail_value; +  } + +  llvm::StringRef sref = s; + +  lldb::addr_t addr = LLDB_INVALID_ADDRESS; +  if (!s.getAsInteger(0, addr)) { +    if (error_ptr) +      error_ptr->Clear(); +    return addr; +  } + +  // Try base 16 with no prefix... +  if (!s.getAsInteger(16, addr)) { +    if (error_ptr) +      error_ptr->Clear(); +    return addr; +  } + +  Target *target = nullptr; +  if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) { +    if (error_ptr) +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str()); +    return fail_value; +  } + +  lldb::ValueObjectSP valobj_sp; +  EvaluateExpressionOptions options; +  options.SetCoerceToId(false); +  options.SetUnwindOnError(true); +  options.SetKeepInMemory(false); +  options.SetTryAllThreads(true); + +  ExpressionResults expr_result = +      target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options); + +  bool success = false; +  if (expr_result == eExpressionCompleted) { +    if (valobj_sp) +      valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable( +          valobj_sp->GetDynamicValueType(), true); +    // Get the address to watch. +    if (valobj_sp) +      addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); +    if (success) { +      if (error_ptr) +        error_ptr->Clear(); +      return addr; +    } else { +      if (error_ptr) { +        error_set = true; +        error_ptr->SetErrorStringWithFormat( +            "address expression \"%s\" resulted in a value whose type " +            "can't be converted to an address: %s", +            s.str().c_str(), valobj_sp->GetTypeName().GetCString()); +      } +    } + +  } else { +    // Since the compiler can't handle things like "main + 12" we should try to +    // do this for now. The compiler doesn't like adding offsets to function +    // pointer types. +    static RegularExpression g_symbol_plus_offset_regex( +        "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); + +    llvm::SmallVector<llvm::StringRef, 4> matches; +    if (g_symbol_plus_offset_regex.Execute(sref, &matches)) { +      uint64_t offset = 0; +      std::string name = matches[1].str(); +      std::string sign = matches[2].str(); +      std::string str_offset = matches[3].str(); +      if (!llvm::StringRef(str_offset).getAsInteger(0, offset)) { +        Status error; +        addr = ToAddress(exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); +        if (addr != LLDB_INVALID_ADDRESS) { +          if (sign[0] == '+') +            return addr + offset; +          else +            return addr - offset; +        } +      } +    } + +    if (error_ptr) { +      error_set = true; +      error_ptr->SetErrorStringWithFormat( +          "address expression \"%s\" evaluation failed", s.str().c_str()); +    } +  } + +  if (error_ptr) { +    if (!error_set) +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str()); +  } +  return fail_value; +}  | 
