15ffd83dbSDimitry Andric //===-- CommandObjectRegister.cpp -----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "CommandObjectRegister.h"
100b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
11fe013be4SDimitry Andric #include "lldb/Core/DumpRegisterInfo.h"
120b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
130b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
14fe013be4SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
15fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
160b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/OptionGroupFormat.h"
180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueArray.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
220b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h"
230b57cec5SDimitry Andric #include "lldb/Target/Process.h"
240b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
250b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
260b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
270b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
280b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
290b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
300b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric using namespace lldb;
330b57cec5SDimitry Andric using namespace lldb_private;
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric // "register read"
369dba64beSDimitry Andric #define LLDB_OPTIONS_register_read
379dba64beSDimitry Andric #include "CommandOptions.inc"
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric class CommandObjectRegisterRead : public CommandObjectParsed {
400b57cec5SDimitry Andric public:
CommandObjectRegisterRead(CommandInterpreter & interpreter)410b57cec5SDimitry Andric CommandObjectRegisterRead(CommandInterpreter &interpreter)
420b57cec5SDimitry Andric : CommandObjectParsed(
430b57cec5SDimitry Andric interpreter, "register read",
440b57cec5SDimitry Andric "Dump the contents of one or more register values from the current "
450b57cec5SDimitry Andric "frame. If no register is specified, dumps them all.",
460b57cec5SDimitry Andric nullptr,
470b57cec5SDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext |
480b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
49fe013be4SDimitry Andric m_format_options(eFormatDefault, UINT64_MAX, UINT64_MAX,
50fe013be4SDimitry Andric {{CommandArgumentType::eArgTypeFormat,
51fe013be4SDimitry Andric "Specify a format to be used for display. If this "
52fe013be4SDimitry Andric "is set, register fields will not be displayed."}}) {
530b57cec5SDimitry Andric CommandArgumentEntry arg;
540b57cec5SDimitry Andric CommandArgumentData register_arg;
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
570b57cec5SDimitry Andric register_arg.arg_type = eArgTypeRegisterName;
580b57cec5SDimitry Andric register_arg.arg_repetition = eArgRepeatStar;
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
610b57cec5SDimitry Andric // argument entry.
620b57cec5SDimitry Andric arg.push_back(register_arg);
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
650b57cec5SDimitry Andric m_arguments.push_back(arg);
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric // Add the "--format"
680b57cec5SDimitry Andric m_option_group.Append(&m_format_options,
690b57cec5SDimitry Andric OptionGroupFormat::OPTION_GROUP_FORMAT |
700b57cec5SDimitry Andric OptionGroupFormat::OPTION_GROUP_GDB_FMT,
710b57cec5SDimitry Andric LLDB_OPT_SET_ALL);
720b57cec5SDimitry Andric m_option_group.Append(&m_command_options);
730b57cec5SDimitry Andric m_option_group.Finalize();
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric ~CommandObjectRegisterRead() override = default;
770b57cec5SDimitry Andric
785ffd83dbSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)795ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
805ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override {
815ffd83dbSDimitry Andric if (!m_exe_ctx.HasProcessScope())
825ffd83dbSDimitry Andric return;
835ffd83dbSDimitry Andric
84fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
85fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr);
865ffd83dbSDimitry Andric }
875ffd83dbSDimitry Andric
GetOptions()880b57cec5SDimitry Andric Options *GetOptions() override { return &m_option_group; }
890b57cec5SDimitry Andric
DumpRegister(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext & reg_ctx,const RegisterInfo & reg_info,bool print_flags)900b57cec5SDimitry Andric bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
91fe013be4SDimitry Andric RegisterContext ®_ctx, const RegisterInfo ®_info,
92fe013be4SDimitry Andric bool print_flags) {
930b57cec5SDimitry Andric RegisterValue reg_value;
94fe013be4SDimitry Andric if (!reg_ctx.ReadRegister(®_info, reg_value))
95fe013be4SDimitry Andric return false;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric strm.Indent();
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric bool prefix_with_altname = (bool)m_command_options.alternate_name;
1000b57cec5SDimitry Andric bool prefix_with_name = !prefix_with_altname;
101fe013be4SDimitry Andric DumpRegisterValue(reg_value, strm, reg_info, prefix_with_name,
102bdd1243dSDimitry Andric prefix_with_altname, m_format_options.GetFormat(), 8,
103fe013be4SDimitry Andric exe_ctx.GetBestExecutionContextScope(), print_flags,
104fe013be4SDimitry Andric exe_ctx.GetTargetSP());
105fe013be4SDimitry Andric if ((reg_info.encoding == eEncodingUint) ||
106fe013be4SDimitry Andric (reg_info.encoding == eEncodingSint)) {
1070b57cec5SDimitry Andric Process *process = exe_ctx.GetProcessPtr();
108fe013be4SDimitry Andric if (process && reg_info.byte_size == process->GetAddressByteSize()) {
1090b57cec5SDimitry Andric addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
1100b57cec5SDimitry Andric if (reg_addr != LLDB_INVALID_ADDRESS) {
1110b57cec5SDimitry Andric Address so_reg_addr;
112fe013be4SDimitry Andric if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(
113fe013be4SDimitry Andric reg_addr, so_reg_addr)) {
1140b57cec5SDimitry Andric strm.PutCString(" ");
1150b57cec5SDimitry Andric so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
1160b57cec5SDimitry Andric Address::DumpStyleResolvedDescription);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric strm.EOL();
1220b57cec5SDimitry Andric return true;
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric
DumpRegisterSet(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext * reg_ctx,size_t set_idx,bool primitive_only=false)1250b57cec5SDimitry Andric bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
1260b57cec5SDimitry Andric RegisterContext *reg_ctx, size_t set_idx,
1270b57cec5SDimitry Andric bool primitive_only = false) {
1280b57cec5SDimitry Andric uint32_t unavailable_count = 0;
1290b57cec5SDimitry Andric uint32_t available_count = 0;
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric if (!reg_ctx)
1320b57cec5SDimitry Andric return false; // thread has no registers (i.e. core files are corrupt,
1330b57cec5SDimitry Andric // incomplete crash logs...)
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
1360b57cec5SDimitry Andric if (reg_set) {
1370b57cec5SDimitry Andric strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
1380b57cec5SDimitry Andric strm.IndentMore();
1390b57cec5SDimitry Andric const size_t num_registers = reg_set->num_registers;
1400b57cec5SDimitry Andric for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
1410b57cec5SDimitry Andric const uint32_t reg = reg_set->registers[reg_idx];
1420b57cec5SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
1430b57cec5SDimitry Andric // Skip the dumping of derived register if primitive_only is true.
1440b57cec5SDimitry Andric if (primitive_only && reg_info && reg_info->value_regs)
1450b57cec5SDimitry Andric continue;
1460b57cec5SDimitry Andric
147fe013be4SDimitry Andric if (reg_info && DumpRegister(exe_ctx, strm, *reg_ctx, *reg_info,
148fe013be4SDimitry Andric /*print_flags=*/false))
1490b57cec5SDimitry Andric ++available_count;
1500b57cec5SDimitry Andric else
1510b57cec5SDimitry Andric ++unavailable_count;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric strm.IndentLess();
1540b57cec5SDimitry Andric if (unavailable_count) {
1550b57cec5SDimitry Andric strm.Indent();
1560b57cec5SDimitry Andric strm.Printf("%u registers were unavailable.\n", unavailable_count);
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric strm.EOL();
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric return available_count > 0;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)164*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
1650b57cec5SDimitry Andric Stream &strm = result.GetOutputStream();
1660b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) {
1690b57cec5SDimitry Andric size_t set_idx;
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric size_t num_register_sets = 1;
1720b57cec5SDimitry Andric const size_t set_array_size = m_command_options.set_indexes.GetSize();
1730b57cec5SDimitry Andric if (set_array_size > 0) {
1740b57cec5SDimitry Andric for (size_t i = 0; i < set_array_size; ++i) {
175fe013be4SDimitry Andric set_idx =
176fe013be4SDimitry Andric m_command_options.set_indexes[i]->GetValueAs<uint64_t>().value_or(
177fe013be4SDimitry Andric UINT32_MAX);
1780b57cec5SDimitry Andric if (set_idx < reg_ctx->GetRegisterSetCount()) {
1790b57cec5SDimitry Andric if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
1800b57cec5SDimitry Andric if (errno)
1810b57cec5SDimitry Andric result.AppendErrorWithFormatv("register read failed: {0}\n",
1820b57cec5SDimitry Andric llvm::sys::StrError());
1830b57cec5SDimitry Andric else
1840b57cec5SDimitry Andric result.AppendError("unknown error while reading registers.\n");
1850b57cec5SDimitry Andric break;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric } else {
1880b57cec5SDimitry Andric result.AppendErrorWithFormat(
1890b57cec5SDimitry Andric "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
1900b57cec5SDimitry Andric break;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric } else {
1940b57cec5SDimitry Andric if (m_command_options.dump_all_sets)
1950b57cec5SDimitry Andric num_register_sets = reg_ctx->GetRegisterSetCount();
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
1980b57cec5SDimitry Andric // When dump_all_sets option is set, dump primitive as well as
1990b57cec5SDimitry Andric // derived registers.
2000b57cec5SDimitry Andric DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
2010b57cec5SDimitry Andric !m_command_options.dump_all_sets.GetCurrentValue());
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric } else {
2050b57cec5SDimitry Andric if (m_command_options.dump_all_sets) {
2060b57cec5SDimitry Andric result.AppendError("the --all option can't be used when registers "
2070b57cec5SDimitry Andric "names are supplied as arguments\n");
2080b57cec5SDimitry Andric } else if (m_command_options.set_indexes.GetSize() > 0) {
2090b57cec5SDimitry Andric result.AppendError("the --set <set> option can't be used when "
2100b57cec5SDimitry Andric "registers names are supplied as arguments\n");
2110b57cec5SDimitry Andric } else {
2120b57cec5SDimitry Andric for (auto &entry : command) {
2130b57cec5SDimitry Andric // in most LLDB commands we accept $rbx as the name for register RBX
2140b57cec5SDimitry Andric // - and here we would reject it and non-existant. we should be more
2150b57cec5SDimitry Andric // consistent towards the user and allow them to say reg read $rbx -
2160b57cec5SDimitry Andric // internally, however, we should be strict and not allow ourselves
2170b57cec5SDimitry Andric // to call our registers $rbx in our own API
2189dba64beSDimitry Andric auto arg_str = entry.ref();
2190b57cec5SDimitry Andric arg_str.consume_front("$");
2200b57cec5SDimitry Andric
221fe013be4SDimitry Andric if (const RegisterInfo *reg_info =
222fe013be4SDimitry Andric reg_ctx->GetRegisterInfoByName(arg_str)) {
223fe013be4SDimitry Andric // If they have asked for a specific format don't obscure that by
224fe013be4SDimitry Andric // printing flags afterwards.
225fe013be4SDimitry Andric bool print_flags =
226fe013be4SDimitry Andric !m_format_options.GetFormatValue().OptionWasSet();
227fe013be4SDimitry Andric if (!DumpRegister(m_exe_ctx, strm, *reg_ctx, *reg_info,
228fe013be4SDimitry Andric print_flags))
2290b57cec5SDimitry Andric strm.Printf("%-12s = error: unavailable\n", reg_info->name);
2300b57cec5SDimitry Andric } else {
2310b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid register name '%s'.\n",
2320b57cec5SDimitry Andric arg_str.str().c_str());
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric class CommandOptions : public OptionGroup {
2400b57cec5SDimitry Andric public:
CommandOptions()2410b57cec5SDimitry Andric CommandOptions()
24204eeddc0SDimitry Andric : set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
2430b57cec5SDimitry Andric dump_all_sets(false, false), // Initial and default values are false
2440b57cec5SDimitry Andric alternate_name(false, false) {}
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric ~CommandOptions() override = default;
2470b57cec5SDimitry Andric
GetDefinitions()2480b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
249bdd1243dSDimitry Andric return llvm::ArrayRef(g_register_read_options);
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2520b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2530b57cec5SDimitry Andric set_indexes.Clear();
2540b57cec5SDimitry Andric dump_all_sets.Clear();
2550b57cec5SDimitry Andric alternate_name.Clear();
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)2580b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2590b57cec5SDimitry Andric ExecutionContext *execution_context) override {
2600b57cec5SDimitry Andric Status error;
2610b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
2620b57cec5SDimitry Andric switch (short_option) {
2630b57cec5SDimitry Andric case 's': {
2640b57cec5SDimitry Andric OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
2650b57cec5SDimitry Andric if (value_sp)
2660b57cec5SDimitry Andric set_indexes.AppendValue(value_sp);
2670b57cec5SDimitry Andric } break;
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric case 'a':
2700b57cec5SDimitry Andric // When we don't use OptionValue::SetValueFromCString(const char *) to
2710b57cec5SDimitry Andric // set an option value, it won't be marked as being set in the options
2720b57cec5SDimitry Andric // so we make a call to let users know the value was set via option
2730b57cec5SDimitry Andric dump_all_sets.SetCurrentValue(true);
2740b57cec5SDimitry Andric dump_all_sets.SetOptionWasSet();
2750b57cec5SDimitry Andric break;
2760b57cec5SDimitry Andric
2770b57cec5SDimitry Andric case 'A':
2780b57cec5SDimitry Andric // When we don't use OptionValue::SetValueFromCString(const char *) to
2790b57cec5SDimitry Andric // set an option value, it won't be marked as being set in the options
2800b57cec5SDimitry Andric // so we make a call to let users know the value was set via option
2810b57cec5SDimitry Andric alternate_name.SetCurrentValue(true);
2820b57cec5SDimitry Andric dump_all_sets.SetOptionWasSet();
2830b57cec5SDimitry Andric break;
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric default:
2869dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric return error;
2890b57cec5SDimitry Andric }
2900b57cec5SDimitry Andric
2910b57cec5SDimitry Andric // Instance variables to hold the values for command options.
2920b57cec5SDimitry Andric OptionValueArray set_indexes;
2930b57cec5SDimitry Andric OptionValueBoolean dump_all_sets;
2940b57cec5SDimitry Andric OptionValueBoolean alternate_name;
2950b57cec5SDimitry Andric };
2960b57cec5SDimitry Andric
2970b57cec5SDimitry Andric OptionGroupOptions m_option_group;
2980b57cec5SDimitry Andric OptionGroupFormat m_format_options;
2990b57cec5SDimitry Andric CommandOptions m_command_options;
3000b57cec5SDimitry Andric };
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric // "register write"
3030b57cec5SDimitry Andric class CommandObjectRegisterWrite : public CommandObjectParsed {
3040b57cec5SDimitry Andric public:
CommandObjectRegisterWrite(CommandInterpreter & interpreter)3050b57cec5SDimitry Andric CommandObjectRegisterWrite(CommandInterpreter &interpreter)
3060b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "register write",
3070b57cec5SDimitry Andric "Modify a single register value.", nullptr,
3080b57cec5SDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext |
3090b57cec5SDimitry Andric eCommandProcessMustBeLaunched |
3100b57cec5SDimitry Andric eCommandProcessMustBePaused) {
3110b57cec5SDimitry Andric CommandArgumentEntry arg1;
3120b57cec5SDimitry Andric CommandArgumentEntry arg2;
3130b57cec5SDimitry Andric CommandArgumentData register_arg;
3140b57cec5SDimitry Andric CommandArgumentData value_arg;
3150b57cec5SDimitry Andric
3160b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
3170b57cec5SDimitry Andric register_arg.arg_type = eArgTypeRegisterName;
3180b57cec5SDimitry Andric register_arg.arg_repetition = eArgRepeatPlain;
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
3210b57cec5SDimitry Andric // argument entry.
3220b57cec5SDimitry Andric arg1.push_back(register_arg);
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
3250b57cec5SDimitry Andric value_arg.arg_type = eArgTypeValue;
3260b57cec5SDimitry Andric value_arg.arg_repetition = eArgRepeatPlain;
3270b57cec5SDimitry Andric
3280b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
3290b57cec5SDimitry Andric // argument entry.
3300b57cec5SDimitry Andric arg2.push_back(value_arg);
3310b57cec5SDimitry Andric
3320b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
3330b57cec5SDimitry Andric m_arguments.push_back(arg1);
3340b57cec5SDimitry Andric m_arguments.push_back(arg2);
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric
3370b57cec5SDimitry Andric ~CommandObjectRegisterWrite() override = default;
3380b57cec5SDimitry Andric
3395ffd83dbSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)3405ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
3415ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override {
3425ffd83dbSDimitry Andric if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
3435ffd83dbSDimitry Andric return;
3445ffd83dbSDimitry Andric
345fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
346fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr);
3475ffd83dbSDimitry Andric }
3485ffd83dbSDimitry Andric
3490b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)350*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
3510b57cec5SDimitry Andric DataExtractor reg_data;
3520b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric if (command.GetArgumentCount() != 2) {
3550b57cec5SDimitry Andric result.AppendError(
3560b57cec5SDimitry Andric "register write takes exactly 2 arguments: <reg-name> <value>");
3570b57cec5SDimitry Andric } else {
3589dba64beSDimitry Andric auto reg_name = command[0].ref();
3599dba64beSDimitry Andric auto value_str = command[1].ref();
3600b57cec5SDimitry Andric
3610b57cec5SDimitry Andric // in most LLDB commands we accept $rbx as the name for register RBX -
3620b57cec5SDimitry Andric // and here we would reject it and non-existant. we should be more
3630b57cec5SDimitry Andric // consistent towards the user and allow them to say reg write $rbx -
3640b57cec5SDimitry Andric // internally, however, we should be strict and not allow ourselves to
3650b57cec5SDimitry Andric // call our registers $rbx in our own API
3660b57cec5SDimitry Andric reg_name.consume_front("$");
3670b57cec5SDimitry Andric
3680b57cec5SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
3690b57cec5SDimitry Andric
3700b57cec5SDimitry Andric if (reg_info) {
3710b57cec5SDimitry Andric RegisterValue reg_value;
3720b57cec5SDimitry Andric
3730b57cec5SDimitry Andric Status error(reg_value.SetValueFromString(reg_info, value_str));
3740b57cec5SDimitry Andric if (error.Success()) {
3750b57cec5SDimitry Andric if (reg_ctx->WriteRegister(reg_info, reg_value)) {
3760b57cec5SDimitry Andric // Toss all frames and anything else in the thread after a register
3770b57cec5SDimitry Andric // has been written.
3780b57cec5SDimitry Andric m_exe_ctx.GetThreadRef().Flush();
3790b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
380*c9157d92SDimitry Andric return;
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric if (error.AsCString()) {
3840b57cec5SDimitry Andric result.AppendErrorWithFormat(
3850b57cec5SDimitry Andric "Failed to write register '%s' with value '%s': %s\n",
3860b57cec5SDimitry Andric reg_name.str().c_str(), value_str.str().c_str(),
3870b57cec5SDimitry Andric error.AsCString());
3880b57cec5SDimitry Andric } else {
3890b57cec5SDimitry Andric result.AppendErrorWithFormat(
3900b57cec5SDimitry Andric "Failed to write register '%s' with value '%s'",
3910b57cec5SDimitry Andric reg_name.str().c_str(), value_str.str().c_str());
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric } else {
3940b57cec5SDimitry Andric result.AppendErrorWithFormat("Register not found for '%s'.\n",
3950b57cec5SDimitry Andric reg_name.str().c_str());
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric };
4000b57cec5SDimitry Andric
401fe013be4SDimitry Andric // "register info"
402fe013be4SDimitry Andric class CommandObjectRegisterInfo : public CommandObjectParsed {
403fe013be4SDimitry Andric public:
CommandObjectRegisterInfo(CommandInterpreter & interpreter)404fe013be4SDimitry Andric CommandObjectRegisterInfo(CommandInterpreter &interpreter)
405fe013be4SDimitry Andric : CommandObjectParsed(interpreter, "register info",
406fe013be4SDimitry Andric "View information about a register.", nullptr,
407*c9157d92SDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext |
408*c9157d92SDimitry Andric eCommandProcessMustBeLaunched |
409*c9157d92SDimitry Andric eCommandProcessMustBePaused) {
410fe013be4SDimitry Andric SetHelpLong(R"(
411fe013be4SDimitry Andric Name The name lldb uses for the register, optionally with an alias.
412fe013be4SDimitry Andric Size The size of the register in bytes and again in bits.
413fe013be4SDimitry Andric Invalidates (*) The registers that would be changed if you wrote this
414fe013be4SDimitry Andric register. For example, writing to a narrower alias of a wider
415fe013be4SDimitry Andric register would change the value of the wider register.
416fe013be4SDimitry Andric Read from (*) The registers that the value of this register is constructed
417fe013be4SDimitry Andric from. For example, a narrower alias of a wider register will be
418fe013be4SDimitry Andric read from the wider register.
419fe013be4SDimitry Andric In sets (*) The register sets that contain this register. For example the
420fe013be4SDimitry Andric PC will be in the "General Purpose Register" set.
421fe013be4SDimitry Andric Fields (*) A table of the names and bit positions of the values contained
422fe013be4SDimitry Andric in this register.
423fe013be4SDimitry Andric
424fe013be4SDimitry Andric Fields marked with (*) may not always be present. Some information may be
425fe013be4SDimitry Andric different for the same register when connected to different debug servers.)");
426fe013be4SDimitry Andric
427fe013be4SDimitry Andric CommandArgumentData register_arg;
428fe013be4SDimitry Andric register_arg.arg_type = eArgTypeRegisterName;
429fe013be4SDimitry Andric register_arg.arg_repetition = eArgRepeatPlain;
430fe013be4SDimitry Andric
431fe013be4SDimitry Andric CommandArgumentEntry arg1;
432fe013be4SDimitry Andric arg1.push_back(register_arg);
433fe013be4SDimitry Andric m_arguments.push_back(arg1);
434fe013be4SDimitry Andric }
435fe013be4SDimitry Andric
436fe013be4SDimitry Andric ~CommandObjectRegisterInfo() override = default;
437fe013be4SDimitry Andric
438fe013be4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)439fe013be4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
440fe013be4SDimitry Andric OptionElementVector &opt_element_vector) override {
441fe013be4SDimitry Andric if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
442fe013be4SDimitry Andric return;
443fe013be4SDimitry Andric CommandCompletions::InvokeCommonCompletionCallbacks(
444fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr);
445fe013be4SDimitry Andric }
446fe013be4SDimitry Andric
447fe013be4SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)448*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
449fe013be4SDimitry Andric if (command.GetArgumentCount() != 1) {
450fe013be4SDimitry Andric result.AppendError("register info takes exactly 1 argument: <reg-name>");
451*c9157d92SDimitry Andric return;
452fe013be4SDimitry Andric }
453fe013be4SDimitry Andric
454fe013be4SDimitry Andric llvm::StringRef reg_name = command[0].ref();
455fe013be4SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
456fe013be4SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
457fe013be4SDimitry Andric if (reg_info) {
458fe013be4SDimitry Andric DumpRegisterInfo(
459fe013be4SDimitry Andric result.GetOutputStream(), *reg_ctx, *reg_info,
460fe013be4SDimitry Andric GetCommandInterpreter().GetDebugger().GetTerminalWidth());
461fe013be4SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
462fe013be4SDimitry Andric } else
463fe013be4SDimitry Andric result.AppendErrorWithFormat("No register found with name '%s'.\n",
464fe013be4SDimitry Andric reg_name.str().c_str());
465fe013be4SDimitry Andric }
466fe013be4SDimitry Andric };
467fe013be4SDimitry Andric
4680b57cec5SDimitry Andric // CommandObjectRegister constructor
CommandObjectRegister(CommandInterpreter & interpreter)4690b57cec5SDimitry Andric CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
4700b57cec5SDimitry Andric : CommandObjectMultiword(interpreter, "register",
4710b57cec5SDimitry Andric "Commands to access registers for the current "
4720b57cec5SDimitry Andric "thread and stack frame.",
473fe013be4SDimitry Andric "register [read|write|info] ...") {
4740b57cec5SDimitry Andric LoadSubCommand("read",
4750b57cec5SDimitry Andric CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
4760b57cec5SDimitry Andric LoadSubCommand("write",
4770b57cec5SDimitry Andric CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
478fe013be4SDimitry Andric LoadSubCommand("info",
479fe013be4SDimitry Andric CommandObjectSP(new CommandObjectRegisterInfo(interpreter)));
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric
4820b57cec5SDimitry Andric CommandObjectRegister::~CommandObjectRegister() = default;
483