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