xref: /llvm-project/lldb/source/Commands/CommandObjectRegister.cpp (revision c4fb7180cbbe977f1ab1ce945a691550f8fdd1fb)
1 //===-- CommandObjectRegister.cpp -----------------------------------------===//
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/DumpRegisterInfo.h"
12 #include "lldb/Core/DumpRegisterValue.h"
13 #include "lldb/Host/OptionParser.h"
14 #include "lldb/Interpreter/CommandInterpreter.h"
15 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionGroupFormat.h"
18 #include "lldb/Interpreter/OptionValueArray.h"
19 #include "lldb/Interpreter/OptionValueBoolean.h"
20 #include "lldb/Interpreter/OptionValueUInt64.h"
21 #include "lldb/Interpreter/Options.h"
22 #include "lldb/Target/ExecutionContext.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/SectionLoadList.h"
26 #include "lldb/Target/Thread.h"
27 #include "lldb/Utility/Args.h"
28 #include "lldb/Utility/DataExtractor.h"
29 #include "lldb/Utility/RegisterValue.h"
30 #include "llvm/Support/Errno.h"
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 // "register read"
36 #define LLDB_OPTIONS_register_read
37 #include "CommandOptions.inc"
38 
39 class CommandObjectRegisterRead : public CommandObjectParsed {
40 public:
41   CommandObjectRegisterRead(CommandInterpreter &interpreter)
42       : CommandObjectParsed(
43             interpreter, "register read",
44             "Dump the contents of one or more register values from the current "
45             "frame.  If no register is specified, dumps them all.",
46             nullptr,
47             eCommandRequiresFrame | eCommandRequiresRegContext |
48                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
49         m_format_options(eFormatDefault, UINT64_MAX, UINT64_MAX,
50                          {{CommandArgumentType::eArgTypeFormat,
51                            "Specify a format to be used for display. If this "
52                            "is set, register fields will not be displayed."}}) {
53     AddSimpleArgumentList(eArgTypeRegisterName, eArgRepeatStar);
54 
55     // Add the "--format"
56     m_option_group.Append(&m_format_options,
57                           OptionGroupFormat::OPTION_GROUP_FORMAT |
58                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
59                           LLDB_OPT_SET_ALL);
60     m_option_group.Append(&m_command_options);
61     m_option_group.Finalize();
62   }
63 
64   ~CommandObjectRegisterRead() override = default;
65 
66   void
67   HandleArgumentCompletion(CompletionRequest &request,
68                            OptionElementVector &opt_element_vector) override {
69     if (!m_exe_ctx.HasProcessScope())
70       return;
71     CommandObject::HandleArgumentCompletion(request, opt_element_vector);
72   }
73 
74   Options *GetOptions() override { return &m_option_group; }
75 
76   bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
77                     RegisterContext &reg_ctx, const RegisterInfo &reg_info,
78                     bool print_flags) {
79     RegisterValue reg_value;
80     if (!reg_ctx.ReadRegister(&reg_info, reg_value))
81       return false;
82 
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                       exe_ctx.GetBestExecutionContextScope(), print_flags,
90                       exe_ctx.GetTargetSP());
91     if ((reg_info.encoding == eEncodingUint) ||
92         (reg_info.encoding == eEncodingSint)) {
93       Process *process = exe_ctx.GetProcessPtr();
94       if (process && reg_info.byte_size == process->GetAddressByteSize()) {
95         addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
96         if (reg_addr != LLDB_INVALID_ADDRESS) {
97           Address so_reg_addr;
98           if (exe_ctx.GetTargetRef().ResolveLoadAddress(reg_addr,
99                                                         so_reg_addr)) {
100             strm.PutCString("  ");
101             so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
102                              Address::DumpStyleResolvedDescription);
103           }
104         }
105       }
106     }
107     strm.EOL();
108     return true;
109   }
110 
111   bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
112                        RegisterContext *reg_ctx, size_t set_idx,
113                        bool primitive_only = false) {
114     uint32_t unavailable_count = 0;
115     uint32_t available_count = 0;
116 
117     if (!reg_ctx)
118       return false; // thread has no registers (i.e. core files are corrupt,
119                     // incomplete crash logs...)
120 
121     const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
122     if (reg_set) {
123       strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
124       strm.IndentMore();
125       const size_t num_registers = reg_set->num_registers;
126       for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
127         const uint32_t reg = reg_set->registers[reg_idx];
128         const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
129         // Skip the dumping of derived register if primitive_only is true.
130         if (primitive_only && reg_info && reg_info->value_regs)
131           continue;
132 
133         if (reg_info && DumpRegister(exe_ctx, strm, *reg_ctx, *reg_info,
134                                      /*print_flags=*/false))
135           ++available_count;
136         else
137           ++unavailable_count;
138       }
139       strm.IndentLess();
140       if (unavailable_count) {
141         strm.Indent();
142         strm.Printf("%u registers were unavailable.\n", unavailable_count);
143       }
144       strm.EOL();
145     }
146     return available_count > 0;
147   }
148 
149 protected:
150   void DoExecute(Args &command, CommandReturnObject &result) override {
151     Stream &strm = result.GetOutputStream();
152     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
153 
154     if (command.GetArgumentCount() == 0) {
155       size_t set_idx;
156 
157       size_t num_register_sets = 1;
158       const size_t set_array_size = m_command_options.set_indexes.GetSize();
159       if (set_array_size > 0) {
160         for (size_t i = 0; i < set_array_size; ++i) {
161           set_idx =
162               m_command_options.set_indexes[i]->GetValueAs<uint64_t>().value_or(
163                   UINT32_MAX);
164           if (set_idx < reg_ctx->GetRegisterSetCount()) {
165             if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
166               if (errno)
167                 result.AppendErrorWithFormatv("register read failed: {0}\n",
168                                               llvm::sys::StrError());
169               else
170                 result.AppendError("unknown error while reading registers.\n");
171               break;
172             }
173           } else {
174             result.AppendErrorWithFormat(
175                 "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
176             break;
177           }
178         }
179       } else {
180         if (m_command_options.dump_all_sets)
181           num_register_sets = reg_ctx->GetRegisterSetCount();
182 
183         for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
184           // When dump_all_sets option is set, dump primitive as well as
185           // derived registers.
186           DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
187                           !m_command_options.dump_all_sets.GetCurrentValue());
188         }
189       }
190     } else {
191       if (m_command_options.dump_all_sets) {
192         result.AppendError("the --all option can't be used when registers "
193                            "names are supplied as arguments\n");
194       } else if (m_command_options.set_indexes.GetSize() > 0) {
195         result.AppendError("the --set <set> option can't be used when "
196                            "registers names are supplied as arguments\n");
197       } else {
198         for (auto &entry : command) {
199           // in most LLDB commands we accept $rbx as the name for register RBX
200           // - and here we would reject it and non-existant. we should be more
201           // consistent towards the user and allow them to say reg read $rbx -
202           // internally, however, we should be strict and not allow ourselves
203           // to call our registers $rbx in our own API
204           auto arg_str = entry.ref();
205           arg_str.consume_front("$");
206 
207           if (const RegisterInfo *reg_info =
208                   reg_ctx->GetRegisterInfoByName(arg_str)) {
209             // If they have asked for a specific format don't obscure that by
210             // printing flags afterwards.
211             bool print_flags =
212                 !m_format_options.GetFormatValue().OptionWasSet();
213             if (!DumpRegister(m_exe_ctx, strm, *reg_ctx, *reg_info,
214                               print_flags))
215               strm.Printf("%-12s = error: unavailable\n", reg_info->name);
216           } else {
217             result.AppendErrorWithFormat("Invalid register name '%s'.\n",
218                                          arg_str.str().c_str());
219           }
220         }
221       }
222     }
223   }
224 
225   class CommandOptions : public OptionGroup {
226   public:
227     CommandOptions()
228         : set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
229           dump_all_sets(false, false), // Initial and default values are false
230           alternate_name(false, false) {}
231 
232     ~CommandOptions() override = default;
233 
234     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
235       return llvm::ArrayRef(g_register_read_options);
236     }
237 
238     void OptionParsingStarting(ExecutionContext *execution_context) override {
239       set_indexes.Clear();
240       dump_all_sets.Clear();
241       alternate_name.Clear();
242     }
243 
244     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
245                           ExecutionContext *execution_context) override {
246       Status error;
247       const int short_option = GetDefinitions()[option_idx].short_option;
248       switch (short_option) {
249       case 's': {
250         OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
251         if (value_sp)
252           set_indexes.AppendValue(value_sp);
253       } break;
254 
255       case 'a':
256         // When we don't use OptionValue::SetValueFromCString(const char *) to
257         // set an option value, it won't be marked as being set in the options
258         // so we make a call to let users know the value was set via option
259         dump_all_sets.SetCurrentValue(true);
260         dump_all_sets.SetOptionWasSet();
261         break;
262 
263       case 'A':
264         // When we don't use OptionValue::SetValueFromCString(const char *) to
265         // set an option value, it won't be marked as being set in the options
266         // so we make a call to let users know the value was set via option
267         alternate_name.SetCurrentValue(true);
268         dump_all_sets.SetOptionWasSet();
269         break;
270 
271       default:
272         llvm_unreachable("Unimplemented option");
273       }
274       return error;
275     }
276 
277     // Instance variables to hold the values for command options.
278     OptionValueArray set_indexes;
279     OptionValueBoolean dump_all_sets;
280     OptionValueBoolean alternate_name;
281   };
282 
283   OptionGroupOptions m_option_group;
284   OptionGroupFormat m_format_options;
285   CommandOptions m_command_options;
286 };
287 
288 // "register write"
289 class CommandObjectRegisterWrite : public CommandObjectParsed {
290 public:
291   CommandObjectRegisterWrite(CommandInterpreter &interpreter)
292       : CommandObjectParsed(interpreter, "register write",
293                             "Modify a single register value.", nullptr,
294                             eCommandRequiresFrame | eCommandRequiresRegContext |
295                                 eCommandProcessMustBeLaunched |
296                                 eCommandProcessMustBePaused) {
297     CommandArgumentEntry arg1;
298     CommandArgumentEntry arg2;
299     CommandArgumentData register_arg;
300     CommandArgumentData value_arg;
301 
302     // Define the first (and only) variant of this arg.
303     register_arg.arg_type = eArgTypeRegisterName;
304     register_arg.arg_repetition = eArgRepeatPlain;
305 
306     // There is only one variant this argument could be; put it into the
307     // argument entry.
308     arg1.push_back(register_arg);
309 
310     // Define the first (and only) variant of this arg.
311     value_arg.arg_type = eArgTypeValue;
312     value_arg.arg_repetition = eArgRepeatPlain;
313 
314     // There is only one variant this argument could be; put it into the
315     // argument entry.
316     arg2.push_back(value_arg);
317 
318     // Push the data for the first argument into the m_arguments vector.
319     m_arguments.push_back(arg1);
320     m_arguments.push_back(arg2);
321   }
322 
323   ~CommandObjectRegisterWrite() override = default;
324 
325   void
326   HandleArgumentCompletion(CompletionRequest &request,
327                            OptionElementVector &opt_element_vector) override {
328     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
329       return;
330 
331     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
332         GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr);
333   }
334 
335 protected:
336   void DoExecute(Args &command, CommandReturnObject &result) override {
337     DataExtractor reg_data;
338     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
339 
340     if (command.GetArgumentCount() != 2) {
341       result.AppendError(
342           "register write takes exactly 2 arguments: <reg-name> <value>");
343     } else {
344       auto reg_name = command[0].ref();
345       auto value_str = command[1].ref();
346 
347       // in most LLDB commands we accept $rbx as the name for register RBX -
348       // and here we would reject it and non-existant. we should be more
349       // consistent towards the user and allow them to say reg write $rbx -
350       // internally, however, we should be strict and not allow ourselves to
351       // call our registers $rbx in our own API
352       reg_name.consume_front("$");
353 
354       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
355 
356       if (reg_info) {
357         RegisterValue reg_value;
358 
359         Status error(reg_value.SetValueFromString(reg_info, value_str));
360         if (error.Success()) {
361           if (reg_ctx->WriteRegister(reg_info, reg_value)) {
362             // Toss all frames and anything else in the thread after a register
363             // has been written.
364             m_exe_ctx.GetThreadRef().Flush();
365             result.SetStatus(eReturnStatusSuccessFinishNoResult);
366             return;
367           }
368         }
369         if (error.AsCString()) {
370           result.AppendErrorWithFormat(
371               "Failed to write register '%s' with value '%s': %s\n",
372               reg_name.str().c_str(), value_str.str().c_str(),
373               error.AsCString());
374         } else {
375           result.AppendErrorWithFormat(
376               "Failed to write register '%s' with value '%s'",
377               reg_name.str().c_str(), value_str.str().c_str());
378         }
379       } else {
380         result.AppendErrorWithFormat("Register not found for '%s'.\n",
381                                      reg_name.str().c_str());
382       }
383     }
384   }
385 };
386 
387 // "register info"
388 class CommandObjectRegisterInfo : public CommandObjectParsed {
389 public:
390   CommandObjectRegisterInfo(CommandInterpreter &interpreter)
391       : CommandObjectParsed(interpreter, "register info",
392                             "View information about a register.", nullptr,
393                             eCommandRequiresFrame | eCommandRequiresRegContext |
394                                 eCommandProcessMustBeLaunched |
395                                 eCommandProcessMustBePaused) {
396     SetHelpLong(R"(
397 Name             The name lldb uses for the register, optionally with an alias.
398 Size             The size of the register in bytes and again in bits.
399 Invalidates (*)  The registers that would be changed if you wrote this
400                  register. For example, writing to a narrower alias of a wider
401                  register would change the value of the wider register.
402 Read from   (*)  The registers that the value of this register is constructed
403                  from. For example, a narrower alias of a wider register will be
404                  read from the wider register.
405 In sets     (*)  The register sets that contain this register. For example the
406                  PC will be in the "General Purpose Register" set.
407 Fields      (*)  A table of the names and bit positions of the values contained
408                  in this register.
409 
410 Fields marked with (*) may not always be present. Some information may be
411 different for the same register when connected to different debug servers.)");
412 
413     AddSimpleArgumentList(eArgTypeRegisterName);
414   }
415 
416   ~CommandObjectRegisterInfo() override = default;
417 
418   void
419   HandleArgumentCompletion(CompletionRequest &request,
420                            OptionElementVector &opt_element_vector) override {
421     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
422       return;
423     CommandObject::HandleArgumentCompletion(request, opt_element_vector);
424   }
425 
426 protected:
427   void DoExecute(Args &command, CommandReturnObject &result) override {
428     if (command.GetArgumentCount() != 1) {
429       result.AppendError("register info takes exactly 1 argument: <reg-name>");
430       return;
431     }
432 
433     llvm::StringRef reg_name = command[0].ref();
434     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
435     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
436     if (reg_info) {
437       DumpRegisterInfo(
438           result.GetOutputStream(), *reg_ctx, *reg_info,
439           GetCommandInterpreter().GetDebugger().GetTerminalWidth());
440       result.SetStatus(eReturnStatusSuccessFinishResult);
441     } else
442       result.AppendErrorWithFormat("No register found with name '%s'.\n",
443                                    reg_name.str().c_str());
444   }
445 };
446 
447 // CommandObjectRegister constructor
448 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
449     : CommandObjectMultiword(interpreter, "register",
450                              "Commands to access registers for the current "
451                              "thread and stack frame.",
452                              "register [read|write|info] ...") {
453   LoadSubCommand("read",
454                  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
455   LoadSubCommand("write",
456                  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
457   LoadSubCommand("info",
458                  CommandObjectSP(new CommandObjectRegisterInfo(interpreter)));
459 }
460 
461 CommandObjectRegister::~CommandObjectRegister() = default;
462