diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp new file mode 100644 index 0000000..81b79b8 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp @@ -0,0 +1,501 @@ +//===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-python.h" + +#include "CommandObjectRegister.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionValueArray.h" +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Thread.h" +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// "register read" +//---------------------------------------------------------------------- +class CommandObjectRegisterRead : public CommandObjectParsed +{ +public: + CommandObjectRegisterRead (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "register read", + "Dump the contents of one or more register values from the current frame. If no register is specified, dumps them all.", + NULL, + eFlagRequiresFrame | + eFlagRequiresRegContext | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ), + m_option_group (interpreter), + m_format_options (eFormatDefault), + m_command_options () + { + CommandArgumentEntry arg; + CommandArgumentData register_arg; + + // Define the first (and only) variant of this arg. + register_arg.arg_type = eArgTypeRegisterName; + register_arg.arg_repetition = eArgRepeatStar; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (register_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + + // Add the "--format" + m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_ALL); + m_option_group.Append (&m_command_options); + m_option_group.Finalize(); + + } + + virtual + ~CommandObjectRegisterRead () + { + } + + Options * + GetOptions () + { + return &m_option_group; + } + + bool + DumpRegister (const ExecutionContext &exe_ctx, + Stream &strm, + RegisterContext *reg_ctx, + const RegisterInfo *reg_info) + { + if (reg_info) + { + RegisterValue reg_value; + + if (reg_ctx->ReadRegister (reg_info, reg_value)) + { + strm.Indent (); + + bool prefix_with_altname = (bool)m_command_options.alternate_name; + bool prefix_with_name = !prefix_with_altname; + reg_value.Dump(&strm, reg_info, prefix_with_name, prefix_with_altname, m_format_options.GetFormat(), 8); + if ((reg_info->encoding == eEncodingUint) || (reg_info->encoding == eEncodingSint)) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && reg_info->byte_size == process->GetAddressByteSize()) + { + addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS); + if (reg_addr != LLDB_INVALID_ADDRESS) + { + Address so_reg_addr; + if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(reg_addr, so_reg_addr)) + { + strm.PutCString (" "); + so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription); + } + } + } + } + strm.EOL(); + return true; + } + } + return false; + } + + bool + DumpRegisterSet (const ExecutionContext &exe_ctx, + Stream &strm, + RegisterContext *reg_ctx, + size_t set_idx, + bool primitive_only=false) + { + uint32_t unavailable_count = 0; + uint32_t available_count = 0; + + if (!reg_ctx) + return false; // thread has no registers (i.e. core files are corrupt, incomplete crash logs...) + + const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx); + if (reg_set) + { + strm.Printf ("%s:\n", reg_set->name); + strm.IndentMore (); + const size_t num_registers = reg_set->num_registers; + for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) + { + const uint32_t reg = reg_set->registers[reg_idx]; + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg); + // Skip the dumping of derived register if primitive_only is true. + if (primitive_only && reg_info && reg_info->value_regs) + continue; + + if (DumpRegister (exe_ctx, strm, reg_ctx, reg_info)) + ++available_count; + else + ++unavailable_count; + } + strm.IndentLess (); + if (unavailable_count) + { + strm.Indent (); + strm.Printf("%u registers were unavailable.\n", unavailable_count); + } + strm.EOL(); + } + return available_count > 0; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + Stream &strm = result.GetOutputStream(); + RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext (); + + const RegisterInfo *reg_info = NULL; + if (command.GetArgumentCount() == 0) + { + size_t set_idx; + + size_t num_register_sets = 1; + const size_t set_array_size = m_command_options.set_indexes.GetSize(); + if (set_array_size > 0) + { + for (size_t i=0; i<set_array_size; ++i) + { + set_idx = m_command_options.set_indexes[i]->GetUInt64Value (UINT32_MAX, NULL); + if (set_idx < reg_ctx->GetRegisterSetCount()) + { + if (!DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx)) + { + if (errno) + result.AppendErrorWithFormat ("register read failed: %s\n", strerror(errno)); + else + result.AppendError ("unknown error while reading registers.\n"); + result.SetStatus (eReturnStatusFailed); + break; + } + } + else + { + result.AppendErrorWithFormat("invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx); + result.SetStatus (eReturnStatusFailed); + break; + } + } + } + else + { + if (m_command_options.dump_all_sets) + num_register_sets = reg_ctx->GetRegisterSetCount(); + + for (set_idx = 0; set_idx < num_register_sets; ++set_idx) + { + // When dump_all_sets option is set, dump primitive as well as derived registers. + DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx, !m_command_options.dump_all_sets.GetCurrentValue()); + } + } + } + else + { + if (m_command_options.dump_all_sets) + { + result.AppendError ("the --all option can't be used when registers names are supplied as arguments\n"); + result.SetStatus (eReturnStatusFailed); + } + else if (m_command_options.set_indexes.GetSize() > 0) + { + result.AppendError ("the --set <set> option can't be used when registers names are supplied as arguments\n"); + result.SetStatus (eReturnStatusFailed); + } + else + { + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + // in most LLDB commands we accept $rbx as the name for register RBX - and here we would + // reject it and non-existant. we should be more consistent towards the user and allow them + // to say reg read $rbx - internally, however, we should be strict and not allow ourselves + // to call our registers $rbx in our own API + if (*arg_cstr == '$') + arg_cstr = arg_cstr+1; + reg_info = reg_ctx->GetRegisterInfoByName(arg_cstr); + + if (reg_info) + { + if (!DumpRegister (m_exe_ctx, strm, reg_ctx, reg_info)) + strm.Printf("%-12s = error: unavailable\n", reg_info->name); + } + else + { + result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr); + } + } + } + } + return result.Succeeded(); + } + + class CommandOptions : public OptionGroup + { + public: + CommandOptions () : + OptionGroup(), + set_indexes (OptionValue::ConvertTypeToMask (OptionValue::eTypeUInt64)), + dump_all_sets (false, false), // Initial and default values are false + alternate_name (false, false) + { + } + + virtual + ~CommandOptions () + { + } + + + virtual uint32_t + GetNumDefinitions (); + + virtual const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + set_indexes.Clear(); + dump_all_sets.Clear(); + alternate_name.Clear(); + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_value) + { + Error error; + const int short_option = g_option_table[option_idx].short_option; + switch (short_option) + { + case 's': + { + OptionValueSP value_sp (OptionValueUInt64::Create (option_value, error)); + if (value_sp) + set_indexes.AppendValue (value_sp); + } + break; + + case 'a': + // When we don't use OptionValue::SetValueFromCString(const char *) to + // set an option value, it won't be marked as being set in the options + // so we make a call to let users know the value was set via option + dump_all_sets.SetCurrentValue (true); + dump_all_sets.SetOptionWasSet (); + break; + + case 'A': + // When we don't use OptionValue::SetValueFromCString(const char *) to + // set an option value, it won't be marked as being set in the options + // so we make a call to let users know the value was set via option + alternate_name.SetCurrentValue (true); + dump_all_sets.SetOptionWasSet (); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + return error; + } + + // Options table: Required for subclasses of Options. + + static const OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + OptionValueArray set_indexes; + OptionValueBoolean dump_all_sets; + OptionValueBoolean alternate_name; + }; + + OptionGroupOptions m_option_group; + OptionGroupFormat m_format_options; + CommandOptions m_command_options; +}; + +const OptionDefinition +CommandObjectRegisterRead::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "alternate", 'A', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Display register names using the alternate register name if there is one."}, + { LLDB_OPT_SET_1 , false, "set" , 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Specify which register sets to dump by index."}, + { LLDB_OPT_SET_2 , false, "all" , 'a', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Show all register sets."}, +}; + +uint32_t +CommandObjectRegisterRead::CommandOptions::GetNumDefinitions () +{ + return llvm::array_lengthof(g_option_table); +} + + +//---------------------------------------------------------------------- +// "register write" +//---------------------------------------------------------------------- +class CommandObjectRegisterWrite : public CommandObjectParsed +{ +public: + CommandObjectRegisterWrite (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "register write", + "Modify a single register value.", + NULL, + eFlagRequiresFrame | + eFlagRequiresRegContext | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused) + { + CommandArgumentEntry arg1; + CommandArgumentEntry arg2; + CommandArgumentData register_arg; + CommandArgumentData value_arg; + + // Define the first (and only) variant of this arg. + register_arg.arg_type = eArgTypeRegisterName; + register_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg1.push_back (register_arg); + + // Define the first (and only) variant of this arg. + value_arg.arg_type = eArgTypeValue; + value_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg2.push_back (value_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg1); + m_arguments.push_back (arg2); + } + + virtual + ~CommandObjectRegisterWrite () + { + } + +protected: + virtual bool + DoExecute(Args& command, CommandReturnObject &result) + { + DataExtractor reg_data; + RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext (); + + if (command.GetArgumentCount() != 2) + { + result.AppendError ("register write takes exactly 2 arguments: <reg-name> <value>"); + result.SetStatus (eReturnStatusFailed); + } + else + { + const char *reg_name = command.GetArgumentAtIndex(0); + const char *value_str = command.GetArgumentAtIndex(1); + + + // in most LLDB commands we accept $rbx as the name for register RBX - and here we would + // reject it and non-existant. we should be more consistent towards the user and allow them + // to say reg write $rbx - internally, however, we should be strict and not allow ourselves + // to call our registers $rbx in our own API + if (reg_name && *reg_name == '$') + reg_name = reg_name+1; + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); + + if (reg_info) + { + RegisterValue reg_value; + + Error error (reg_value.SetValueFromCString (reg_info, value_str)); + if (error.Success()) + { + if (reg_ctx->WriteRegister (reg_info, reg_value)) + { + // Toss all frames and anything else in the thread + // after a register has been written. + m_exe_ctx.GetThreadRef().Flush(); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + } + if (error.AsCString()) + { + result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n", + reg_name, + value_str, + error.AsCString()); + } + else + { + result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s'", + reg_name, + value_str); + } + result.SetStatus (eReturnStatusFailed); + } + else + { + result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } +}; + + +//---------------------------------------------------------------------- +// CommandObjectRegister constructor +//---------------------------------------------------------------------- +CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "register", + "A set of commands to access thread registers.", + "register [read|write] ...") +{ + LoadSubCommand ("read", CommandObjectSP (new CommandObjectRegisterRead (interpreter))); + LoadSubCommand ("write", CommandObjectSP (new CommandObjectRegisterWrite (interpreter))); +} + + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectRegister::~CommandObjectRegister() +{ +} |