1 //===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectRegister.h"
10 #include "lldb/Core/Debugger.h"
11 #include "lldb/Core/DumpRegisterValue.h"
12 #include "lldb/Host/OptionParser.h"
13 #include "lldb/Interpreter/CommandInterpreter.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Interpreter/OptionGroupFormat.h"
16 #include "lldb/Interpreter/OptionValueArray.h"
17 #include "lldb/Interpreter/OptionValueBoolean.h"
18 #include "lldb/Interpreter/OptionValueUInt64.h"
19 #include "lldb/Interpreter/Options.h"
20 #include "lldb/Target/ExecutionContext.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/SectionLoadList.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/Args.h"
26 #include "lldb/Utility/DataExtractor.h"
27 #include "lldb/Utility/RegisterValue.h"
28 #include "lldb/Utility/Scalar.h"
29 #include "llvm/Support/Errno.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 // "register read"
35 #define LLDB_OPTIONS_register_read
36 #include "CommandOptions.inc"
37 
38 class CommandObjectRegisterRead : public CommandObjectParsed {
39 public:
40   CommandObjectRegisterRead(CommandInterpreter &interpreter)
41       : CommandObjectParsed(
42             interpreter, "register read",
43             "Dump the contents of one or more register values from the current "
44             "frame.  If no register is specified, dumps them all.",
45             nullptr,
46             eCommandRequiresFrame | eCommandRequiresRegContext |
47                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
48         m_option_group(), m_format_options(eFormatDefault),
49         m_command_options() {
50     CommandArgumentEntry arg;
51     CommandArgumentData register_arg;
52 
53     // Define the first (and only) variant of this arg.
54     register_arg.arg_type = eArgTypeRegisterName;
55     register_arg.arg_repetition = eArgRepeatStar;
56 
57     // There is only one variant this argument could be; put it into the
58     // argument entry.
59     arg.push_back(register_arg);
60 
61     // Push the data for the first argument into the m_arguments vector.
62     m_arguments.push_back(arg);
63 
64     // Add the "--format"
65     m_option_group.Append(&m_format_options,
66                           OptionGroupFormat::OPTION_GROUP_FORMAT |
67                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
68                           LLDB_OPT_SET_ALL);
69     m_option_group.Append(&m_command_options);
70     m_option_group.Finalize();
71   }
72 
73   ~CommandObjectRegisterRead() override = default;
74 
75   Options *GetOptions() override { return &m_option_group; }
76 
77   bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
78                     RegisterContext *reg_ctx, const RegisterInfo *reg_info) {
79     if (reg_info) {
80       RegisterValue reg_value;
81 
82       if (reg_ctx->ReadRegister(reg_info, reg_value)) {
83         strm.Indent();
84 
85         bool prefix_with_altname = (bool)m_command_options.alternate_name;
86         bool prefix_with_name = !prefix_with_altname;
87         DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name,
88                           prefix_with_altname, m_format_options.GetFormat(), 8);
89         if ((reg_info->encoding == eEncodingUint) ||
90             (reg_info->encoding == eEncodingSint)) {
91           Process *process = exe_ctx.GetProcessPtr();
92           if (process && reg_info->byte_size == process->GetAddressByteSize()) {
93             addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
94             if (reg_addr != LLDB_INVALID_ADDRESS) {
95               Address so_reg_addr;
96               if (exe_ctx.GetTargetRef()
97                       .GetSectionLoadList()
98                       .ResolveLoadAddress(reg_addr, so_reg_addr)) {
99                 strm.PutCString("  ");
100                 so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
101                                  Address::DumpStyleResolvedDescription);
102               }
103             }
104           }
105         }
106         strm.EOL();
107         return true;
108       }
109     }
110     return false;
111   }
112 
113   bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
114                        RegisterContext *reg_ctx, size_t set_idx,
115                        bool primitive_only = false) {
116     uint32_t unavailable_count = 0;
117     uint32_t available_count = 0;
118 
119     if (!reg_ctx)
120       return false; // thread has no registers (i.e. core files are corrupt,
121                     // incomplete crash logs...)
122 
123     const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
124     if (reg_set) {
125       strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
126       strm.IndentMore();
127       const size_t num_registers = reg_set->num_registers;
128       for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
129         const uint32_t reg = reg_set->registers[reg_idx];
130         const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
131         // Skip the dumping of derived register if primitive_only is true.
132         if (primitive_only && reg_info && reg_info->value_regs)
133           continue;
134 
135         if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info))
136           ++available_count;
137         else
138           ++unavailable_count;
139       }
140       strm.IndentLess();
141       if (unavailable_count) {
142         strm.Indent();
143         strm.Printf("%u registers were unavailable.\n", unavailable_count);
144       }
145       strm.EOL();
146     }
147     return available_count > 0;
148   }
149 
150 protected:
151   bool DoExecute(Args &command, CommandReturnObject &result) override {
152     Stream &strm = result.GetOutputStream();
153     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
154 
155     const RegisterInfo *reg_info = nullptr;
156     if (command.GetArgumentCount() == 0) {
157       size_t set_idx;
158 
159       size_t num_register_sets = 1;
160       const size_t set_array_size = m_command_options.set_indexes.GetSize();
161       if (set_array_size > 0) {
162         for (size_t i = 0; i < set_array_size; ++i) {
163           set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX,
164                                                                      nullptr);
165           if (set_idx < reg_ctx->GetRegisterSetCount()) {
166             if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
167               if (errno)
168                 result.AppendErrorWithFormatv("register read failed: {0}\n",
169                                               llvm::sys::StrError());
170               else
171                 result.AppendError("unknown error while reading registers.\n");
172               result.SetStatus(eReturnStatusFailed);
173               break;
174             }
175           } else {
176             result.AppendErrorWithFormat(
177                 "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
178             result.SetStatus(eReturnStatusFailed);
179             break;
180           }
181         }
182       } else {
183         if (m_command_options.dump_all_sets)
184           num_register_sets = reg_ctx->GetRegisterSetCount();
185 
186         for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
187           // When dump_all_sets option is set, dump primitive as well as
188           // derived registers.
189           DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
190                           !m_command_options.dump_all_sets.GetCurrentValue());
191         }
192       }
193     } else {
194       if (m_command_options.dump_all_sets) {
195         result.AppendError("the --all option can't be used when registers "
196                            "names are supplied as arguments\n");
197         result.SetStatus(eReturnStatusFailed);
198       } else if (m_command_options.set_indexes.GetSize() > 0) {
199         result.AppendError("the --set <set> option can't be used when "
200                            "registers names are supplied as arguments\n");
201         result.SetStatus(eReturnStatusFailed);
202       } else {
203         for (auto &entry : command) {
204           // in most LLDB commands we accept $rbx as the name for register RBX
205           // - and here we would reject it and non-existant. we should be more
206           // consistent towards the user and allow them to say reg read $rbx -
207           // internally, however, we should be strict and not allow ourselves
208           // to call our registers $rbx in our own API
209           auto arg_str = entry.ref;
210           arg_str.consume_front("$");
211 
212           reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
213 
214           if (reg_info) {
215             if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info))
216               strm.Printf("%-12s = error: unavailable\n", reg_info->name);
217           } else {
218             result.AppendErrorWithFormat("Invalid register name '%s'.\n",
219                                          arg_str.str().c_str());
220           }
221         }
222       }
223     }
224     return result.Succeeded();
225   }
226 
227   class CommandOptions : public OptionGroup {
228   public:
229     CommandOptions()
230         : OptionGroup(),
231           set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
232           dump_all_sets(false, false), // Initial and default values are false
233           alternate_name(false, false) {}
234 
235     ~CommandOptions() override = default;
236 
237     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
238       return llvm::makeArrayRef(g_register_read_options);
239     }
240 
241     void OptionParsingStarting(ExecutionContext *execution_context) override {
242       set_indexes.Clear();
243       dump_all_sets.Clear();
244       alternate_name.Clear();
245     }
246 
247     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
248                           ExecutionContext *execution_context) override {
249       Status error;
250       const int short_option = GetDefinitions()[option_idx].short_option;
251       switch (short_option) {
252       case 's': {
253         OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
254         if (value_sp)
255           set_indexes.AppendValue(value_sp);
256       } break;
257 
258       case 'a':
259         // When we don't use OptionValue::SetValueFromCString(const char *) to
260         // set an option value, it won't be marked as being set in the options
261         // so we make a call to let users know the value was set via option
262         dump_all_sets.SetCurrentValue(true);
263         dump_all_sets.SetOptionWasSet();
264         break;
265 
266       case 'A':
267         // When we don't use OptionValue::SetValueFromCString(const char *) to
268         // set an option value, it won't be marked as being set in the options
269         // so we make a call to let users know the value was set via option
270         alternate_name.SetCurrentValue(true);
271         dump_all_sets.SetOptionWasSet();
272         break;
273 
274       default:
275         error.SetErrorStringWithFormat("unrecognized short option '%c'",
276                                        short_option);
277         break;
278       }
279       return error;
280     }
281 
282     // Instance variables to hold the values for command options.
283     OptionValueArray set_indexes;
284     OptionValueBoolean dump_all_sets;
285     OptionValueBoolean alternate_name;
286   };
287 
288   OptionGroupOptions m_option_group;
289   OptionGroupFormat m_format_options;
290   CommandOptions m_command_options;
291 };
292 
293 // "register write"
294 class CommandObjectRegisterWrite : public CommandObjectParsed {
295 public:
296   CommandObjectRegisterWrite(CommandInterpreter &interpreter)
297       : CommandObjectParsed(interpreter, "register write",
298                             "Modify a single register value.", nullptr,
299                             eCommandRequiresFrame | eCommandRequiresRegContext |
300                                 eCommandProcessMustBeLaunched |
301                                 eCommandProcessMustBePaused) {
302     CommandArgumentEntry arg1;
303     CommandArgumentEntry arg2;
304     CommandArgumentData register_arg;
305     CommandArgumentData value_arg;
306 
307     // Define the first (and only) variant of this arg.
308     register_arg.arg_type = eArgTypeRegisterName;
309     register_arg.arg_repetition = eArgRepeatPlain;
310 
311     // There is only one variant this argument could be; put it into the
312     // argument entry.
313     arg1.push_back(register_arg);
314 
315     // Define the first (and only) variant of this arg.
316     value_arg.arg_type = eArgTypeValue;
317     value_arg.arg_repetition = eArgRepeatPlain;
318 
319     // There is only one variant this argument could be; put it into the
320     // argument entry.
321     arg2.push_back(value_arg);
322 
323     // Push the data for the first argument into the m_arguments vector.
324     m_arguments.push_back(arg1);
325     m_arguments.push_back(arg2);
326   }
327 
328   ~CommandObjectRegisterWrite() override = default;
329 
330 protected:
331   bool DoExecute(Args &command, CommandReturnObject &result) override {
332     DataExtractor reg_data;
333     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
334 
335     if (command.GetArgumentCount() != 2) {
336       result.AppendError(
337           "register write takes exactly 2 arguments: <reg-name> <value>");
338       result.SetStatus(eReturnStatusFailed);
339     } else {
340       auto reg_name = command[0].ref;
341       auto value_str = command[1].ref;
342 
343       // in most LLDB commands we accept $rbx as the name for register RBX -
344       // and here we would reject it and non-existant. we should be more
345       // consistent towards the user and allow them to say reg write $rbx -
346       // internally, however, we should be strict and not allow ourselves to
347       // call our registers $rbx in our own API
348       reg_name.consume_front("$");
349 
350       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
351 
352       if (reg_info) {
353         RegisterValue reg_value;
354 
355         Status error(reg_value.SetValueFromString(reg_info, value_str));
356         if (error.Success()) {
357           if (reg_ctx->WriteRegister(reg_info, reg_value)) {
358             // Toss all frames and anything else in the thread after a register
359             // has been written.
360             m_exe_ctx.GetThreadRef().Flush();
361             result.SetStatus(eReturnStatusSuccessFinishNoResult);
362             return true;
363           }
364         }
365         if (error.AsCString()) {
366           result.AppendErrorWithFormat(
367               "Failed to write register '%s' with value '%s': %s\n",
368               reg_name.str().c_str(), value_str.str().c_str(),
369               error.AsCString());
370         } else {
371           result.AppendErrorWithFormat(
372               "Failed to write register '%s' with value '%s'",
373               reg_name.str().c_str(), value_str.str().c_str());
374         }
375         result.SetStatus(eReturnStatusFailed);
376       } else {
377         result.AppendErrorWithFormat("Register not found for '%s'.\n",
378                                      reg_name.str().c_str());
379         result.SetStatus(eReturnStatusFailed);
380       }
381     }
382     return result.Succeeded();
383   }
384 };
385 
386 // CommandObjectRegister constructor
387 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
388     : CommandObjectMultiword(interpreter, "register",
389                              "Commands to access registers for the current "
390                              "thread and stack frame.",
391                              "register [read|write] ...") {
392   LoadSubCommand("read",
393                  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
394   LoadSubCommand("write",
395                  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
396 }
397 
398 CommandObjectRegister::~CommandObjectRegister() = default;
399