1ac7ddfbfSEd Maste //===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
104bb0738eSEd Maste #include "CommandObjectRegister.h"
11435933ddSDimitry Andric #include "lldb/Core/Debugger.h"
124ba319b5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
13f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h"
14ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
15ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
16ac7ddfbfSEd Maste #include "lldb/Interpreter/OptionGroupFormat.h"
17ac7ddfbfSEd Maste #include "lldb/Interpreter/OptionValueArray.h"
181c3bbb01SEd Maste #include "lldb/Interpreter/OptionValueBoolean.h"
19ac7ddfbfSEd Maste #include "lldb/Interpreter/OptionValueUInt64.h"
20435933ddSDimitry Andric #include "lldb/Interpreter/Options.h"
21ac7ddfbfSEd Maste #include "lldb/Target/ExecutionContext.h"
22ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
23ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h"
2412b93ac6SEd Maste #include "lldb/Target/SectionLoadList.h"
25ac7ddfbfSEd Maste #include "lldb/Target/Thread.h"
264ba319b5SDimitry Andric #include "lldb/Utility/Args.h"
27f678e45dSDimitry Andric #include "lldb/Utility/DataExtractor.h"
28*b5893f02SDimitry Andric #include "lldb/Utility/RegisterValue.h"
29*b5893f02SDimitry Andric #include "lldb/Utility/Scalar.h"
30db17bf38SDimitry Andric #include "llvm/Support/Errno.h"
31ac7ddfbfSEd Maste 
32ac7ddfbfSEd Maste using namespace lldb;
33ac7ddfbfSEd Maste using namespace lldb_private;
34ac7ddfbfSEd Maste 
35ac7ddfbfSEd Maste //----------------------------------------------------------------------
36ac7ddfbfSEd Maste // "register read"
37ac7ddfbfSEd Maste //----------------------------------------------------------------------
38435933ddSDimitry Andric 
39*b5893f02SDimitry Andric static constexpr OptionDefinition g_register_read_options[] = {
40435933ddSDimitry Andric     // clang-format off
41*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "alternate", 'A', OptionParser::eNoArgument,       nullptr, {}, 0, eArgTypeNone,  "Display register names using the alternate register name if there is one." },
42*b5893f02SDimitry Andric   { LLDB_OPT_SET_1,   false, "set",       's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeIndex, "Specify which register sets to dump by index." },
43*b5893f02SDimitry Andric   { LLDB_OPT_SET_2,   false, "all",       'a', OptionParser::eNoArgument,       nullptr, {}, 0, eArgTypeNone,  "Show all register sets." },
44435933ddSDimitry Andric     // clang-format on
45435933ddSDimitry Andric };
46435933ddSDimitry Andric 
47435933ddSDimitry Andric class CommandObjectRegisterRead : public CommandObjectParsed {
48ac7ddfbfSEd Maste public:
CommandObjectRegisterRead(CommandInterpreter & interpreter)49435933ddSDimitry Andric   CommandObjectRegisterRead(CommandInterpreter &interpreter)
50435933ddSDimitry Andric       : CommandObjectParsed(
51435933ddSDimitry Andric             interpreter, "register read",
52435933ddSDimitry Andric             "Dump the contents of one or more register values from the current "
53435933ddSDimitry Andric             "frame.  If no register is specified, dumps them all.",
544bb0738eSEd Maste             nullptr,
55435933ddSDimitry Andric             eCommandRequiresFrame | eCommandRequiresRegContext |
56435933ddSDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
57435933ddSDimitry Andric         m_option_group(), m_format_options(eFormatDefault),
58435933ddSDimitry Andric         m_command_options() {
59ac7ddfbfSEd Maste     CommandArgumentEntry arg;
60ac7ddfbfSEd Maste     CommandArgumentData register_arg;
61ac7ddfbfSEd Maste 
62ac7ddfbfSEd Maste     // Define the first (and only) variant of this arg.
63ac7ddfbfSEd Maste     register_arg.arg_type = eArgTypeRegisterName;
64ac7ddfbfSEd Maste     register_arg.arg_repetition = eArgRepeatStar;
65ac7ddfbfSEd Maste 
66435933ddSDimitry Andric     // There is only one variant this argument could be; put it into the
67435933ddSDimitry Andric     // argument entry.
68ac7ddfbfSEd Maste     arg.push_back(register_arg);
69ac7ddfbfSEd Maste 
70ac7ddfbfSEd Maste     // Push the data for the first argument into the m_arguments vector.
71ac7ddfbfSEd Maste     m_arguments.push_back(arg);
72ac7ddfbfSEd Maste 
73ac7ddfbfSEd Maste     // Add the "--format"
74435933ddSDimitry Andric     m_option_group.Append(&m_format_options,
75435933ddSDimitry Andric                           OptionGroupFormat::OPTION_GROUP_FORMAT |
76435933ddSDimitry Andric                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
77435933ddSDimitry Andric                           LLDB_OPT_SET_ALL);
78ac7ddfbfSEd Maste     m_option_group.Append(&m_command_options);
79ac7ddfbfSEd Maste     m_option_group.Finalize();
80ac7ddfbfSEd Maste   }
81ac7ddfbfSEd Maste 
824bb0738eSEd Maste   ~CommandObjectRegisterRead() override = default;
83ac7ddfbfSEd Maste 
GetOptions()84435933ddSDimitry Andric   Options *GetOptions() override { return &m_option_group; }
85ac7ddfbfSEd Maste 
DumpRegister(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext * reg_ctx,const RegisterInfo * reg_info)86435933ddSDimitry Andric   bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
87435933ddSDimitry Andric                     RegisterContext *reg_ctx, const RegisterInfo *reg_info) {
88435933ddSDimitry Andric     if (reg_info) {
89ac7ddfbfSEd Maste       RegisterValue reg_value;
90ac7ddfbfSEd Maste 
91435933ddSDimitry Andric       if (reg_ctx->ReadRegister(reg_info, reg_value)) {
92ac7ddfbfSEd Maste         strm.Indent();
93ac7ddfbfSEd Maste 
9435617911SEd Maste         bool prefix_with_altname = (bool)m_command_options.alternate_name;
95ac7ddfbfSEd Maste         bool prefix_with_name = !prefix_with_altname;
964ba319b5SDimitry Andric         DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name,
974ba319b5SDimitry Andric                           prefix_with_altname, m_format_options.GetFormat(), 8);
98435933ddSDimitry Andric         if ((reg_info->encoding == eEncodingUint) ||
99435933ddSDimitry Andric             (reg_info->encoding == eEncodingSint)) {
100ac7ddfbfSEd Maste           Process *process = exe_ctx.GetProcessPtr();
101435933ddSDimitry Andric           if (process && reg_info->byte_size == process->GetAddressByteSize()) {
102ac7ddfbfSEd Maste             addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
103435933ddSDimitry Andric             if (reg_addr != LLDB_INVALID_ADDRESS) {
104ac7ddfbfSEd Maste               Address so_reg_addr;
105435933ddSDimitry Andric               if (exe_ctx.GetTargetRef()
106435933ddSDimitry Andric                       .GetSectionLoadList()
107435933ddSDimitry Andric                       .ResolveLoadAddress(reg_addr, so_reg_addr)) {
108ac7ddfbfSEd Maste                 strm.PutCString("  ");
109435933ddSDimitry Andric                 so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
110435933ddSDimitry Andric                                  Address::DumpStyleResolvedDescription);
111ac7ddfbfSEd Maste               }
112ac7ddfbfSEd Maste             }
113ac7ddfbfSEd Maste           }
114ac7ddfbfSEd Maste         }
115ac7ddfbfSEd Maste         strm.EOL();
116ac7ddfbfSEd Maste         return true;
117ac7ddfbfSEd Maste       }
118ac7ddfbfSEd Maste     }
119ac7ddfbfSEd Maste     return false;
120ac7ddfbfSEd Maste   }
121ac7ddfbfSEd Maste 
DumpRegisterSet(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext * reg_ctx,size_t set_idx,bool primitive_only=false)122435933ddSDimitry Andric   bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
123435933ddSDimitry Andric                        RegisterContext *reg_ctx, size_t set_idx,
124435933ddSDimitry Andric                        bool primitive_only = false) {
125ac7ddfbfSEd Maste     uint32_t unavailable_count = 0;
126ac7ddfbfSEd Maste     uint32_t available_count = 0;
127ac7ddfbfSEd Maste 
128ac7ddfbfSEd Maste     if (!reg_ctx)
129435933ddSDimitry Andric       return false; // thread has no registers (i.e. core files are corrupt,
130435933ddSDimitry Andric                     // incomplete crash logs...)
131ac7ddfbfSEd Maste 
132ac7ddfbfSEd Maste     const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
133435933ddSDimitry Andric     if (reg_set) {
1341c3bbb01SEd Maste       strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
135ac7ddfbfSEd Maste       strm.IndentMore();
136ac7ddfbfSEd Maste       const size_t num_registers = reg_set->num_registers;
137435933ddSDimitry Andric       for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
138ac7ddfbfSEd Maste         const uint32_t reg = reg_set->registers[reg_idx];
139ac7ddfbfSEd Maste         const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
140ac7ddfbfSEd Maste         // Skip the dumping of derived register if primitive_only is true.
141ac7ddfbfSEd Maste         if (primitive_only && reg_info && reg_info->value_regs)
142ac7ddfbfSEd Maste           continue;
143ac7ddfbfSEd Maste 
144ac7ddfbfSEd Maste         if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info))
145ac7ddfbfSEd Maste           ++available_count;
146ac7ddfbfSEd Maste         else
147ac7ddfbfSEd Maste           ++unavailable_count;
148ac7ddfbfSEd Maste       }
149ac7ddfbfSEd Maste       strm.IndentLess();
150435933ddSDimitry Andric       if (unavailable_count) {
151ac7ddfbfSEd Maste         strm.Indent();
152ac7ddfbfSEd Maste         strm.Printf("%u registers were unavailable.\n", unavailable_count);
153ac7ddfbfSEd Maste       }
154ac7ddfbfSEd Maste       strm.EOL();
155ac7ddfbfSEd Maste     }
156ac7ddfbfSEd Maste     return available_count > 0;
157ac7ddfbfSEd Maste   }
158ac7ddfbfSEd Maste 
159ac7ddfbfSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)160435933ddSDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
161ac7ddfbfSEd Maste     Stream &strm = result.GetOutputStream();
162ac7ddfbfSEd Maste     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
163ac7ddfbfSEd Maste 
1644bb0738eSEd Maste     const RegisterInfo *reg_info = nullptr;
165435933ddSDimitry Andric     if (command.GetArgumentCount() == 0) {
166ac7ddfbfSEd Maste       size_t set_idx;
167ac7ddfbfSEd Maste 
168ac7ddfbfSEd Maste       size_t num_register_sets = 1;
169ac7ddfbfSEd Maste       const size_t set_array_size = m_command_options.set_indexes.GetSize();
170435933ddSDimitry Andric       if (set_array_size > 0) {
171435933ddSDimitry Andric         for (size_t i = 0; i < set_array_size; ++i) {
172435933ddSDimitry Andric           set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX,
173435933ddSDimitry Andric                                                                      nullptr);
174435933ddSDimitry Andric           if (set_idx < reg_ctx->GetRegisterSetCount()) {
175435933ddSDimitry Andric             if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
176ac7ddfbfSEd Maste               if (errno)
177db17bf38SDimitry Andric                 result.AppendErrorWithFormatv("register read failed: {0}\n",
178db17bf38SDimitry Andric                                               llvm::sys::StrError());
179ac7ddfbfSEd Maste               else
180ac7ddfbfSEd Maste                 result.AppendError("unknown error while reading registers.\n");
181ac7ddfbfSEd Maste               result.SetStatus(eReturnStatusFailed);
182ac7ddfbfSEd Maste               break;
183ac7ddfbfSEd Maste             }
184435933ddSDimitry Andric           } else {
185435933ddSDimitry Andric             result.AppendErrorWithFormat(
186435933ddSDimitry Andric                 "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
187ac7ddfbfSEd Maste             result.SetStatus(eReturnStatusFailed);
188ac7ddfbfSEd Maste             break;
189ac7ddfbfSEd Maste           }
190ac7ddfbfSEd Maste         }
191435933ddSDimitry Andric       } else {
192ac7ddfbfSEd Maste         if (m_command_options.dump_all_sets)
193ac7ddfbfSEd Maste           num_register_sets = reg_ctx->GetRegisterSetCount();
194ac7ddfbfSEd Maste 
195435933ddSDimitry Andric         for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
1964ba319b5SDimitry Andric           // When dump_all_sets option is set, dump primitive as well as
1974ba319b5SDimitry Andric           // derived registers.
198435933ddSDimitry Andric           DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
199435933ddSDimitry Andric                           !m_command_options.dump_all_sets.GetCurrentValue());
200ac7ddfbfSEd Maste         }
201ac7ddfbfSEd Maste       }
202435933ddSDimitry Andric     } else {
203435933ddSDimitry Andric       if (m_command_options.dump_all_sets) {
204435933ddSDimitry Andric         result.AppendError("the --all option can't be used when registers "
205435933ddSDimitry Andric                            "names are supplied as arguments\n");
206ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
207435933ddSDimitry Andric       } else if (m_command_options.set_indexes.GetSize() > 0) {
208435933ddSDimitry Andric         result.AppendError("the --set <set> option can't be used when "
209435933ddSDimitry Andric                            "registers names are supplied as arguments\n");
210ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
211435933ddSDimitry Andric       } else {
212435933ddSDimitry Andric         for (auto &entry : command) {
2134ba319b5SDimitry Andric           // in most LLDB commands we accept $rbx as the name for register RBX
2144ba319b5SDimitry Andric           // - and here we would reject it and non-existant. we should be more
215435933ddSDimitry Andric           // consistent towards the user and allow them to say reg read $rbx -
216435933ddSDimitry Andric           // internally, however, we should be strict and not allow ourselves
217ac7ddfbfSEd Maste           // to call our registers $rbx in our own API
218435933ddSDimitry Andric           auto arg_str = entry.ref;
219435933ddSDimitry Andric           arg_str.consume_front("$");
220ac7ddfbfSEd Maste 
221435933ddSDimitry Andric           reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
222435933ddSDimitry Andric 
223435933ddSDimitry Andric           if (reg_info) {
224ac7ddfbfSEd Maste             if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info))
225ac7ddfbfSEd Maste               strm.Printf("%-12s = error: unavailable\n", reg_info->name);
226435933ddSDimitry Andric           } else {
227435933ddSDimitry Andric             result.AppendErrorWithFormat("Invalid register name '%s'.\n",
228435933ddSDimitry Andric                                          arg_str.str().c_str());
229ac7ddfbfSEd Maste           }
230ac7ddfbfSEd Maste         }
231ac7ddfbfSEd Maste       }
232ac7ddfbfSEd Maste     }
233ac7ddfbfSEd Maste     return result.Succeeded();
234ac7ddfbfSEd Maste   }
235ac7ddfbfSEd Maste 
236435933ddSDimitry Andric   class CommandOptions : public OptionGroup {
237ac7ddfbfSEd Maste   public:
CommandOptions()238435933ddSDimitry Andric     CommandOptions()
239435933ddSDimitry Andric         : OptionGroup(),
240ac7ddfbfSEd Maste           set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
241ac7ddfbfSEd Maste           dump_all_sets(false, false), // Initial and default values are false
242435933ddSDimitry Andric           alternate_name(false, false) {}
243ac7ddfbfSEd Maste 
2444bb0738eSEd Maste     ~CommandOptions() override = default;
245ac7ddfbfSEd Maste 
GetDefinitions()246435933ddSDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
247435933ddSDimitry Andric       return llvm::makeArrayRef(g_register_read_options);
248ac7ddfbfSEd Maste     }
249ac7ddfbfSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)250435933ddSDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
251ac7ddfbfSEd Maste       set_indexes.Clear();
252ac7ddfbfSEd Maste       dump_all_sets.Clear();
253ac7ddfbfSEd Maste       alternate_name.Clear();
254ac7ddfbfSEd Maste     }
255ac7ddfbfSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)2565517e702SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
257435933ddSDimitry Andric                           ExecutionContext *execution_context) override {
2585517e702SDimitry Andric       Status error;
259435933ddSDimitry Andric       const int short_option = GetDefinitions()[option_idx].short_option;
260435933ddSDimitry Andric       switch (short_option) {
261435933ddSDimitry Andric       case 's': {
262ac7ddfbfSEd Maste         OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
263ac7ddfbfSEd Maste         if (value_sp)
264ac7ddfbfSEd Maste           set_indexes.AppendValue(value_sp);
265435933ddSDimitry Andric       } break;
266ac7ddfbfSEd Maste 
267ac7ddfbfSEd Maste       case 'a':
268ac7ddfbfSEd Maste         // When we don't use OptionValue::SetValueFromCString(const char *) to
269ac7ddfbfSEd Maste         // set an option value, it won't be marked as being set in the options
270ac7ddfbfSEd Maste         // so we make a call to let users know the value was set via option
271ac7ddfbfSEd Maste         dump_all_sets.SetCurrentValue(true);
272ac7ddfbfSEd Maste         dump_all_sets.SetOptionWasSet();
273ac7ddfbfSEd Maste         break;
274ac7ddfbfSEd Maste 
275ac7ddfbfSEd Maste       case 'A':
276ac7ddfbfSEd Maste         // When we don't use OptionValue::SetValueFromCString(const char *) to
277ac7ddfbfSEd Maste         // set an option value, it won't be marked as being set in the options
278ac7ddfbfSEd Maste         // so we make a call to let users know the value was set via option
279ac7ddfbfSEd Maste         alternate_name.SetCurrentValue(true);
280ac7ddfbfSEd Maste         dump_all_sets.SetOptionWasSet();
281ac7ddfbfSEd Maste         break;
282ac7ddfbfSEd Maste 
283ac7ddfbfSEd Maste       default:
284435933ddSDimitry Andric         error.SetErrorStringWithFormat("unrecognized short option '%c'",
285435933ddSDimitry Andric                                        short_option);
286ac7ddfbfSEd Maste         break;
287ac7ddfbfSEd Maste       }
288ac7ddfbfSEd Maste       return error;
289ac7ddfbfSEd Maste     }
290ac7ddfbfSEd Maste 
291ac7ddfbfSEd Maste     // Instance variables to hold the values for command options.
292ac7ddfbfSEd Maste     OptionValueArray set_indexes;
293ac7ddfbfSEd Maste     OptionValueBoolean dump_all_sets;
294ac7ddfbfSEd Maste     OptionValueBoolean alternate_name;
295ac7ddfbfSEd Maste   };
296ac7ddfbfSEd Maste 
297ac7ddfbfSEd Maste   OptionGroupOptions m_option_group;
298ac7ddfbfSEd Maste   OptionGroupFormat m_format_options;
299ac7ddfbfSEd Maste   CommandOptions m_command_options;
300ac7ddfbfSEd Maste };
301ac7ddfbfSEd Maste 
302ac7ddfbfSEd Maste //----------------------------------------------------------------------
303ac7ddfbfSEd Maste // "register write"
304ac7ddfbfSEd Maste //----------------------------------------------------------------------
305435933ddSDimitry Andric class CommandObjectRegisterWrite : public CommandObjectParsed {
306ac7ddfbfSEd Maste public:
CommandObjectRegisterWrite(CommandInterpreter & interpreter)307435933ddSDimitry Andric   CommandObjectRegisterWrite(CommandInterpreter &interpreter)
308435933ddSDimitry Andric       : CommandObjectParsed(interpreter, "register write",
309435933ddSDimitry Andric                             "Modify a single register value.", nullptr,
310435933ddSDimitry Andric                             eCommandRequiresFrame | eCommandRequiresRegContext |
3111c3bbb01SEd Maste                                 eCommandProcessMustBeLaunched |
312435933ddSDimitry Andric                                 eCommandProcessMustBePaused) {
313ac7ddfbfSEd Maste     CommandArgumentEntry arg1;
314ac7ddfbfSEd Maste     CommandArgumentEntry arg2;
315ac7ddfbfSEd Maste     CommandArgumentData register_arg;
316ac7ddfbfSEd Maste     CommandArgumentData value_arg;
317ac7ddfbfSEd Maste 
318ac7ddfbfSEd Maste     // Define the first (and only) variant of this arg.
319ac7ddfbfSEd Maste     register_arg.arg_type = eArgTypeRegisterName;
320ac7ddfbfSEd Maste     register_arg.arg_repetition = eArgRepeatPlain;
321ac7ddfbfSEd Maste 
322435933ddSDimitry Andric     // There is only one variant this argument could be; put it into the
323435933ddSDimitry Andric     // argument entry.
324ac7ddfbfSEd Maste     arg1.push_back(register_arg);
325ac7ddfbfSEd Maste 
326ac7ddfbfSEd Maste     // Define the first (and only) variant of this arg.
327ac7ddfbfSEd Maste     value_arg.arg_type = eArgTypeValue;
328ac7ddfbfSEd Maste     value_arg.arg_repetition = eArgRepeatPlain;
329ac7ddfbfSEd Maste 
330435933ddSDimitry Andric     // There is only one variant this argument could be; put it into the
331435933ddSDimitry Andric     // argument entry.
332ac7ddfbfSEd Maste     arg2.push_back(value_arg);
333ac7ddfbfSEd Maste 
334ac7ddfbfSEd Maste     // Push the data for the first argument into the m_arguments vector.
335ac7ddfbfSEd Maste     m_arguments.push_back(arg1);
336ac7ddfbfSEd Maste     m_arguments.push_back(arg2);
337ac7ddfbfSEd Maste   }
338ac7ddfbfSEd Maste 
3394bb0738eSEd Maste   ~CommandObjectRegisterWrite() override = default;
340ac7ddfbfSEd Maste 
341ac7ddfbfSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)342435933ddSDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
343ac7ddfbfSEd Maste     DataExtractor reg_data;
344ac7ddfbfSEd Maste     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
345ac7ddfbfSEd Maste 
346435933ddSDimitry Andric     if (command.GetArgumentCount() != 2) {
347435933ddSDimitry Andric       result.AppendError(
348435933ddSDimitry Andric           "register write takes exactly 2 arguments: <reg-name> <value>");
349ac7ddfbfSEd Maste       result.SetStatus(eReturnStatusFailed);
350435933ddSDimitry Andric     } else {
351435933ddSDimitry Andric       auto reg_name = command[0].ref;
352435933ddSDimitry Andric       auto value_str = command[1].ref;
353ac7ddfbfSEd Maste 
3544ba319b5SDimitry Andric       // in most LLDB commands we accept $rbx as the name for register RBX -
3554ba319b5SDimitry Andric       // and here we would reject it and non-existant. we should be more
3564ba319b5SDimitry Andric       // consistent towards the user and allow them to say reg write $rbx -
3574ba319b5SDimitry Andric       // internally, however, we should be strict and not allow ourselves to
3584ba319b5SDimitry Andric       // call our registers $rbx in our own API
359435933ddSDimitry Andric       reg_name.consume_front("$");
360ac7ddfbfSEd Maste 
361ac7ddfbfSEd Maste       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
362ac7ddfbfSEd Maste 
363435933ddSDimitry Andric       if (reg_info) {
364ac7ddfbfSEd Maste         RegisterValue reg_value;
365ac7ddfbfSEd Maste 
3665517e702SDimitry Andric         Status error(reg_value.SetValueFromString(reg_info, value_str));
367435933ddSDimitry Andric         if (error.Success()) {
368435933ddSDimitry Andric           if (reg_ctx->WriteRegister(reg_info, reg_value)) {
3694ba319b5SDimitry Andric             // Toss all frames and anything else in the thread after a register
3704ba319b5SDimitry Andric             // has been written.
371ac7ddfbfSEd Maste             m_exe_ctx.GetThreadRef().Flush();
372ac7ddfbfSEd Maste             result.SetStatus(eReturnStatusSuccessFinishNoResult);
373ac7ddfbfSEd Maste             return true;
374ac7ddfbfSEd Maste           }
375ac7ddfbfSEd Maste         }
376435933ddSDimitry Andric         if (error.AsCString()) {
377435933ddSDimitry Andric           result.AppendErrorWithFormat(
378435933ddSDimitry Andric               "Failed to write register '%s' with value '%s': %s\n",
379435933ddSDimitry Andric               reg_name.str().c_str(), value_str.str().c_str(),
380ac7ddfbfSEd Maste               error.AsCString());
381435933ddSDimitry Andric         } else {
382435933ddSDimitry Andric           result.AppendErrorWithFormat(
383435933ddSDimitry Andric               "Failed to write register '%s' with value '%s'",
384435933ddSDimitry Andric               reg_name.str().c_str(), value_str.str().c_str());
385ac7ddfbfSEd Maste         }
386ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
387435933ddSDimitry Andric       } else {
388435933ddSDimitry Andric         result.AppendErrorWithFormat("Register not found for '%s'.\n",
389435933ddSDimitry Andric                                      reg_name.str().c_str());
390ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
391ac7ddfbfSEd Maste       }
392ac7ddfbfSEd Maste     }
393ac7ddfbfSEd Maste     return result.Succeeded();
394ac7ddfbfSEd Maste   }
395ac7ddfbfSEd Maste };
396ac7ddfbfSEd Maste 
397ac7ddfbfSEd Maste //----------------------------------------------------------------------
398ac7ddfbfSEd Maste // CommandObjectRegister constructor
399ac7ddfbfSEd Maste //----------------------------------------------------------------------
CommandObjectRegister(CommandInterpreter & interpreter)4004bb0738eSEd Maste CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
4014bb0738eSEd Maste     : CommandObjectMultiword(interpreter, "register",
402435933ddSDimitry Andric                              "Commands to access registers for the current "
403435933ddSDimitry Andric                              "thread and stack frame.",
404435933ddSDimitry Andric                              "register [read|write] ...") {
405435933ddSDimitry Andric   LoadSubCommand("read",
406435933ddSDimitry Andric                  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
407435933ddSDimitry Andric   LoadSubCommand("write",
408435933ddSDimitry Andric                  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
409ac7ddfbfSEd Maste }
410ac7ddfbfSEd Maste 
4114bb0738eSEd Maste CommandObjectRegister::~CommandObjectRegister() = default;
412