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 &reg_ctx, const RegisterInfo &reg_info,
92fe013be4SDimitry Andric                     bool print_flags) {
930b57cec5SDimitry Andric     RegisterValue reg_value;
94fe013be4SDimitry Andric     if (!reg_ctx.ReadRegister(&reg_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