Files
llvm/lldb/source/Commands/CommandObjectRegister.cpp

411 lines
16 KiB
C++
Raw Normal View History

//===-- 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 "CommandObjectRegister.h"
#include "lldb/Core/Debugger.h"
2011-05-09 20:18:18 +00:00
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionValueArray.h"
#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Interpreter/Options.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 "lldb/Utility/Args.h"
#include "lldb/Utility/DataExtractor.h"
#include "llvm/Support/Errno.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// "register read"
//----------------------------------------------------------------------
static OptionDefinition g_register_read_options[] = {
// clang-format off
{ 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." },
// clang-format on
};
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.",
nullptr,
eCommandRequiresFrame | eCommandRequiresRegContext |
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
m_option_group(), 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();
}
~CommandObjectRegisterRead() override = default;
Options *GetOptions() override { 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);
}
Did some work on the "register read" command to only show the first register set by default when dumping registers. If you want to see all of the register sets you can use the "--all" option: (lldb) register read --all If you want to just see some register sets, you can currently specify them by index: (lldb) register read --set 0 --set 2 We need to get shorter register set names soon so we can specify the register sets by name without having to type too much. I will make this change soon. You can also have any integer encoded registers resolve the address values back to any code or data from the object files using the "--lookup" option. Below is sample output when stopped in the libc function "puts" with some const strings in registers: Process 8973 stopped * thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1 (lldb) register read --lookup General Purpose Registers: rax = 0x0000000100000e98 "----------------------------------------------------------------------" rbx = 0x0000000000000000 rcx = 0x0000000000000001 rdx = 0x0000000000000000 rdi = 0x0000000100000e98 "----------------------------------------------------------------------" rsi = 0x0000000100800000 rbp = 0x00007fff5fbff710 rsp = 0x00007fff5fbff280 r8 = 0x0000000000000040 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fff828fa30f libSystem.B.dylib`puts + 1 rflags = 0x0000000000000246 cs = 0x0000000000000027 fs = 0x0000000000000000 gs = 0x0000000000000000 As we can see, we see two constant strings and the PC (register "rip") is showing the code it resolves to. I fixed the register "--format" option to work as expected. Added a setting to disable skipping the function prologue when setting breakpoints as a target settings variable: (lldb) settings set target.skip-prologue false Updated the user settings controller boolean value handler funciton to be able to take the default value so it can correctly respond to the eVarSetOperationClear operation. Did some usability work on the OptionValue classes. Fixed the "image lookup" command to correctly respond to the "--verbose" option and display the detailed symbol context information when looking up line table entries and functions by name. This previously was only working for address lookups. llvm-svn: 129977
2011-04-22 03:55:06 +00:00
}
}
Did some work on the "register read" command to only show the first register set by default when dumping registers. If you want to see all of the register sets you can use the "--all" option: (lldb) register read --all If you want to just see some register sets, you can currently specify them by index: (lldb) register read --set 0 --set 2 We need to get shorter register set names soon so we can specify the register sets by name without having to type too much. I will make this change soon. You can also have any integer encoded registers resolve the address values back to any code or data from the object files using the "--lookup" option. Below is sample output when stopped in the libc function "puts" with some const strings in registers: Process 8973 stopped * thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1 (lldb) register read --lookup General Purpose Registers: rax = 0x0000000100000e98 "----------------------------------------------------------------------" rbx = 0x0000000000000000 rcx = 0x0000000000000001 rdx = 0x0000000000000000 rdi = 0x0000000100000e98 "----------------------------------------------------------------------" rsi = 0x0000000100800000 rbp = 0x00007fff5fbff710 rsp = 0x00007fff5fbff280 r8 = 0x0000000000000040 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fff828fa30f libSystem.B.dylib`puts + 1 rflags = 0x0000000000000246 cs = 0x0000000000000027 fs = 0x0000000000000000 gs = 0x0000000000000000 As we can see, we see two constant strings and the PC (register "rip") is showing the code it resolves to. I fixed the register "--format" option to work as expected. Added a setting to disable skipping the function prologue when setting breakpoints as a target settings variable: (lldb) settings set target.skip-prologue false Updated the user settings controller boolean value handler funciton to be able to take the default value so it can correctly respond to the eVarSetOperationClear operation. Did some usability work on the OptionValue classes. Fixed the "image lookup" command to correctly respond to the "--verbose" option and display the detailed symbol context information when looking up line table entries and functions by name. This previously was only working for address lookups. llvm-svn: 129977
2011-04-22 03:55:06 +00:00
}
strm.EOL();
return true;
}
Did some work on the "register read" command to only show the first register set by default when dumping registers. If you want to see all of the register sets you can use the "--all" option: (lldb) register read --all If you want to just see some register sets, you can currently specify them by index: (lldb) register read --set 0 --set 2 We need to get shorter register set names soon so we can specify the register sets by name without having to type too much. I will make this change soon. You can also have any integer encoded registers resolve the address values back to any code or data from the object files using the "--lookup" option. Below is sample output when stopped in the libc function "puts" with some const strings in registers: Process 8973 stopped * thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1 (lldb) register read --lookup General Purpose Registers: rax = 0x0000000100000e98 "----------------------------------------------------------------------" rbx = 0x0000000000000000 rcx = 0x0000000000000001 rdx = 0x0000000000000000 rdi = 0x0000000100000e98 "----------------------------------------------------------------------" rsi = 0x0000000100800000 rbp = 0x00007fff5fbff710 rsp = 0x00007fff5fbff280 r8 = 0x0000000000000040 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fff828fa30f libSystem.B.dylib`puts + 1 rflags = 0x0000000000000246 cs = 0x0000000000000027 fs = 0x0000000000000000 gs = 0x0000000000000000 As we can see, we see two constant strings and the PC (register "rip") is showing the code it resolves to. I fixed the register "--format" option to work as expected. Added a setting to disable skipping the function prologue when setting breakpoints as a target settings variable: (lldb) settings set target.skip-prologue false Updated the user settings controller boolean value handler funciton to be able to take the default value so it can correctly respond to the eVarSetOperationClear operation. Did some usability work on the OptionValue classes. Fixed the "image lookup" command to correctly respond to the "--verbose" option and display the detailed symbol context information when looking up line table entries and functions by name. This previously was only working for address lookups. llvm-svn: 129977
2011-04-22 03:55:06 +00:00
}
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 ? reg_set->name : "unknown"));
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();
Did some work on the "register read" command to only show the first register set by default when dumping registers. If you want to see all of the register sets you can use the "--all" option: (lldb) register read --all If you want to just see some register sets, you can currently specify them by index: (lldb) register read --set 0 --set 2 We need to get shorter register set names soon so we can specify the register sets by name without having to type too much. I will make this change soon. You can also have any integer encoded registers resolve the address values back to any code or data from the object files using the "--lookup" option. Below is sample output when stopped in the libc function "puts" with some const strings in registers: Process 8973 stopped * thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1 (lldb) register read --lookup General Purpose Registers: rax = 0x0000000100000e98 "----------------------------------------------------------------------" rbx = 0x0000000000000000 rcx = 0x0000000000000001 rdx = 0x0000000000000000 rdi = 0x0000000100000e98 "----------------------------------------------------------------------" rsi = 0x0000000100800000 rbp = 0x00007fff5fbff710 rsp = 0x00007fff5fbff280 r8 = 0x0000000000000040 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fff828fa30f libSystem.B.dylib`puts + 1 rflags = 0x0000000000000246 cs = 0x0000000000000027 fs = 0x0000000000000000 gs = 0x0000000000000000 As we can see, we see two constant strings and the PC (register "rip") is showing the code it resolves to. I fixed the register "--format" option to work as expected. Added a setting to disable skipping the function prologue when setting breakpoints as a target settings variable: (lldb) settings set target.skip-prologue false Updated the user settings controller boolean value handler funciton to be able to take the default value so it can correctly respond to the eVarSetOperationClear operation. Did some usability work on the OptionValue classes. Fixed the "image lookup" command to correctly respond to the "--verbose" option and display the detailed symbol context information when looking up line table entries and functions by name. This previously was only working for address lookups. llvm-svn: 129977
2011-04-22 03:55:06 +00:00
}
return available_count > 0;
}
Did some work on the "register read" command to only show the first register set by default when dumping registers. If you want to see all of the register sets you can use the "--all" option: (lldb) register read --all If you want to just see some register sets, you can currently specify them by index: (lldb) register read --set 0 --set 2 We need to get shorter register set names soon so we can specify the register sets by name without having to type too much. I will make this change soon. You can also have any integer encoded registers resolve the address values back to any code or data from the object files using the "--lookup" option. Below is sample output when stopped in the libc function "puts" with some const strings in registers: Process 8973 stopped * thread #1: tid = 0x2c03, 0x00007fff828fa30f libSystem.B.dylib`puts + 1, stop reason = instruction step into frame #0: 0x00007fff828fa30f libSystem.B.dylib`puts + 1 (lldb) register read --lookup General Purpose Registers: rax = 0x0000000100000e98 "----------------------------------------------------------------------" rbx = 0x0000000000000000 rcx = 0x0000000000000001 rdx = 0x0000000000000000 rdi = 0x0000000100000e98 "----------------------------------------------------------------------" rsi = 0x0000000100800000 rbp = 0x00007fff5fbff710 rsp = 0x00007fff5fbff280 r8 = 0x0000000000000040 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fff828fa30f libSystem.B.dylib`puts + 1 rflags = 0x0000000000000246 cs = 0x0000000000000027 fs = 0x0000000000000000 gs = 0x0000000000000000 As we can see, we see two constant strings and the PC (register "rip") is showing the code it resolves to. I fixed the register "--format" option to work as expected. Added a setting to disable skipping the function prologue when setting breakpoints as a target settings variable: (lldb) settings set target.skip-prologue false Updated the user settings controller boolean value handler funciton to be able to take the default value so it can correctly respond to the eVarSetOperationClear operation. Did some usability work on the OptionValue classes. Fixed the "image lookup" command to correctly respond to the "--verbose" option and display the detailed symbol context information when looking up line table entries and functions by name. This previously was only working for address lookups. llvm-svn: 129977
2011-04-22 03:55:06 +00:00
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
Stream &strm = result.GetOutputStream();
RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
const RegisterInfo *reg_info = nullptr;
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,
nullptr);
if (set_idx < reg_ctx->GetRegisterSetCount()) {
if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
if (errno)
result.AppendErrorWithFormatv("register read failed: {0}\n",
llvm::sys::StrError());
else
result.AppendError("unknown error while reading registers.\n");
result.SetStatus(eReturnStatusFailed);
break;
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are: enum { //---------------------------------------------------------------------- // eFlagRequiresTarget // // Ensures a valid target is contained in m_exe_ctx prior to executing // the command. If a target doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidTargetDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidTargetDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresTarget = (1u << 0), //---------------------------------------------------------------------- // eFlagRequiresProcess // // Ensures a valid process is contained in m_exe_ctx prior to executing // the command. If a process doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidProcessDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidProcessDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresProcess = (1u << 1), //---------------------------------------------------------------------- // eFlagRequiresThread // // Ensures a valid thread is contained in m_exe_ctx prior to executing // the command. If a thread doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidThreadDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidThreadDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresThread = (1u << 2), //---------------------------------------------------------------------- // eFlagRequiresFrame // // Ensures a valid frame is contained in m_exe_ctx prior to executing // the command. If a frame doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidFrameDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidFrameDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresFrame = (1u << 3), //---------------------------------------------------------------------- // eFlagRequiresRegContext // // Ensures a valid register context (from the selected frame if there // is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx) // is availble from m_exe_ctx prior to executing the command. If a // target doesn't exist or is invalid, the command will fail and // CommandObject::GetInvalidRegContextDescription() will be returned as // the error. CommandObject subclasses can override the virtual function // for GetInvalidRegContextDescription() to provide custom strings when // needed. //---------------------------------------------------------------------- eFlagRequiresRegContext = (1u << 4), //---------------------------------------------------------------------- // eFlagTryTargetAPILock // // Attempts to acquire the target lock if a target is selected in the // command interpreter. If the command object fails to acquire the API // lock, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagTryTargetAPILock = (1u << 5), //---------------------------------------------------------------------- // eFlagProcessMustBeLaunched // // Verifies that there is a launched process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBeLaunched = (1u << 6), //---------------------------------------------------------------------- // eFlagProcessMustBePaused // // Verifies that there is a paused process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBePaused = (1u << 7) }; Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands. llvm-svn: 171990
2013-01-09 19:44:40 +00:00
}
} else {
result.AppendErrorWithFormat(
"invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
result.SetStatus(eReturnStatusFailed);
break;
}
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are: enum { //---------------------------------------------------------------------- // eFlagRequiresTarget // // Ensures a valid target is contained in m_exe_ctx prior to executing // the command. If a target doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidTargetDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidTargetDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresTarget = (1u << 0), //---------------------------------------------------------------------- // eFlagRequiresProcess // // Ensures a valid process is contained in m_exe_ctx prior to executing // the command. If a process doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidProcessDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidProcessDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresProcess = (1u << 1), //---------------------------------------------------------------------- // eFlagRequiresThread // // Ensures a valid thread is contained in m_exe_ctx prior to executing // the command. If a thread doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidThreadDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidThreadDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresThread = (1u << 2), //---------------------------------------------------------------------- // eFlagRequiresFrame // // Ensures a valid frame is contained in m_exe_ctx prior to executing // the command. If a frame doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidFrameDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidFrameDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresFrame = (1u << 3), //---------------------------------------------------------------------- // eFlagRequiresRegContext // // Ensures a valid register context (from the selected frame if there // is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx) // is availble from m_exe_ctx prior to executing the command. If a // target doesn't exist or is invalid, the command will fail and // CommandObject::GetInvalidRegContextDescription() will be returned as // the error. CommandObject subclasses can override the virtual function // for GetInvalidRegContextDescription() to provide custom strings when // needed. //---------------------------------------------------------------------- eFlagRequiresRegContext = (1u << 4), //---------------------------------------------------------------------- // eFlagTryTargetAPILock // // Attempts to acquire the target lock if a target is selected in the // command interpreter. If the command object fails to acquire the API // lock, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagTryTargetAPILock = (1u << 5), //---------------------------------------------------------------------- // eFlagProcessMustBeLaunched // // Verifies that there is a launched process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBeLaunched = (1u << 6), //---------------------------------------------------------------------- // eFlagProcessMustBePaused // // Verifies that there is a paused process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBePaused = (1u << 7) }; Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands. llvm-svn: 171990
2013-01-09 19:44:40 +00:00
}
} 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 {
for (auto &entry : command) {
// 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
auto arg_str = entry.ref;
arg_str.consume_front("$");
reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
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_str.str().c_str());
}
}
}
}
return result.Succeeded();
}
Many improvements to the Platform base class and subclasses. The base Platform class now implements the Host functionality for a lot of things that make sense by default so that subclasses can check: int PlatformSubclass::Foo () { if (IsHost()) return Platform::Foo (); // Let the platform base class do the host specific stuff // Platform subclass specific code... int result = ... return result; } Added new functions to the platform: virtual const char *Platform::GetUserName (uint32_t uid); virtual const char *Platform::GetGroupName (uint32_t gid); The user and group names are cached locally so that remote platforms can avoid sending packets multiple times to resolve this information. Added the parent process ID to the ProcessInfo class. Added a new ProcessInfoMatch class which helps us to match processes up and changed the Host layer over to using this new class. The new class allows us to search for processs: 1 - by name (equal to, starts with, ends with, contains, and regex) 2 - by pid 3 - And further check for parent pid == value, uid == value, gid == value, euid == value, egid == value, arch == value, parent == value. This is all hookup up to the "platform process list" command which required adding dumping routines to dump process information. If the Host class implements the process lookup routines, you can now lists processes on your local machine: machine1.foo.com % lldb (lldb) platform process list PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME ====== ====== ========== ========== ========== ========== ======================== ============================ 99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge 94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker 94852 244 username usergroup username usergroup x86_64-apple-darwin Safari 94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode 92742 92710 username usergroup username usergroup i386-apple-darwin debugserver This of course also works remotely with the lldb-platform: machine1.foo.com % lldb-platform --listen 1234 machine2.foo.com % lldb (lldb) platform create remote-macosx Platform: remote-macosx Connected: no (lldb) platform connect connect://localhost:1444 Platform: remote-macosx Triple: x86_64-apple-darwin OS Version: 10.6.7 (10J869) Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 Hostname: machine1.foo.com Connected: yes (lldb) platform process list PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME ====== ====== ========== ========== ========== ========== ======================== ============================ 99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation 99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb 99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge 94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker 94852 244 username usergroup username usergroup x86_64-apple-darwin Safari The lldb-platform implements everything with the Host:: layer, so this should "just work" for linux. I will probably be adding more stuff to the Host layer for launching processes and attaching to processes so that this support should eventually just work as well. Modified the target to be able to be created with an architecture that differs from the main executable. This is needed for iOS debugging since we can have an "armv6" binary which can run on an "armv7" machine, so we want to be able to do: % lldb (lldb) platform create remote-ios (lldb) file --arch armv7 a.out Where "a.out" is an armv6 executable. The platform then can correctly decide to open all "armv7" images for all dependent shared libraries. Modified the disassembly to show the current PC value. Example output: (lldb) disassemble --frame a.out`main: 0x1eb7: pushl %ebp 0x1eb8: movl %esp, %ebp 0x1eba: pushl %ebx 0x1ebb: subl $20, %esp 0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18 0x1ec3: popl %ebx -> 0x1ec4: calll 0x1f12 ; getpid 0x1ec9: movl %eax, 4(%esp) 0x1ecd: leal 199(%ebx), %eax 0x1ed3: movl %eax, (%esp) 0x1ed6: calll 0x1f18 ; printf 0x1edb: leal 213(%ebx), %eax 0x1ee1: movl %eax, (%esp) 0x1ee4: calll 0x1f1e ; puts 0x1ee9: calll 0x1f0c ; getchar 0x1eee: movl $20, (%esp) 0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6 0x1efa: movl $12, %eax 0x1eff: addl $20, %esp 0x1f02: popl %ebx 0x1f03: leave 0x1f04: ret This can be handy when dealing with the new --line options that was recently added: (lldb) disassemble --line a.out`main + 13 at test.c:19 18 { -> 19 printf("Process: %i\n\n", getpid()); 20 puts("Press any key to continue..."); getchar(); -> 0x1ec4: calll 0x1f12 ; getpid 0x1ec9: movl %eax, 4(%esp) 0x1ecd: leal 199(%ebx), %eax 0x1ed3: movl %eax, (%esp) 0x1ed6: calll 0x1f18 ; printf Modified the ModuleList to have a lookup based solely on a UUID. Since the UUID is typically the MD5 checksum of a binary image, there is no need to give the path and architecture when searching for a pre-existing image in an image list. Now that we support remote debugging a bit better, our lldb_private::Module needs to be able to track what the original path for file was as the platform knows it, as well as where the file is locally. The module has the two following functions to retrieve both paths: const FileSpec &Module::GetFileSpec () const; const FileSpec &Module::GetPlatformFileSpec () const; llvm-svn: 128563
2011-03-30 18:16:51 +00:00
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) {}
~CommandOptions() override = default;
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
return llvm::makeArrayRef(g_register_read_options);
}
void OptionParsingStarting(ExecutionContext *execution_context) override {
set_indexes.Clear();
dump_all_sets.Clear();
alternate_name.Clear();
}
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
ExecutionContext *execution_context) override {
Status error;
const int short_option = GetDefinitions()[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;
}
// 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;
};
//----------------------------------------------------------------------
// "register write"
//----------------------------------------------------------------------
class CommandObjectRegisterWrite : public CommandObjectParsed {
public:
CommandObjectRegisterWrite(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "register write",
"Modify a single register value.", nullptr,
eCommandRequiresFrame | eCommandRequiresRegContext |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused) {
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);
}
~CommandObjectRegisterWrite() override = default;
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
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 {
auto reg_name = command[0].ref;
auto value_str = command[1].ref;
// 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
reg_name.consume_front("$");
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
if (reg_info) {
RegisterValue reg_value;
Status error(reg_value.SetValueFromString(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;
}
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are: enum { //---------------------------------------------------------------------- // eFlagRequiresTarget // // Ensures a valid target is contained in m_exe_ctx prior to executing // the command. If a target doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidTargetDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidTargetDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresTarget = (1u << 0), //---------------------------------------------------------------------- // eFlagRequiresProcess // // Ensures a valid process is contained in m_exe_ctx prior to executing // the command. If a process doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidProcessDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidProcessDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresProcess = (1u << 1), //---------------------------------------------------------------------- // eFlagRequiresThread // // Ensures a valid thread is contained in m_exe_ctx prior to executing // the command. If a thread doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidThreadDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidThreadDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresThread = (1u << 2), //---------------------------------------------------------------------- // eFlagRequiresFrame // // Ensures a valid frame is contained in m_exe_ctx prior to executing // the command. If a frame doesn't exist or is invalid, the command // will fail and CommandObject::GetInvalidFrameDescription() will be // returned as the error. CommandObject subclasses can override the // virtual function for GetInvalidFrameDescription() to provide custom // strings when needed. //---------------------------------------------------------------------- eFlagRequiresFrame = (1u << 3), //---------------------------------------------------------------------- // eFlagRequiresRegContext // // Ensures a valid register context (from the selected frame if there // is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx) // is availble from m_exe_ctx prior to executing the command. If a // target doesn't exist or is invalid, the command will fail and // CommandObject::GetInvalidRegContextDescription() will be returned as // the error. CommandObject subclasses can override the virtual function // for GetInvalidRegContextDescription() to provide custom strings when // needed. //---------------------------------------------------------------------- eFlagRequiresRegContext = (1u << 4), //---------------------------------------------------------------------- // eFlagTryTargetAPILock // // Attempts to acquire the target lock if a target is selected in the // command interpreter. If the command object fails to acquire the API // lock, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagTryTargetAPILock = (1u << 5), //---------------------------------------------------------------------- // eFlagProcessMustBeLaunched // // Verifies that there is a launched process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBeLaunched = (1u << 6), //---------------------------------------------------------------------- // eFlagProcessMustBePaused // // Verifies that there is a paused process in m_exe_ctx, if there // isn't, the command will fail with an appropriate error message. //---------------------------------------------------------------------- eFlagProcessMustBePaused = (1u << 7) }; Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands. llvm-svn: 171990
2013-01-09 19:44:40 +00:00
}
if (error.AsCString()) {
result.AppendErrorWithFormat(
"Failed to write register '%s' with value '%s': %s\n",
reg_name.str().c_str(), value_str.str().c_str(),
error.AsCString());
} else {
result.AppendErrorWithFormat(
"Failed to write register '%s' with value '%s'",
reg_name.str().c_str(), value_str.str().c_str());
}
result.SetStatus(eReturnStatusFailed);
} else {
result.AppendErrorWithFormat("Register not found for '%s'.\n",
reg_name.str().c_str());
result.SetStatus(eReturnStatusFailed);
}
}
return result.Succeeded();
}
};
//----------------------------------------------------------------------
// CommandObjectRegister constructor
//----------------------------------------------------------------------
CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
: CommandObjectMultiword(interpreter, "register",
"Commands to access registers for the current "
"thread and stack frame.",
"register [read|write] ...") {
LoadSubCommand("read",
CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
LoadSubCommand("write",
CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
}
CommandObjectRegister::~CommandObjectRegister() = default;