2013-08-23 17:46:38 +00:00
//===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
2016-07-23 20:50:09 +00:00
# include "llvm/ADT/STLExtras.h"
2013-08-23 17:46:38 +00:00
// Project includes
2016-07-23 20:50:09 +00:00
# include "CommandObjectRegister.h"
2013-08-23 17:46:38 +00:00
# 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"
2015-07-03 16:57:06 +00:00
# include "lldb/Interpreter/OptionValueBoolean.h"
2013-08-23 17:46:38 +00:00
# include "lldb/Interpreter/OptionValueUInt64.h"
# include "lldb/Target/ExecutionContext.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/RegisterContext.h"
2014-02-18 16:23:10 +00:00
# include "lldb/Target/SectionLoadList.h"
2013-08-23 17:46:38 +00:00
# include "lldb/Target/Thread.h"
using namespace lldb ;
using namespace lldb_private ;
//----------------------------------------------------------------------
// "register read"
//----------------------------------------------------------------------
class CommandObjectRegisterRead : public CommandObjectParsed
{
public :
CommandObjectRegisterRead ( CommandInterpreter & interpreter ) :
2016-07-23 20:50:09 +00:00
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. " ,
nullptr ,
eCommandRequiresFrame |
eCommandRequiresRegContext |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused ) ,
2013-08-23 17:46:38 +00:00
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 ( ) ;
}
2016-07-23 20:50:09 +00:00
~ CommandObjectRegisterRead ( ) override = default ;
2013-08-23 17:46:38 +00:00
Options *
2015-12-30 11:55:28 +00:00
GetOptions ( ) override
2013-08-23 17:46:38 +00:00
{
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 ( ) ;
2013-11-06 16:48:53 +00:00
bool prefix_with_altname = ( bool ) m_command_options . alternate_name ;
2013-08-23 17:46:38 +00:00
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 )
{
2015-07-03 16:57:06 +00:00
strm . Printf ( " %s: \n " , ( reg_set - > name ? reg_set - > name : " unknown " ) ) ;
2013-08-23 17:46:38 +00:00
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 :
2015-12-30 11:55:28 +00:00
bool
DoExecute ( Args & command , CommandReturnObject & result ) override
2013-08-23 17:46:38 +00:00
{
Stream & strm = result . GetOutputStream ( ) ;
RegisterContext * reg_ctx = m_exe_ctx . GetRegisterContext ( ) ;
2016-07-23 20:50:09 +00:00
const RegisterInfo * reg_info = nullptr ;
2013-08-23 17:46:38 +00:00
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 )
{
2016-07-23 20:50:09 +00:00
for ( size_t i = 0 ; i < set_array_size ; + + i )
2013-08-23 17:46:38 +00:00
{
2016-07-23 20:50:09 +00:00
set_idx = m_command_options . set_indexes [ i ] - > GetUInt64Value ( UINT32_MAX , nullptr ) ;
2013-08-23 17:46:38 +00:00
if ( set_idx < reg_ctx - > GetRegisterSetCount ( ) )
{
if ( ! DumpRegisterSet ( m_exe_ctx , strm , reg_ctx , set_idx ) )
{
if ( errno )
2013-11-06 16:48:53 +00:00
result . AppendErrorWithFormat ( " register read failed: %s \n " , strerror ( errno ) ) ;
2013-08-23 17:46:38 +00:00
else
result . AppendError ( " unknown error while reading registers. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
break ;
}
}
else
{
2014-11-25 21:00:58 +00:00
result . AppendErrorWithFormat ( " invalid register set index: % " PRIu64 " \n " , ( uint64_t ) set_idx ) ;
2013-08-23 17:46:38 +00:00
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 ;
2016-07-23 20:50:09 +00:00
for ( int arg_idx = 0 ; ( arg_cstr = command . GetArgumentAtIndex ( arg_idx ) ) ! = nullptr ; + + arg_idx )
2013-08-23 17:46:38 +00:00
{
// 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 )
{
}
2016-07-23 20:50:09 +00:00
~ CommandOptions ( ) override = default ;
2015-12-30 11:55:28 +00:00
uint32_t
GetNumDefinitions ( ) override ;
2013-08-23 17:46:38 +00:00
2015-12-30 11:55:28 +00:00
const OptionDefinition *
GetDefinitions ( ) override
2013-08-23 17:46:38 +00:00
{
return g_option_table ;
}
2015-12-30 11:55:28 +00:00
void
OptionParsingStarting ( CommandInterpreter & interpreter ) override
2013-08-23 17:46:38 +00:00
{
set_indexes . Clear ( ) ;
dump_all_sets . Clear ( ) ;
alternate_name . Clear ( ) ;
}
2015-12-30 11:55:28 +00:00
Error
2013-08-23 17:46:38 +00:00
SetOptionValue ( CommandInterpreter & interpreter ,
uint32_t option_idx ,
2015-12-30 11:55:28 +00:00
const char * option_value ) override
2013-08-23 17:46:38 +00:00
{
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 [ ] =
{
2016-07-23 20:50:09 +00:00
{ LLDB_OPT_SET_ALL , false , " alternate " , ' A ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Display register names using the alternate register name if there is one. " } ,
{ LLDB_OPT_SET_1 , false , " set " , ' s ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeIndex , " Specify which register sets to dump by index. " } ,
{ LLDB_OPT_SET_2 , false , " all " , ' a ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Show all register sets. " } ,
2013-08-23 17:46:38 +00:00
} ;
uint32_t
CommandObjectRegisterRead : : CommandOptions : : GetNumDefinitions ( )
{
2014-11-25 21:00:58 +00:00
return llvm : : array_lengthof ( g_option_table ) ;
2013-08-23 17:46:38 +00:00
}
//----------------------------------------------------------------------
// "register write"
//----------------------------------------------------------------------
class CommandObjectRegisterWrite : public CommandObjectParsed
{
public :
CommandObjectRegisterWrite ( CommandInterpreter & interpreter ) :
2016-07-23 20:50:09 +00:00
CommandObjectParsed ( interpreter ,
" register write " ,
" Modify a single register value. " ,
nullptr ,
eCommandRequiresFrame |
eCommandRequiresRegContext |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused )
2013-08-23 17:46:38 +00:00
{
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 ) ;
}
2016-07-23 20:50:09 +00:00
~ CommandObjectRegisterWrite ( ) override = default ;
2013-08-23 17:46:38 +00:00
protected :
2015-12-30 11:55:28 +00:00
bool
DoExecute ( Args & command , CommandReturnObject & result ) override
2013-08-23 17:46:38 +00:00
{
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 ) ;
2016-07-23 20:50:09 +00:00
2013-08-23 17:46:38 +00:00
// 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
//----------------------------------------------------------------------
2016-07-23 20:50:09 +00:00
CommandObjectRegister : : CommandObjectRegister ( CommandInterpreter & interpreter )
: CommandObjectMultiword ( interpreter , " register " ,
" Commands to access registers for the current thread and stack frame. " ,
" register [read|write] ... " )
2013-08-23 17:46:38 +00:00
{
LoadSubCommand ( " read " , CommandObjectSP ( new CommandObjectRegisterRead ( interpreter ) ) ) ;
LoadSubCommand ( " write " , CommandObjectSP ( new CommandObjectRegisterWrite ( interpreter ) ) ) ;
}
2016-07-23 20:50:09 +00:00
CommandObjectRegister : : ~ CommandObjectRegister ( ) = default ;