diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp new file mode 100644 index 000000000000..6b56ad2ea819 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp @@ -0,0 +1,283 @@ +//===-- OptionGroupFormat.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 "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; + +static constexpr OptionDefinition g_default_option_definitions[] = { + {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."}, +}; + +OptionGroupFormat::OptionGroupFormat( + lldb::Format default_format, uint64_t default_byte_size, + uint64_t default_count, OptionGroupFormatUsageTextVector usage_text_vector) + : 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'), m_has_gdb_format(false) { + // Copy the default option definitions. + std::copy(std::begin(g_default_option_definitions), + std::end(g_default_option_definitions), + std::begin(m_option_definitions)); + + for (auto usage_text_tuple : usage_text_vector) { + switch (std::get<0>(usage_text_tuple)) { + case eArgTypeFormat: + m_option_definitions[0].usage_text = std::get<1>(usage_text_tuple); + break; + case eArgTypeByteSize: + m_option_definitions[2].usage_text = std::get<1>(usage_text_tuple); + break; + default: + llvm_unreachable("Unimplemented option"); + } + } +} + +llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() { + auto result = llvm::ArrayRef(m_option_definitions); + 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 = m_option_definitions[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; +} |