LLDB  mainline
CommandObjectRegister.cpp
Go to the documentation of this file.
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 
10 #include "lldb/Core/Debugger.h"
12 #include "lldb/Host/OptionParser.h"
21 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/Args.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 
36 static constexpr OptionDefinition g_register_read_options[] = {
37  // clang-format off
38  { LLDB_OPT_SET_ALL, false, "alternate", 'A', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Display register names using the alternate register name if there is one." },
39  { LLDB_OPT_SET_1, false, "set", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeIndex, "Specify which register sets to dump by index." },
40  { LLDB_OPT_SET_2, false, "all", 'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show all register sets." },
41  // clang-format on
42 };
43 
45 public:
48  interpreter, "register read",
49  "Dump the contents of one or more register values from the current "
50  "frame. If no register is specified, dumps them all.",
51  nullptr,
52  eCommandRequiresFrame | eCommandRequiresRegContext |
53  eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
54  m_option_group(), m_format_options(eFormatDefault),
55  m_command_options() {
57  CommandArgumentData register_arg;
58 
59  // Define the first (and only) variant of this arg.
60  register_arg.arg_type = eArgTypeRegisterName;
61  register_arg.arg_repetition = eArgRepeatStar;
62 
63  // There is only one variant this argument could be; put it into the
64  // argument entry.
65  arg.push_back(register_arg);
66 
67  // Push the data for the first argument into the m_arguments vector.
68  m_arguments.push_back(arg);
69 
70  // Add the "--format"
71  m_option_group.Append(&m_format_options,
72  OptionGroupFormat::OPTION_GROUP_FORMAT |
73  OptionGroupFormat::OPTION_GROUP_GDB_FMT,
75  m_option_group.Append(&m_command_options);
76  m_option_group.Finalize();
77  }
78 
79  ~CommandObjectRegisterRead() override = default;
80 
81  Options *GetOptions() override { return &m_option_group; }
82 
83  bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
84  RegisterContext *reg_ctx, const RegisterInfo *reg_info) {
85  if (reg_info) {
86  RegisterValue reg_value;
87 
88  if (reg_ctx->ReadRegister(reg_info, reg_value)) {
89  strm.Indent();
90 
91  bool prefix_with_altname = (bool)m_command_options.alternate_name;
92  bool prefix_with_name = !prefix_with_altname;
93  DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name,
94  prefix_with_altname, m_format_options.GetFormat(), 8);
95  if ((reg_info->encoding == eEncodingUint) ||
96  (reg_info->encoding == eEncodingSint)) {
97  Process *process = exe_ctx.GetProcessPtr();
98  if (process && reg_info->byte_size == process->GetAddressByteSize()) {
99  addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
100  if (reg_addr != LLDB_INVALID_ADDRESS) {
101  Address so_reg_addr;
102  if (exe_ctx.GetTargetRef()
104  .ResolveLoadAddress(reg_addr, so_reg_addr)) {
105  strm.PutCString(" ");
106  so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
107  Address::DumpStyleResolvedDescription);
108  }
109  }
110  }
111  }
112  strm.EOL();
113  return true;
114  }
115  }
116  return false;
117  }
118 
119  bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
120  RegisterContext *reg_ctx, size_t set_idx,
121  bool primitive_only = false) {
122  uint32_t unavailable_count = 0;
123  uint32_t available_count = 0;
124 
125  if (!reg_ctx)
126  return false; // thread has no registers (i.e. core files are corrupt,
127  // incomplete crash logs...)
128 
129  const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
130  if (reg_set) {
131  strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
132  strm.IndentMore();
133  const size_t num_registers = reg_set->num_registers;
134  for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
135  const uint32_t reg = reg_set->registers[reg_idx];
136  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
137  // Skip the dumping of derived register if primitive_only is true.
138  if (primitive_only && reg_info && reg_info->value_regs)
139  continue;
140 
141  if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info))
142  ++available_count;
143  else
144  ++unavailable_count;
145  }
146  strm.IndentLess();
147  if (unavailable_count) {
148  strm.Indent();
149  strm.Printf("%u registers were unavailable.\n", unavailable_count);
150  }
151  strm.EOL();
152  }
153  return available_count > 0;
154  }
155 
156 protected:
157  bool DoExecute(Args &command, CommandReturnObject &result) override {
158  Stream &strm = result.GetOutputStream();
159  RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
160 
161  const RegisterInfo *reg_info = nullptr;
162  if (command.GetArgumentCount() == 0) {
163  size_t set_idx;
164 
165  size_t num_register_sets = 1;
166  const size_t set_array_size = m_command_options.set_indexes.GetSize();
167  if (set_array_size > 0) {
168  for (size_t i = 0; i < set_array_size; ++i) {
169  set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX,
170  nullptr);
171  if (set_idx < reg_ctx->GetRegisterSetCount()) {
172  if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
173  if (errno)
174  result.AppendErrorWithFormatv("register read failed: {0}\n",
175  llvm::sys::StrError());
176  else
177  result.AppendError("unknown error while reading registers.\n");
179  break;
180  }
181  } else {
182  result.AppendErrorWithFormat(
183  "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
185  break;
186  }
187  }
188  } else {
189  if (m_command_options.dump_all_sets)
190  num_register_sets = reg_ctx->GetRegisterSetCount();
191 
192  for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
193  // When dump_all_sets option is set, dump primitive as well as
194  // derived registers.
195  DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
196  !m_command_options.dump_all_sets.GetCurrentValue());
197  }
198  }
199  } else {
200  if (m_command_options.dump_all_sets) {
201  result.AppendError("the --all option can't be used when registers "
202  "names are supplied as arguments\n");
204  } else if (m_command_options.set_indexes.GetSize() > 0) {
205  result.AppendError("the --set <set> option can't be used when "
206  "registers names are supplied as arguments\n");
208  } else {
209  for (auto &entry : command) {
210  // in most LLDB commands we accept $rbx as the name for register RBX
211  // - and here we would reject it and non-existant. we should be more
212  // consistent towards the user and allow them to say reg read $rbx -
213  // internally, however, we should be strict and not allow ourselves
214  // to call our registers $rbx in our own API
215  auto arg_str = entry.ref;
216  arg_str.consume_front("$");
217 
218  reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
219 
220  if (reg_info) {
221  if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info))
222  strm.Printf("%-12s = error: unavailable\n", reg_info->name);
223  } else {
224  result.AppendErrorWithFormat("Invalid register name '%s'.\n",
225  arg_str.str().c_str());
226  }
227  }
228  }
229  }
230  return result.Succeeded();
231  }
232 
233  class CommandOptions : public OptionGroup {
234  public:
236  : OptionGroup(),
237  set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
238  dump_all_sets(false, false), // Initial and default values are false
239  alternate_name(false, false) {}
240 
241  ~CommandOptions() override = default;
242 
243  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
244  return llvm::makeArrayRef(g_register_read_options);
245  }
246 
247  void OptionParsingStarting(ExecutionContext *execution_context) override {
248  set_indexes.Clear();
249  dump_all_sets.Clear();
250  alternate_name.Clear();
251  }
252 
253  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
254  ExecutionContext *execution_context) override {
255  Status error;
256  const int short_option = GetDefinitions()[option_idx].short_option;
257  switch (short_option) {
258  case 's': {
259  OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
260  if (value_sp)
261  set_indexes.AppendValue(value_sp);
262  } break;
263 
264  case 'a':
265  // When we don't use OptionValue::SetValueFromCString(const char *) to
266  // set an option value, it won't be marked as being set in the options
267  // so we make a call to let users know the value was set via option
268  dump_all_sets.SetCurrentValue(true);
269  dump_all_sets.SetOptionWasSet();
270  break;
271 
272  case 'A':
273  // When we don't use OptionValue::SetValueFromCString(const char *) to
274  // set an option value, it won't be marked as being set in the options
275  // so we make a call to let users know the value was set via option
276  alternate_name.SetCurrentValue(true);
277  dump_all_sets.SetOptionWasSet();
278  break;
279 
280  default:
281  error.SetErrorStringWithFormat("unrecognized short option '%c'",
282  short_option);
283  break;
284  }
285  return error;
286  }
287 
288  // Instance variables to hold the values for command options.
292  };
293 
297 };
298 
299 // "register write"
301 public:
303  : CommandObjectParsed(interpreter, "register write",
304  "Modify a single register value.", nullptr,
305  eCommandRequiresFrame | eCommandRequiresRegContext |
306  eCommandProcessMustBeLaunched |
307  eCommandProcessMustBePaused) {
310  CommandArgumentData register_arg;
311  CommandArgumentData value_arg;
312 
313  // Define the first (and only) variant of this arg.
314  register_arg.arg_type = eArgTypeRegisterName;
315  register_arg.arg_repetition = eArgRepeatPlain;
316 
317  // There is only one variant this argument could be; put it into the
318  // argument entry.
319  arg1.push_back(register_arg);
320 
321  // Define the first (and only) variant of this arg.
322  value_arg.arg_type = eArgTypeValue;
323  value_arg.arg_repetition = eArgRepeatPlain;
324 
325  // There is only one variant this argument could be; put it into the
326  // argument entry.
327  arg2.push_back(value_arg);
328 
329  // Push the data for the first argument into the m_arguments vector.
330  m_arguments.push_back(arg1);
331  m_arguments.push_back(arg2);
332  }
333 
334  ~CommandObjectRegisterWrite() override = default;
335 
336 protected:
337  bool DoExecute(Args &command, CommandReturnObject &result) override {
338  DataExtractor reg_data;
339  RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
340 
341  if (command.GetArgumentCount() != 2) {
342  result.AppendError(
343  "register write takes exactly 2 arguments: <reg-name> <value>");
345  } else {
346  auto reg_name = command[0].ref;
347  auto value_str = command[1].ref;
348 
349  // in most LLDB commands we accept $rbx as the name for register RBX -
350  // and here we would reject it and non-existant. we should be more
351  // consistent towards the user and allow them to say reg write $rbx -
352  // internally, however, we should be strict and not allow ourselves to
353  // call our registers $rbx in our own API
354  reg_name.consume_front("$");
355 
356  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
357 
358  if (reg_info) {
359  RegisterValue reg_value;
360 
361  Status error(reg_value.SetValueFromString(reg_info, value_str));
362  if (error.Success()) {
363  if (reg_ctx->WriteRegister(reg_info, reg_value)) {
364  // Toss all frames and anything else in the thread after a register
365  // has been written.
366  m_exe_ctx.GetThreadRef().Flush();
368  return true;
369  }
370  }
371  if (error.AsCString()) {
372  result.AppendErrorWithFormat(
373  "Failed to write register '%s' with value '%s': %s\n",
374  reg_name.str().c_str(), value_str.str().c_str(),
375  error.AsCString());
376  } else {
377  result.AppendErrorWithFormat(
378  "Failed to write register '%s' with value '%s'",
379  reg_name.str().c_str(), value_str.str().c_str());
380  }
382  } else {
383  result.AppendErrorWithFormat("Register not found for '%s'.\n",
384  reg_name.str().c_str());
386  }
387  }
388  return result.Succeeded();
389  }
390 };
391 
392 // CommandObjectRegister constructor
393 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
394  : CommandObjectMultiword(interpreter, "register",
395  "Commands to access registers for the current "
396  "thread and stack frame.",
397  "register [read|write] ...") {
398  LoadSubCommand("read",
399  CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
400  LoadSubCommand("write",
401  CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
402 }
403 
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
std::vector< CommandArgumentData > CommandArgumentEntry
An data extractor class.
Definition: DataExtractor.h:47
A command line argument class.
Definition: Args.h:32
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.cpp:254
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style=DumpStyleInvalid, uint32_t addr_byte_size=UINT32_MAX) const
Dump a description of this object to a Stream.
Definition: Address.cpp:374
virtual bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)=0
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
Status SetValueFromString(const RegisterInfo *reg_info, llvm::StringRef value_str)
bool DumpRegisterValue(const RegisterValue &reg_val, Stream *s, const RegisterInfo *reg_info, bool prefix_with_name, bool prefix_with_alt_name, lldb::Format format, uint32_t reg_name_right_align_at=0)
#define UINT32_MAX
Definition: lldb-defines.h:31
virtual const RegisterSet * GetRegisterSet(size_t reg_set)=0
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectRegisterWrite(CommandInterpreter &interpreter)
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:127
SectionLoadList & GetSectionLoadList()
Definition: Target.h:1012
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3370
bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, RegisterContext *reg_ctx, const RegisterInfo *reg_info)
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, bool allow_section_end=false) const
virtual const RegisterInfo * GetRegisterInfoAtIndex(size_t reg)=0
virtual bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)=0
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
Process * GetProcessPtr() const
Returns a pointer to the process object.
void IndentLess(int amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:221
const RegisterInfo * GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx=0)
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
static constexpr OptionDefinition g_register_read_options[]
void AppendErrorWithFormatv(const char *format, Args &&... args)
A section + offset based address class.
Definition: Address.h:80
#define LLDB_OPT_SET_2
Definition: lldb-defines.h:112
static bool DumpRegister(Stream &s, StackFrame *frame, RegisterKind reg_kind, uint32_t reg_num, Format format)
A command line option parsing protocol class.
Definition: Options.h:62
bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm, RegisterContext *reg_ctx, size_t set_idx, bool primitive_only=false)
void void AppendError(llvm::StringRef in_string)
uint64_t addr_t
Definition: lldb-types.h:83
void OptionParsingStarting(ExecutionContext *execution_context) override
Target & GetTargetRef() const
Returns a reference to the target object.
Definition: SBAddress.h:15
size_t Indent(const char *s=nullptr)
Indent the current line in the stream.
Definition: Stream.cpp:131
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
#define LLDB_OPT_SET_ALL
Definition: lldb-defines.h:110
bool DoExecute(Args &command, CommandReturnObject &result) override
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
void IndentMore(int amount=2)
Increment the current indentation level.
Definition: Stream.cpp:218
#define LLDB_OPT_SET_1
Definition: lldb-defines.h:111
ExecutionContextScope * GetBestExecutionContextScope() const
virtual size_t GetRegisterSetCount()=0
void SetStatus(lldb::ReturnStatus status)
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override
CommandObjectRegisterRead(CommandInterpreter &interpreter)
An error handling class.
Definition: Status.h:44