diff options
Diffstat (limited to 'lldb/source/Interpreter/OptionGroupFormat.cpp')
| -rw-r--r-- | lldb/source/Interpreter/OptionGroupFormat.cpp | 267 | 
1 files changed, 267 insertions, 0 deletions
diff --git a/lldb/source/Interpreter/OptionGroupFormat.cpp b/lldb/source/Interpreter/OptionGroupFormat.cpp new file mode 100644 index 000000000000..c25e35f84517 --- /dev/null +++ b/lldb/source/Interpreter/OptionGroupFormat.cpp @@ -0,0 +1,267 @@ +//===-- OptionGroupFormat.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/OptionGroupFormat.h" + +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupFormat::OptionGroupFormat(lldb::Format default_format, +                                     uint64_t default_byte_size, +                                     uint64_t default_count) +    : m_format(default_format, default_format), +      m_byte_size(default_byte_size, default_byte_size), +      m_count(default_count, default_count), m_prev_gdb_format('x'), +      m_prev_gdb_size('w') {} + +OptionGroupFormat::~OptionGroupFormat() {} + +static constexpr OptionDefinition g_option_table[] = { +    {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument, +     nullptr, {}, 0, eArgTypeFormat, +     "Specify a format to be used for display."}, +    {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument, +     nullptr, {}, 0, eArgTypeGDBFormat, +     "Specify a format using a GDB format specifier string."}, +    {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument, +     nullptr, {}, 0, eArgTypeByteSize, +     "The size in bytes to use when displaying with the selected format."}, +    {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument, +     nullptr, {}, 0, eArgTypeCount, +     "The number of total items to display."}, +}; + +llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() { +  auto result = llvm::makeArrayRef(g_option_table); +  if (m_byte_size.GetDefaultValue() < UINT64_MAX) { +    if (m_count.GetDefaultValue() < UINT64_MAX) +      return result; +    else +      return result.take_front(3); +  } +  return result.take_front(2); +} + +Status OptionGroupFormat::SetOptionValue(uint32_t option_idx, +                                         llvm::StringRef option_arg, +                                         ExecutionContext *execution_context) { +  Status error; +  const int short_option = g_option_table[option_idx].short_option; + +  switch (short_option) { +  case 'f': +    error = m_format.SetValueFromString(option_arg); +    break; + +  case 'c': +    if (m_count.GetDefaultValue() == 0) { +      error.SetErrorString("--count option is disabled"); +    } else { +      error = m_count.SetValueFromString(option_arg); +      if (m_count.GetCurrentValue() == 0) +        error.SetErrorStringWithFormat("invalid --count option value '%s'", +                                       option_arg.str().c_str()); +    } +    break; + +  case 's': +    if (m_byte_size.GetDefaultValue() == 0) { +      error.SetErrorString("--size option is disabled"); +    } else { +      error = m_byte_size.SetValueFromString(option_arg); +      if (m_byte_size.GetCurrentValue() == 0) +        error.SetErrorStringWithFormat("invalid --size option value '%s'", +                                       option_arg.str().c_str()); +    } +    break; + +  case 'G': { +    uint64_t count = 0; +    llvm::StringRef gdb_format_str = option_arg; +    gdb_format_str.consumeInteger(0, count); + +    Format format = eFormatDefault; +    uint32_t byte_size = 0; + +    while (!gdb_format_str.empty() && +           ParserGDBFormatLetter(execution_context, gdb_format_str[0], format, +                                 byte_size)) { +      gdb_format_str = gdb_format_str.drop_front(); +    } + +    // We the first character of the "gdb_format_str" is not the +    // NULL terminator, we didn't consume the entire string and +    // something is wrong. Also, if none of the format, size or count was +    // specified correctly, then abort. +    if (!gdb_format_str.empty() || +        (format == eFormatInvalid && byte_size == 0 && count == 0)) { +      // Nothing got set correctly +      error.SetErrorStringWithFormat("invalid gdb format string '%s'", +                                     option_arg.str().c_str()); +      return error; +    } + +    // At least one of the format, size or count was set correctly. Anything +    // that wasn't set correctly should be set to the previous default +    if (format == eFormatInvalid) +      ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format, +                            byte_size); + +    const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX; +    const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX; +    if (byte_size_enabled) { +      // Byte size is enabled +      if (byte_size == 0) +        ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format, +                              byte_size); +    } else { +      // Byte size is disabled, make sure it wasn't specified but if this is an +      // address, it's actually necessary to specify one so don't error out +      if (byte_size > 0 && format != lldb::eFormatAddressInfo) { +        error.SetErrorString( +            "this command doesn't support specifying a byte size"); +        return error; +      } +    } + +    if (count_enabled) { +      // Count is enabled and was not set, set it to the default for gdb format +      // statements (which is 1). +      if (count == 0) +        count = 1; +    } else { +      // Count is disabled, make sure it wasn't specified +      if (count > 0) { +        error.SetErrorString("this command doesn't support specifying a count"); +        return error; +      } +    } + +    m_format.SetCurrentValue(format); +    m_format.SetOptionWasSet(); +    if (byte_size_enabled) { +      m_byte_size.SetCurrentValue(byte_size); +      m_byte_size.SetOptionWasSet(); +    } +    if (count_enabled) { +      m_count.SetCurrentValue(count); +      m_count.SetOptionWasSet(); +    } +  } break; + +  default: +    llvm_unreachable("Unimplemented option"); +  } + +  return error; +} + +bool OptionGroupFormat::ParserGDBFormatLetter( +    ExecutionContext *execution_context, char format_letter, Format &format, +    uint32_t &byte_size) { +  m_has_gdb_format = true; +  switch (format_letter) { +  case 'o': +    format = eFormatOctal; +    m_prev_gdb_format = format_letter; +    return true; +  case 'x': +    format = eFormatHex; +    m_prev_gdb_format = format_letter; +    return true; +  case 'd': +    format = eFormatDecimal; +    m_prev_gdb_format = format_letter; +    return true; +  case 'u': +    format = eFormatUnsigned; +    m_prev_gdb_format = format_letter; +    return true; +  case 't': +    format = eFormatBinary; +    m_prev_gdb_format = format_letter; +    return true; +  case 'f': +    format = eFormatFloat; +    m_prev_gdb_format = format_letter; +    return true; +  case 'a': +    format = eFormatAddressInfo; +    { +      TargetSP target_sp = +          execution_context ? execution_context->GetTargetSP() : TargetSP(); +      if (target_sp) +        byte_size = target_sp->GetArchitecture().GetAddressByteSize(); +      m_prev_gdb_format = format_letter; +      return true; +    } +  case 'i': +    format = eFormatInstruction; +    m_prev_gdb_format = format_letter; +    return true; +  case 'c': +    format = eFormatChar; +    m_prev_gdb_format = format_letter; +    return true; +  case 's': +    format = eFormatCString; +    m_prev_gdb_format = format_letter; +    return true; +  case 'T': +    format = eFormatOSType; +    m_prev_gdb_format = format_letter; +    return true; +  case 'A': +    format = eFormatHexFloat; +    m_prev_gdb_format = format_letter; +    return true; + +  case 'b': +  case 'h': +  case 'w': +  case 'g': +    { +      // Size isn't used for printing instructions, so if a size is specified, +      // and the previous format was 'i', then we should reset it to the +      // default ('x').  Otherwise we'll continue to print as instructions, +      // which isn't expected. +      if (format_letter == 'b') +          byte_size = 1; +      else if (format_letter == 'h') +          byte_size = 2; +      else if (format_letter == 'w') +          byte_size = 4; +      else if (format_letter == 'g') +          byte_size = 8; + +        m_prev_gdb_size = format_letter; +        if (m_prev_gdb_format == 'i') +          m_prev_gdb_format = 'x'; +        return true; +    } +    break; +  default: +    break; +  } + + +  return false; +} + +void OptionGroupFormat::OptionParsingStarting( +    ExecutionContext *execution_context) { +  m_format.Clear(); +  m_byte_size.Clear(); +  m_count.Clear(); +  m_has_gdb_format = false; +}  | 
