xref: /llvm-project/lldb/source/Commands/CommandObjectRegister.cpp (revision 0d9a201e2624998922f825ebbe01aae0cce4bbd5)
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         llvm_unreachable("Unimplemented option");
276       }
277       return error;
278     }
279 
280     // Instance variables to hold the values for command options.
281     OptionValueArray set_indexes;
282     OptionValueBoolean dump_all_sets;
283     OptionValueBoolean alternate_name;
284   };
285 
286   OptionGroupOptions m_option_group;
287   OptionGroupFormat m_format_options;
288   CommandOptions m_command_options;
289 };
290 
291 // "register write"
292 class CommandObjectRegisterWrite : public CommandObjectParsed {
293 public:
294   CommandObjectRegisterWrite(CommandInterpreter &interpreter)
295       : CommandObjectParsed(interpreter, "register write",
296                             "Modify a single register value.", nullptr,
297                             eCommandRequiresFrame | eCommandRequiresRegContext |
298                                 eCommandProcessMustBeLaunched |
299                                 eCommandProcessMustBePaused) {
300     CommandArgumentEntry arg1;
301     CommandArgumentEntry arg2;
302     CommandArgumentData register_arg;
303     CommandArgumentData value_arg;
304 
305     // Define the first (and only) variant of this arg.
306     register_arg.arg_type = eArgTypeRegisterName;
307     register_arg.arg_repetition = eArgRepeatPlain;
308 
309     // There is only one variant this argument could be; put it into the
310     // argument entry.
311     arg1.push_back(register_arg);
312 
313     // Define the first (and only) variant of this arg.
314     value_arg.arg_type = eArgTypeValue;
315     value_arg.arg_repetition = eArgRepeatPlain;
316 
317     // There is only one variant this argument could be; put it into the
318     // argument entry.
319     arg2.push_back(value_arg);
320 
321     // Push the data for the first argument into the m_arguments vector.
322     m_arguments.push_back(arg1);
323     m_arguments.push_back(arg2);
324   }
325 
326   ~CommandObjectRegisterWrite() override = default;
327 
328 protected:
329   bool DoExecute(Args &command, CommandReturnObject &result) override {
330     DataExtractor reg_data;
331     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
332 
333     if (command.GetArgumentCount() != 2) {
334       result.AppendError(
335           "register write takes exactly 2 arguments: <reg-name> <value>");
336       result.SetStatus(eReturnStatusFailed);
337     } else {
338       auto reg_name = command[0].ref();
339       auto value_str = command[1].ref();
340 
341       // in most LLDB commands we accept $rbx as the name for register RBX -
342       // and here we would reject it and non-existant. we should be more
343       // consistent towards the user and allow them to say reg write $rbx -
344       // internally, however, we should be strict and not allow ourselves to
345       // call our registers $rbx in our own API
346       reg_name.consume_front("$");
347 
348       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
349 
350       if (reg_info) {
351         RegisterValue reg_value;
352 
353         Status error(reg_value.SetValueFromString(reg_info, value_str));
354         if (error.Success()) {
355           if (reg_ctx->WriteRegister(reg_info, reg_value)) {
356             // Toss all frames and anything else in the thread after a register
357             // has been written.
358             m_exe_ctx.GetThreadRef().Flush();
359             result.SetStatus(eReturnStatusSuccessFinishNoResult);
360             return true;
361           }
362         }
363         if (error.AsCString()) {
364           result.AppendErrorWithFormat(
365               "Failed to write register '%s' with value '%s': %s\n",
366               reg_name.str().c_str(), value_str.str().c_str(),
367               error.AsCString());
368         } else {
369           result.AppendErrorWithFormat(
370               "Failed to write register '%s' with value '%s'",
371               reg_name.str().c_str(), value_str.str().c_str());
372         }
373         result.SetStatus(eReturnStatusFailed);
374       } else {
375         result.AppendErrorWithFormat("Register not found for '%s'.\n",
376                                      reg_name.str().c_str());
377         result.SetStatus(eReturnStatusFailed);
378       }
379     }
380     return result.Succeeded();
381   }
382 };
383 
384 // CommandObjectRegister constructor
385 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
386     : CommandObjectMultiword(interpreter, "register",
387                              "Commands to access registers for the current "
388                              "thread and stack frame.",
389                              "register [read|write] ...") {
390   LoadSubCommand("read",
391                  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
392   LoadSubCommand("write",
393                  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
394 }
395 
396 CommandObjectRegister::~CommandObjectRegister() = default;
397