xref: /freebsd-src/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
1106c3fb27SDimitry Andric #include "lldb/Core/DumpRegisterInfo.h"
120b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
130b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
1406c3fb27SDimitry 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:
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),
4906c3fb27SDimitry Andric         m_format_options(eFormatDefault, UINT64_MAX, UINT64_MAX,
5006c3fb27SDimitry Andric                          {{CommandArgumentType::eArgTypeFormat,
5106c3fb27SDimitry Andric                            "Specify a format to be used for display. If this "
5206c3fb27SDimitry Andric                            "is set, register fields will not be displayed."}}) {
53*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeRegisterName, eArgRepeatStar);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric     // Add the "--format"
560b57cec5SDimitry Andric     m_option_group.Append(&m_format_options,
570b57cec5SDimitry Andric                           OptionGroupFormat::OPTION_GROUP_FORMAT |
580b57cec5SDimitry Andric                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
590b57cec5SDimitry Andric                           LLDB_OPT_SET_ALL);
600b57cec5SDimitry Andric     m_option_group.Append(&m_command_options);
610b57cec5SDimitry Andric     m_option_group.Finalize();
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   ~CommandObjectRegisterRead() override = default;
650b57cec5SDimitry Andric 
665ffd83dbSDimitry Andric   void
675ffd83dbSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
685ffd83dbSDimitry Andric                            OptionElementVector &opt_element_vector) override {
695ffd83dbSDimitry Andric     if (!m_exe_ctx.HasProcessScope())
705ffd83dbSDimitry Andric       return;
71*0fca6ea1SDimitry Andric     CommandObject::HandleArgumentCompletion(request, opt_element_vector);
725ffd83dbSDimitry Andric   }
735ffd83dbSDimitry Andric 
740b57cec5SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
7706c3fb27SDimitry Andric                     RegisterContext &reg_ctx, const RegisterInfo &reg_info,
7806c3fb27SDimitry Andric                     bool print_flags) {
790b57cec5SDimitry Andric     RegisterValue reg_value;
8006c3fb27SDimitry Andric     if (!reg_ctx.ReadRegister(&reg_info, reg_value))
8106c3fb27SDimitry Andric       return false;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric     strm.Indent();
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     bool prefix_with_altname = (bool)m_command_options.alternate_name;
860b57cec5SDimitry Andric     bool prefix_with_name = !prefix_with_altname;
8706c3fb27SDimitry Andric     DumpRegisterValue(reg_value, strm, reg_info, prefix_with_name,
88bdd1243dSDimitry Andric                       prefix_with_altname, m_format_options.GetFormat(), 8,
8906c3fb27SDimitry Andric                       exe_ctx.GetBestExecutionContextScope(), print_flags,
9006c3fb27SDimitry Andric                       exe_ctx.GetTargetSP());
9106c3fb27SDimitry Andric     if ((reg_info.encoding == eEncodingUint) ||
9206c3fb27SDimitry Andric         (reg_info.encoding == eEncodingSint)) {
930b57cec5SDimitry Andric       Process *process = exe_ctx.GetProcessPtr();
9406c3fb27SDimitry Andric       if (process && reg_info.byte_size == process->GetAddressByteSize()) {
950b57cec5SDimitry Andric         addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
960b57cec5SDimitry Andric         if (reg_addr != LLDB_INVALID_ADDRESS) {
970b57cec5SDimitry Andric           Address so_reg_addr;
9806c3fb27SDimitry Andric           if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(
9906c3fb27SDimitry Andric                   reg_addr, so_reg_addr)) {
1000b57cec5SDimitry Andric             strm.PutCString("  ");
1010b57cec5SDimitry Andric             so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
1020b57cec5SDimitry Andric                              Address::DumpStyleResolvedDescription);
1030b57cec5SDimitry Andric           }
1040b57cec5SDimitry Andric         }
1050b57cec5SDimitry Andric       }
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric     strm.EOL();
1080b57cec5SDimitry Andric     return true;
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
1120b57cec5SDimitry Andric                        RegisterContext *reg_ctx, size_t set_idx,
1130b57cec5SDimitry Andric                        bool primitive_only = false) {
1140b57cec5SDimitry Andric     uint32_t unavailable_count = 0;
1150b57cec5SDimitry Andric     uint32_t available_count = 0;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     if (!reg_ctx)
1180b57cec5SDimitry Andric       return false; // thread has no registers (i.e. core files are corrupt,
1190b57cec5SDimitry Andric                     // incomplete crash logs...)
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric     const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
1220b57cec5SDimitry Andric     if (reg_set) {
1230b57cec5SDimitry Andric       strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
1240b57cec5SDimitry Andric       strm.IndentMore();
1250b57cec5SDimitry Andric       const size_t num_registers = reg_set->num_registers;
1260b57cec5SDimitry Andric       for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
1270b57cec5SDimitry Andric         const uint32_t reg = reg_set->registers[reg_idx];
1280b57cec5SDimitry Andric         const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
1290b57cec5SDimitry Andric         // Skip the dumping of derived register if primitive_only is true.
1300b57cec5SDimitry Andric         if (primitive_only && reg_info && reg_info->value_regs)
1310b57cec5SDimitry Andric           continue;
1320b57cec5SDimitry Andric 
13306c3fb27SDimitry Andric         if (reg_info && DumpRegister(exe_ctx, strm, *reg_ctx, *reg_info,
13406c3fb27SDimitry Andric                                      /*print_flags=*/false))
1350b57cec5SDimitry Andric           ++available_count;
1360b57cec5SDimitry Andric         else
1370b57cec5SDimitry Andric           ++unavailable_count;
1380b57cec5SDimitry Andric       }
1390b57cec5SDimitry Andric       strm.IndentLess();
1400b57cec5SDimitry Andric       if (unavailable_count) {
1410b57cec5SDimitry Andric         strm.Indent();
1420b57cec5SDimitry Andric         strm.Printf("%u registers were unavailable.\n", unavailable_count);
1430b57cec5SDimitry Andric       }
1440b57cec5SDimitry Andric       strm.EOL();
1450b57cec5SDimitry Andric     }
1460b57cec5SDimitry Andric     return available_count > 0;
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric protected:
1505f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
1510b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
1520b57cec5SDimitry Andric     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     if (command.GetArgumentCount() == 0) {
1550b57cec5SDimitry Andric       size_t set_idx;
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric       size_t num_register_sets = 1;
1580b57cec5SDimitry Andric       const size_t set_array_size = m_command_options.set_indexes.GetSize();
1590b57cec5SDimitry Andric       if (set_array_size > 0) {
1600b57cec5SDimitry Andric         for (size_t i = 0; i < set_array_size; ++i) {
16106c3fb27SDimitry Andric           set_idx =
16206c3fb27SDimitry Andric               m_command_options.set_indexes[i]->GetValueAs<uint64_t>().value_or(
16306c3fb27SDimitry Andric                   UINT32_MAX);
1640b57cec5SDimitry Andric           if (set_idx < reg_ctx->GetRegisterSetCount()) {
1650b57cec5SDimitry Andric             if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
1660b57cec5SDimitry Andric               if (errno)
1670b57cec5SDimitry Andric                 result.AppendErrorWithFormatv("register read failed: {0}\n",
1680b57cec5SDimitry Andric                                               llvm::sys::StrError());
1690b57cec5SDimitry Andric               else
1700b57cec5SDimitry Andric                 result.AppendError("unknown error while reading registers.\n");
1710b57cec5SDimitry Andric               break;
1720b57cec5SDimitry Andric             }
1730b57cec5SDimitry Andric           } else {
1740b57cec5SDimitry Andric             result.AppendErrorWithFormat(
1750b57cec5SDimitry Andric                 "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
1760b57cec5SDimitry Andric             break;
1770b57cec5SDimitry Andric           }
1780b57cec5SDimitry Andric         }
1790b57cec5SDimitry Andric       } else {
1800b57cec5SDimitry Andric         if (m_command_options.dump_all_sets)
1810b57cec5SDimitry Andric           num_register_sets = reg_ctx->GetRegisterSetCount();
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric         for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
1840b57cec5SDimitry Andric           // When dump_all_sets option is set, dump primitive as well as
1850b57cec5SDimitry Andric           // derived registers.
1860b57cec5SDimitry Andric           DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
1870b57cec5SDimitry Andric                           !m_command_options.dump_all_sets.GetCurrentValue());
1880b57cec5SDimitry Andric         }
1890b57cec5SDimitry Andric       }
1900b57cec5SDimitry Andric     } else {
1910b57cec5SDimitry Andric       if (m_command_options.dump_all_sets) {
1920b57cec5SDimitry Andric         result.AppendError("the --all option can't be used when registers "
1930b57cec5SDimitry Andric                            "names are supplied as arguments\n");
1940b57cec5SDimitry Andric       } else if (m_command_options.set_indexes.GetSize() > 0) {
1950b57cec5SDimitry Andric         result.AppendError("the --set <set> option can't be used when "
1960b57cec5SDimitry Andric                            "registers names are supplied as arguments\n");
1970b57cec5SDimitry Andric       } else {
1980b57cec5SDimitry Andric         for (auto &entry : command) {
1990b57cec5SDimitry Andric           // in most LLDB commands we accept $rbx as the name for register RBX
2000b57cec5SDimitry Andric           // - and here we would reject it and non-existant. we should be more
2010b57cec5SDimitry Andric           // consistent towards the user and allow them to say reg read $rbx -
2020b57cec5SDimitry Andric           // internally, however, we should be strict and not allow ourselves
2030b57cec5SDimitry Andric           // to call our registers $rbx in our own API
2049dba64beSDimitry Andric           auto arg_str = entry.ref();
2050b57cec5SDimitry Andric           arg_str.consume_front("$");
2060b57cec5SDimitry Andric 
20706c3fb27SDimitry Andric           if (const RegisterInfo *reg_info =
20806c3fb27SDimitry Andric                   reg_ctx->GetRegisterInfoByName(arg_str)) {
20906c3fb27SDimitry Andric             // If they have asked for a specific format don't obscure that by
21006c3fb27SDimitry Andric             // printing flags afterwards.
21106c3fb27SDimitry Andric             bool print_flags =
21206c3fb27SDimitry Andric                 !m_format_options.GetFormatValue().OptionWasSet();
21306c3fb27SDimitry Andric             if (!DumpRegister(m_exe_ctx, strm, *reg_ctx, *reg_info,
21406c3fb27SDimitry Andric                               print_flags))
2150b57cec5SDimitry Andric               strm.Printf("%-12s = error: unavailable\n", reg_info->name);
2160b57cec5SDimitry Andric           } else {
2170b57cec5SDimitry Andric             result.AppendErrorWithFormat("Invalid register name '%s'.\n",
2180b57cec5SDimitry Andric                                          arg_str.str().c_str());
2190b57cec5SDimitry Andric           }
2200b57cec5SDimitry Andric         }
2210b57cec5SDimitry Andric       }
2220b57cec5SDimitry Andric     }
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   class CommandOptions : public OptionGroup {
2260b57cec5SDimitry Andric   public:
2270b57cec5SDimitry Andric     CommandOptions()
22804eeddc0SDimitry Andric         : set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
2290b57cec5SDimitry Andric           dump_all_sets(false, false), // Initial and default values are false
2300b57cec5SDimitry Andric           alternate_name(false, false) {}
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric     ~CommandOptions() override = default;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
235bdd1243dSDimitry Andric       return llvm::ArrayRef(g_register_read_options);
2360b57cec5SDimitry Andric     }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2390b57cec5SDimitry Andric       set_indexes.Clear();
2400b57cec5SDimitry Andric       dump_all_sets.Clear();
2410b57cec5SDimitry Andric       alternate_name.Clear();
2420b57cec5SDimitry Andric     }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2450b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
2460b57cec5SDimitry Andric       Status error;
2470b57cec5SDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
2480b57cec5SDimitry Andric       switch (short_option) {
2490b57cec5SDimitry Andric       case 's': {
2500b57cec5SDimitry Andric         OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
2510b57cec5SDimitry Andric         if (value_sp)
2520b57cec5SDimitry Andric           set_indexes.AppendValue(value_sp);
2530b57cec5SDimitry Andric       } break;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric       case 'a':
2560b57cec5SDimitry Andric         // When we don't use OptionValue::SetValueFromCString(const char *) to
2570b57cec5SDimitry Andric         // set an option value, it won't be marked as being set in the options
2580b57cec5SDimitry Andric         // so we make a call to let users know the value was set via option
2590b57cec5SDimitry Andric         dump_all_sets.SetCurrentValue(true);
2600b57cec5SDimitry Andric         dump_all_sets.SetOptionWasSet();
2610b57cec5SDimitry Andric         break;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric       case 'A':
2640b57cec5SDimitry Andric         // When we don't use OptionValue::SetValueFromCString(const char *) to
2650b57cec5SDimitry Andric         // set an option value, it won't be marked as being set in the options
2660b57cec5SDimitry Andric         // so we make a call to let users know the value was set via option
2670b57cec5SDimitry Andric         alternate_name.SetCurrentValue(true);
2680b57cec5SDimitry Andric         dump_all_sets.SetOptionWasSet();
2690b57cec5SDimitry Andric         break;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric       default:
2729dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
2730b57cec5SDimitry Andric       }
2740b57cec5SDimitry Andric       return error;
2750b57cec5SDimitry Andric     }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
2780b57cec5SDimitry Andric     OptionValueArray set_indexes;
2790b57cec5SDimitry Andric     OptionValueBoolean dump_all_sets;
2800b57cec5SDimitry Andric     OptionValueBoolean alternate_name;
2810b57cec5SDimitry Andric   };
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   OptionGroupOptions m_option_group;
2840b57cec5SDimitry Andric   OptionGroupFormat m_format_options;
2850b57cec5SDimitry Andric   CommandOptions m_command_options;
2860b57cec5SDimitry Andric };
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric // "register write"
2890b57cec5SDimitry Andric class CommandObjectRegisterWrite : public CommandObjectParsed {
2900b57cec5SDimitry Andric public:
2910b57cec5SDimitry Andric   CommandObjectRegisterWrite(CommandInterpreter &interpreter)
2920b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "register write",
2930b57cec5SDimitry Andric                             "Modify a single register value.", nullptr,
2940b57cec5SDimitry Andric                             eCommandRequiresFrame | eCommandRequiresRegContext |
2950b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
2960b57cec5SDimitry Andric                                 eCommandProcessMustBePaused) {
2970b57cec5SDimitry Andric     CommandArgumentEntry arg1;
2980b57cec5SDimitry Andric     CommandArgumentEntry arg2;
2990b57cec5SDimitry Andric     CommandArgumentData register_arg;
3000b57cec5SDimitry Andric     CommandArgumentData value_arg;
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3030b57cec5SDimitry Andric     register_arg.arg_type = eArgTypeRegisterName;
3040b57cec5SDimitry Andric     register_arg.arg_repetition = eArgRepeatPlain;
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3070b57cec5SDimitry Andric     // argument entry.
3080b57cec5SDimitry Andric     arg1.push_back(register_arg);
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3110b57cec5SDimitry Andric     value_arg.arg_type = eArgTypeValue;
3120b57cec5SDimitry Andric     value_arg.arg_repetition = eArgRepeatPlain;
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3150b57cec5SDimitry Andric     // argument entry.
3160b57cec5SDimitry Andric     arg2.push_back(value_arg);
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
3190b57cec5SDimitry Andric     m_arguments.push_back(arg1);
3200b57cec5SDimitry Andric     m_arguments.push_back(arg2);
3210b57cec5SDimitry Andric   }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   ~CommandObjectRegisterWrite() override = default;
3240b57cec5SDimitry Andric 
3255ffd83dbSDimitry Andric   void
3265ffd83dbSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
3275ffd83dbSDimitry Andric                            OptionElementVector &opt_element_vector) override {
3285ffd83dbSDimitry Andric     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
3295ffd83dbSDimitry Andric       return;
3305ffd83dbSDimitry Andric 
33106c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
33206c3fb27SDimitry Andric         GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr);
3335ffd83dbSDimitry Andric   }
3345ffd83dbSDimitry Andric 
3350b57cec5SDimitry Andric protected:
3365f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
3370b57cec5SDimitry Andric     DataExtractor reg_data;
3380b57cec5SDimitry Andric     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric     if (command.GetArgumentCount() != 2) {
3410b57cec5SDimitry Andric       result.AppendError(
3420b57cec5SDimitry Andric           "register write takes exactly 2 arguments: <reg-name> <value>");
3430b57cec5SDimitry Andric     } else {
3449dba64beSDimitry Andric       auto reg_name = command[0].ref();
3459dba64beSDimitry Andric       auto value_str = command[1].ref();
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric       // in most LLDB commands we accept $rbx as the name for register RBX -
3480b57cec5SDimitry Andric       // and here we would reject it and non-existant. we should be more
3490b57cec5SDimitry Andric       // consistent towards the user and allow them to say reg write $rbx -
3500b57cec5SDimitry Andric       // internally, however, we should be strict and not allow ourselves to
3510b57cec5SDimitry Andric       // call our registers $rbx in our own API
3520b57cec5SDimitry Andric       reg_name.consume_front("$");
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric       if (reg_info) {
3570b57cec5SDimitry Andric         RegisterValue reg_value;
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric         Status error(reg_value.SetValueFromString(reg_info, value_str));
3600b57cec5SDimitry Andric         if (error.Success()) {
3610b57cec5SDimitry Andric           if (reg_ctx->WriteRegister(reg_info, reg_value)) {
3620b57cec5SDimitry Andric             // Toss all frames and anything else in the thread after a register
3630b57cec5SDimitry Andric             // has been written.
3640b57cec5SDimitry Andric             m_exe_ctx.GetThreadRef().Flush();
3650b57cec5SDimitry Andric             result.SetStatus(eReturnStatusSuccessFinishNoResult);
3665f757f3fSDimitry Andric             return;
3670b57cec5SDimitry Andric           }
3680b57cec5SDimitry Andric         }
3690b57cec5SDimitry Andric         if (error.AsCString()) {
3700b57cec5SDimitry Andric           result.AppendErrorWithFormat(
3710b57cec5SDimitry Andric               "Failed to write register '%s' with value '%s': %s\n",
3720b57cec5SDimitry Andric               reg_name.str().c_str(), value_str.str().c_str(),
3730b57cec5SDimitry Andric               error.AsCString());
3740b57cec5SDimitry Andric         } else {
3750b57cec5SDimitry Andric           result.AppendErrorWithFormat(
3760b57cec5SDimitry Andric               "Failed to write register '%s' with value '%s'",
3770b57cec5SDimitry Andric               reg_name.str().c_str(), value_str.str().c_str());
3780b57cec5SDimitry Andric         }
3790b57cec5SDimitry Andric       } else {
3800b57cec5SDimitry Andric         result.AppendErrorWithFormat("Register not found for '%s'.\n",
3810b57cec5SDimitry Andric                                      reg_name.str().c_str());
3820b57cec5SDimitry Andric       }
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric };
3860b57cec5SDimitry Andric 
38706c3fb27SDimitry Andric // "register info"
38806c3fb27SDimitry Andric class CommandObjectRegisterInfo : public CommandObjectParsed {
38906c3fb27SDimitry Andric public:
39006c3fb27SDimitry Andric   CommandObjectRegisterInfo(CommandInterpreter &interpreter)
39106c3fb27SDimitry Andric       : CommandObjectParsed(interpreter, "register info",
39206c3fb27SDimitry Andric                             "View information about a register.", nullptr,
3935f757f3fSDimitry Andric                             eCommandRequiresFrame | eCommandRequiresRegContext |
3945f757f3fSDimitry Andric                                 eCommandProcessMustBeLaunched |
3955f757f3fSDimitry Andric                                 eCommandProcessMustBePaused) {
39606c3fb27SDimitry Andric     SetHelpLong(R"(
39706c3fb27SDimitry Andric Name             The name lldb uses for the register, optionally with an alias.
39806c3fb27SDimitry Andric Size             The size of the register in bytes and again in bits.
39906c3fb27SDimitry Andric Invalidates (*)  The registers that would be changed if you wrote this
40006c3fb27SDimitry Andric                  register. For example, writing to a narrower alias of a wider
40106c3fb27SDimitry Andric                  register would change the value of the wider register.
40206c3fb27SDimitry Andric Read from   (*)  The registers that the value of this register is constructed
40306c3fb27SDimitry Andric                  from. For example, a narrower alias of a wider register will be
40406c3fb27SDimitry Andric                  read from the wider register.
40506c3fb27SDimitry Andric In sets     (*)  The register sets that contain this register. For example the
40606c3fb27SDimitry Andric                  PC will be in the "General Purpose Register" set.
40706c3fb27SDimitry Andric Fields      (*)  A table of the names and bit positions of the values contained
40806c3fb27SDimitry Andric                  in this register.
40906c3fb27SDimitry Andric 
41006c3fb27SDimitry Andric Fields marked with (*) may not always be present. Some information may be
41106c3fb27SDimitry Andric different for the same register when connected to different debug servers.)");
41206c3fb27SDimitry Andric 
413*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeRegisterName);
41406c3fb27SDimitry Andric   }
41506c3fb27SDimitry Andric 
41606c3fb27SDimitry Andric   ~CommandObjectRegisterInfo() override = default;
41706c3fb27SDimitry Andric 
41806c3fb27SDimitry Andric   void
41906c3fb27SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
42006c3fb27SDimitry Andric                            OptionElementVector &opt_element_vector) override {
42106c3fb27SDimitry Andric     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
42206c3fb27SDimitry Andric       return;
423*0fca6ea1SDimitry Andric     CommandObject::HandleArgumentCompletion(request, opt_element_vector);
42406c3fb27SDimitry Andric   }
42506c3fb27SDimitry Andric 
42606c3fb27SDimitry Andric protected:
4275f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
42806c3fb27SDimitry Andric     if (command.GetArgumentCount() != 1) {
42906c3fb27SDimitry Andric       result.AppendError("register info takes exactly 1 argument: <reg-name>");
4305f757f3fSDimitry Andric       return;
43106c3fb27SDimitry Andric     }
43206c3fb27SDimitry Andric 
43306c3fb27SDimitry Andric     llvm::StringRef reg_name = command[0].ref();
43406c3fb27SDimitry Andric     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
43506c3fb27SDimitry Andric     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
43606c3fb27SDimitry Andric     if (reg_info) {
43706c3fb27SDimitry Andric       DumpRegisterInfo(
43806c3fb27SDimitry Andric           result.GetOutputStream(), *reg_ctx, *reg_info,
43906c3fb27SDimitry Andric           GetCommandInterpreter().GetDebugger().GetTerminalWidth());
44006c3fb27SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
44106c3fb27SDimitry Andric     } else
44206c3fb27SDimitry Andric       result.AppendErrorWithFormat("No register found with name '%s'.\n",
44306c3fb27SDimitry Andric                                    reg_name.str().c_str());
44406c3fb27SDimitry Andric   }
44506c3fb27SDimitry Andric };
44606c3fb27SDimitry Andric 
4470b57cec5SDimitry Andric // CommandObjectRegister constructor
4480b57cec5SDimitry Andric CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
4490b57cec5SDimitry Andric     : CommandObjectMultiword(interpreter, "register",
4500b57cec5SDimitry Andric                              "Commands to access registers for the current "
4510b57cec5SDimitry Andric                              "thread and stack frame.",
45206c3fb27SDimitry Andric                              "register [read|write|info] ...") {
4530b57cec5SDimitry Andric   LoadSubCommand("read",
4540b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
4550b57cec5SDimitry Andric   LoadSubCommand("write",
4560b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
45706c3fb27SDimitry Andric   LoadSubCommand("info",
45806c3fb27SDimitry Andric                  CommandObjectSP(new CommandObjectRegisterInfo(interpreter)));
4590b57cec5SDimitry Andric }
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric CommandObjectRegister::~CommandObjectRegister() = default;
462