1dda28197Spatrick //===-- CommandObjectRegister.cpp -----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectRegister.h"
10061da546Spatrick #include "lldb/Core/Debugger.h"
11061da546Spatrick #include "lldb/Core/DumpRegisterValue.h"
12061da546Spatrick #include "lldb/Host/OptionParser.h"
13*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
14061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
15061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h"
16061da546Spatrick #include "lldb/Interpreter/OptionValueArray.h"
17061da546Spatrick #include "lldb/Interpreter/OptionValueBoolean.h"
18061da546Spatrick #include "lldb/Interpreter/OptionValueUInt64.h"
19061da546Spatrick #include "lldb/Interpreter/Options.h"
20061da546Spatrick #include "lldb/Target/ExecutionContext.h"
21061da546Spatrick #include "lldb/Target/Process.h"
22061da546Spatrick #include "lldb/Target/RegisterContext.h"
23061da546Spatrick #include "lldb/Target/SectionLoadList.h"
24061da546Spatrick #include "lldb/Target/Thread.h"
25061da546Spatrick #include "lldb/Utility/Args.h"
26061da546Spatrick #include "lldb/Utility/DataExtractor.h"
27061da546Spatrick #include "lldb/Utility/RegisterValue.h"
28061da546Spatrick #include "llvm/Support/Errno.h"
29061da546Spatrick
30061da546Spatrick using namespace lldb;
31061da546Spatrick using namespace lldb_private;
32061da546Spatrick
33061da546Spatrick // "register read"
34061da546Spatrick #define LLDB_OPTIONS_register_read
35061da546Spatrick #include "CommandOptions.inc"
36061da546Spatrick
37061da546Spatrick class CommandObjectRegisterRead : public CommandObjectParsed {
38061da546Spatrick public:
CommandObjectRegisterRead(CommandInterpreter & interpreter)39061da546Spatrick CommandObjectRegisterRead(CommandInterpreter &interpreter)
40061da546Spatrick : CommandObjectParsed(
41061da546Spatrick interpreter, "register read",
42061da546Spatrick "Dump the contents of one or more register values from the current "
43061da546Spatrick "frame. If no register is specified, dumps them all.",
44061da546Spatrick nullptr,
45061da546Spatrick eCommandRequiresFrame | eCommandRequiresRegContext |
46061da546Spatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
47*f6aab3d8Srobert m_format_options(eFormatDefault) {
48061da546Spatrick CommandArgumentEntry arg;
49061da546Spatrick CommandArgumentData register_arg;
50061da546Spatrick
51061da546Spatrick // Define the first (and only) variant of this arg.
52061da546Spatrick register_arg.arg_type = eArgTypeRegisterName;
53061da546Spatrick register_arg.arg_repetition = eArgRepeatStar;
54061da546Spatrick
55061da546Spatrick // There is only one variant this argument could be; put it into the
56061da546Spatrick // argument entry.
57061da546Spatrick arg.push_back(register_arg);
58061da546Spatrick
59061da546Spatrick // Push the data for the first argument into the m_arguments vector.
60061da546Spatrick m_arguments.push_back(arg);
61061da546Spatrick
62061da546Spatrick // Add the "--format"
63061da546Spatrick m_option_group.Append(&m_format_options,
64061da546Spatrick OptionGroupFormat::OPTION_GROUP_FORMAT |
65061da546Spatrick OptionGroupFormat::OPTION_GROUP_GDB_FMT,
66061da546Spatrick LLDB_OPT_SET_ALL);
67061da546Spatrick m_option_group.Append(&m_command_options);
68061da546Spatrick m_option_group.Finalize();
69061da546Spatrick }
70061da546Spatrick
71061da546Spatrick ~CommandObjectRegisterRead() override = default;
72061da546Spatrick
73dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)74dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
75dda28197Spatrick OptionElementVector &opt_element_vector) override {
76dda28197Spatrick if (!m_exe_ctx.HasProcessScope())
77dda28197Spatrick return;
78dda28197Spatrick
79dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
80dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eRegisterCompletion,
81dda28197Spatrick request, nullptr);
82dda28197Spatrick }
83dda28197Spatrick
GetOptions()84061da546Spatrick Options *GetOptions() override { return &m_option_group; }
85061da546Spatrick
DumpRegister(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext * reg_ctx,const RegisterInfo * reg_info)86061da546Spatrick bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
87061da546Spatrick RegisterContext *reg_ctx, const RegisterInfo *reg_info) {
88061da546Spatrick if (reg_info) {
89061da546Spatrick RegisterValue reg_value;
90061da546Spatrick
91061da546Spatrick if (reg_ctx->ReadRegister(reg_info, reg_value)) {
92061da546Spatrick strm.Indent();
93061da546Spatrick
94061da546Spatrick bool prefix_with_altname = (bool)m_command_options.alternate_name;
95061da546Spatrick bool prefix_with_name = !prefix_with_altname;
96061da546Spatrick DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name,
97*f6aab3d8Srobert prefix_with_altname, m_format_options.GetFormat(), 8,
98*f6aab3d8Srobert exe_ctx.GetBestExecutionContextScope());
99061da546Spatrick if ((reg_info->encoding == eEncodingUint) ||
100061da546Spatrick (reg_info->encoding == eEncodingSint)) {
101061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
102061da546Spatrick if (process && reg_info->byte_size == process->GetAddressByteSize()) {
103061da546Spatrick addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
104061da546Spatrick if (reg_addr != LLDB_INVALID_ADDRESS) {
105061da546Spatrick Address so_reg_addr;
106061da546Spatrick if (exe_ctx.GetTargetRef()
107061da546Spatrick .GetSectionLoadList()
108061da546Spatrick .ResolveLoadAddress(reg_addr, so_reg_addr)) {
109061da546Spatrick strm.PutCString(" ");
110061da546Spatrick so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(),
111061da546Spatrick Address::DumpStyleResolvedDescription);
112061da546Spatrick }
113061da546Spatrick }
114061da546Spatrick }
115061da546Spatrick }
116061da546Spatrick strm.EOL();
117061da546Spatrick return true;
118061da546Spatrick }
119061da546Spatrick }
120061da546Spatrick return false;
121061da546Spatrick }
122061da546Spatrick
DumpRegisterSet(const ExecutionContext & exe_ctx,Stream & strm,RegisterContext * reg_ctx,size_t set_idx,bool primitive_only=false)123061da546Spatrick bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm,
124061da546Spatrick RegisterContext *reg_ctx, size_t set_idx,
125061da546Spatrick bool primitive_only = false) {
126061da546Spatrick uint32_t unavailable_count = 0;
127061da546Spatrick uint32_t available_count = 0;
128061da546Spatrick
129061da546Spatrick if (!reg_ctx)
130061da546Spatrick return false; // thread has no registers (i.e. core files are corrupt,
131061da546Spatrick // incomplete crash logs...)
132061da546Spatrick
133061da546Spatrick const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx);
134061da546Spatrick if (reg_set) {
135061da546Spatrick strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown"));
136061da546Spatrick strm.IndentMore();
137061da546Spatrick const size_t num_registers = reg_set->num_registers;
138061da546Spatrick for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
139061da546Spatrick const uint32_t reg = reg_set->registers[reg_idx];
140061da546Spatrick const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
141061da546Spatrick // Skip the dumping of derived register if primitive_only is true.
142061da546Spatrick if (primitive_only && reg_info && reg_info->value_regs)
143061da546Spatrick continue;
144061da546Spatrick
145061da546Spatrick if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info))
146061da546Spatrick ++available_count;
147061da546Spatrick else
148061da546Spatrick ++unavailable_count;
149061da546Spatrick }
150061da546Spatrick strm.IndentLess();
151061da546Spatrick if (unavailable_count) {
152061da546Spatrick strm.Indent();
153061da546Spatrick strm.Printf("%u registers were unavailable.\n", unavailable_count);
154061da546Spatrick }
155061da546Spatrick strm.EOL();
156061da546Spatrick }
157061da546Spatrick return available_count > 0;
158061da546Spatrick }
159061da546Spatrick
160061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)161061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
162061da546Spatrick Stream &strm = result.GetOutputStream();
163061da546Spatrick RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
164061da546Spatrick
165061da546Spatrick const RegisterInfo *reg_info = nullptr;
166061da546Spatrick if (command.GetArgumentCount() == 0) {
167061da546Spatrick size_t set_idx;
168061da546Spatrick
169061da546Spatrick size_t num_register_sets = 1;
170061da546Spatrick const size_t set_array_size = m_command_options.set_indexes.GetSize();
171061da546Spatrick if (set_array_size > 0) {
172061da546Spatrick for (size_t i = 0; i < set_array_size; ++i) {
173061da546Spatrick set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX,
174061da546Spatrick nullptr);
175061da546Spatrick if (set_idx < reg_ctx->GetRegisterSetCount()) {
176061da546Spatrick if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
177061da546Spatrick if (errno)
178061da546Spatrick result.AppendErrorWithFormatv("register read failed: {0}\n",
179061da546Spatrick llvm::sys::StrError());
180061da546Spatrick else
181061da546Spatrick result.AppendError("unknown error while reading registers.\n");
182061da546Spatrick break;
183061da546Spatrick }
184061da546Spatrick } else {
185061da546Spatrick result.AppendErrorWithFormat(
186061da546Spatrick "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx);
187061da546Spatrick break;
188061da546Spatrick }
189061da546Spatrick }
190061da546Spatrick } else {
191061da546Spatrick if (m_command_options.dump_all_sets)
192061da546Spatrick num_register_sets = reg_ctx->GetRegisterSetCount();
193061da546Spatrick
194061da546Spatrick for (set_idx = 0; set_idx < num_register_sets; ++set_idx) {
195061da546Spatrick // When dump_all_sets option is set, dump primitive as well as
196061da546Spatrick // derived registers.
197061da546Spatrick DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx,
198061da546Spatrick !m_command_options.dump_all_sets.GetCurrentValue());
199061da546Spatrick }
200061da546Spatrick }
201061da546Spatrick } else {
202061da546Spatrick if (m_command_options.dump_all_sets) {
203061da546Spatrick result.AppendError("the --all option can't be used when registers "
204061da546Spatrick "names are supplied as arguments\n");
205061da546Spatrick } else if (m_command_options.set_indexes.GetSize() > 0) {
206061da546Spatrick result.AppendError("the --set <set> option can't be used when "
207061da546Spatrick "registers names are supplied as arguments\n");
208061da546Spatrick } else {
209061da546Spatrick for (auto &entry : command) {
210061da546Spatrick // in most LLDB commands we accept $rbx as the name for register RBX
211061da546Spatrick // - and here we would reject it and non-existant. we should be more
212061da546Spatrick // consistent towards the user and allow them to say reg read $rbx -
213061da546Spatrick // internally, however, we should be strict and not allow ourselves
214061da546Spatrick // to call our registers $rbx in our own API
215061da546Spatrick auto arg_str = entry.ref();
216061da546Spatrick arg_str.consume_front("$");
217061da546Spatrick
218061da546Spatrick reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
219061da546Spatrick
220061da546Spatrick if (reg_info) {
221061da546Spatrick if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info))
222061da546Spatrick strm.Printf("%-12s = error: unavailable\n", reg_info->name);
223061da546Spatrick } else {
224061da546Spatrick result.AppendErrorWithFormat("Invalid register name '%s'.\n",
225061da546Spatrick arg_str.str().c_str());
226061da546Spatrick }
227061da546Spatrick }
228061da546Spatrick }
229061da546Spatrick }
230061da546Spatrick return result.Succeeded();
231061da546Spatrick }
232061da546Spatrick
233061da546Spatrick class CommandOptions : public OptionGroup {
234061da546Spatrick public:
CommandOptions()235061da546Spatrick CommandOptions()
236*f6aab3d8Srobert : set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)),
237061da546Spatrick dump_all_sets(false, false), // Initial and default values are false
238061da546Spatrick alternate_name(false, false) {}
239061da546Spatrick
240061da546Spatrick ~CommandOptions() override = default;
241061da546Spatrick
GetDefinitions()242061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
243*f6aab3d8Srobert return llvm::ArrayRef(g_register_read_options);
244061da546Spatrick }
245061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)246061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
247061da546Spatrick set_indexes.Clear();
248061da546Spatrick dump_all_sets.Clear();
249061da546Spatrick alternate_name.Clear();
250061da546Spatrick }
251061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)252061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
253061da546Spatrick ExecutionContext *execution_context) override {
254061da546Spatrick Status error;
255061da546Spatrick const int short_option = GetDefinitions()[option_idx].short_option;
256061da546Spatrick switch (short_option) {
257061da546Spatrick case 's': {
258061da546Spatrick OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error));
259061da546Spatrick if (value_sp)
260061da546Spatrick set_indexes.AppendValue(value_sp);
261061da546Spatrick } break;
262061da546Spatrick
263061da546Spatrick case 'a':
264061da546Spatrick // When we don't use OptionValue::SetValueFromCString(const char *) to
265061da546Spatrick // set an option value, it won't be marked as being set in the options
266061da546Spatrick // so we make a call to let users know the value was set via option
267061da546Spatrick dump_all_sets.SetCurrentValue(true);
268061da546Spatrick dump_all_sets.SetOptionWasSet();
269061da546Spatrick break;
270061da546Spatrick
271061da546Spatrick case 'A':
272061da546Spatrick // When we don't use OptionValue::SetValueFromCString(const char *) to
273061da546Spatrick // set an option value, it won't be marked as being set in the options
274061da546Spatrick // so we make a call to let users know the value was set via option
275061da546Spatrick alternate_name.SetCurrentValue(true);
276061da546Spatrick dump_all_sets.SetOptionWasSet();
277061da546Spatrick break;
278061da546Spatrick
279061da546Spatrick default:
280061da546Spatrick llvm_unreachable("Unimplemented option");
281061da546Spatrick }
282061da546Spatrick return error;
283061da546Spatrick }
284061da546Spatrick
285061da546Spatrick // Instance variables to hold the values for command options.
286061da546Spatrick OptionValueArray set_indexes;
287061da546Spatrick OptionValueBoolean dump_all_sets;
288061da546Spatrick OptionValueBoolean alternate_name;
289061da546Spatrick };
290061da546Spatrick
291061da546Spatrick OptionGroupOptions m_option_group;
292061da546Spatrick OptionGroupFormat m_format_options;
293061da546Spatrick CommandOptions m_command_options;
294061da546Spatrick };
295061da546Spatrick
296061da546Spatrick // "register write"
297061da546Spatrick class CommandObjectRegisterWrite : public CommandObjectParsed {
298061da546Spatrick public:
CommandObjectRegisterWrite(CommandInterpreter & interpreter)299061da546Spatrick CommandObjectRegisterWrite(CommandInterpreter &interpreter)
300061da546Spatrick : CommandObjectParsed(interpreter, "register write",
301061da546Spatrick "Modify a single register value.", nullptr,
302061da546Spatrick eCommandRequiresFrame | eCommandRequiresRegContext |
303061da546Spatrick eCommandProcessMustBeLaunched |
304061da546Spatrick eCommandProcessMustBePaused) {
305061da546Spatrick CommandArgumentEntry arg1;
306061da546Spatrick CommandArgumentEntry arg2;
307061da546Spatrick CommandArgumentData register_arg;
308061da546Spatrick CommandArgumentData value_arg;
309061da546Spatrick
310061da546Spatrick // Define the first (and only) variant of this arg.
311061da546Spatrick register_arg.arg_type = eArgTypeRegisterName;
312061da546Spatrick register_arg.arg_repetition = eArgRepeatPlain;
313061da546Spatrick
314061da546Spatrick // There is only one variant this argument could be; put it into the
315061da546Spatrick // argument entry.
316061da546Spatrick arg1.push_back(register_arg);
317061da546Spatrick
318061da546Spatrick // Define the first (and only) variant of this arg.
319061da546Spatrick value_arg.arg_type = eArgTypeValue;
320061da546Spatrick value_arg.arg_repetition = eArgRepeatPlain;
321061da546Spatrick
322061da546Spatrick // There is only one variant this argument could be; put it into the
323061da546Spatrick // argument entry.
324061da546Spatrick arg2.push_back(value_arg);
325061da546Spatrick
326061da546Spatrick // Push the data for the first argument into the m_arguments vector.
327061da546Spatrick m_arguments.push_back(arg1);
328061da546Spatrick m_arguments.push_back(arg2);
329061da546Spatrick }
330061da546Spatrick
331061da546Spatrick ~CommandObjectRegisterWrite() override = default;
332061da546Spatrick
333dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)334dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
335dda28197Spatrick OptionElementVector &opt_element_vector) override {
336dda28197Spatrick if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
337dda28197Spatrick return;
338dda28197Spatrick
339dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
340dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eRegisterCompletion,
341dda28197Spatrick request, nullptr);
342dda28197Spatrick }
343dda28197Spatrick
344061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)345061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
346061da546Spatrick DataExtractor reg_data;
347061da546Spatrick RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
348061da546Spatrick
349061da546Spatrick if (command.GetArgumentCount() != 2) {
350061da546Spatrick result.AppendError(
351061da546Spatrick "register write takes exactly 2 arguments: <reg-name> <value>");
352061da546Spatrick } else {
353061da546Spatrick auto reg_name = command[0].ref();
354061da546Spatrick auto value_str = command[1].ref();
355061da546Spatrick
356061da546Spatrick // in most LLDB commands we accept $rbx as the name for register RBX -
357061da546Spatrick // and here we would reject it and non-existant. we should be more
358061da546Spatrick // consistent towards the user and allow them to say reg write $rbx -
359061da546Spatrick // internally, however, we should be strict and not allow ourselves to
360061da546Spatrick // call our registers $rbx in our own API
361061da546Spatrick reg_name.consume_front("$");
362061da546Spatrick
363061da546Spatrick const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
364061da546Spatrick
365061da546Spatrick if (reg_info) {
366061da546Spatrick RegisterValue reg_value;
367061da546Spatrick
368061da546Spatrick Status error(reg_value.SetValueFromString(reg_info, value_str));
369061da546Spatrick if (error.Success()) {
370061da546Spatrick if (reg_ctx->WriteRegister(reg_info, reg_value)) {
371061da546Spatrick // Toss all frames and anything else in the thread after a register
372061da546Spatrick // has been written.
373061da546Spatrick m_exe_ctx.GetThreadRef().Flush();
374061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
375061da546Spatrick return true;
376061da546Spatrick }
377061da546Spatrick }
378061da546Spatrick if (error.AsCString()) {
379061da546Spatrick result.AppendErrorWithFormat(
380061da546Spatrick "Failed to write register '%s' with value '%s': %s\n",
381061da546Spatrick reg_name.str().c_str(), value_str.str().c_str(),
382061da546Spatrick error.AsCString());
383061da546Spatrick } else {
384061da546Spatrick result.AppendErrorWithFormat(
385061da546Spatrick "Failed to write register '%s' with value '%s'",
386061da546Spatrick reg_name.str().c_str(), value_str.str().c_str());
387061da546Spatrick }
388061da546Spatrick } else {
389061da546Spatrick result.AppendErrorWithFormat("Register not found for '%s'.\n",
390061da546Spatrick reg_name.str().c_str());
391061da546Spatrick }
392061da546Spatrick }
393061da546Spatrick return result.Succeeded();
394061da546Spatrick }
395061da546Spatrick };
396061da546Spatrick
397061da546Spatrick // CommandObjectRegister constructor
CommandObjectRegister(CommandInterpreter & interpreter)398061da546Spatrick CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter)
399061da546Spatrick : CommandObjectMultiword(interpreter, "register",
400061da546Spatrick "Commands to access registers for the current "
401061da546Spatrick "thread and stack frame.",
402061da546Spatrick "register [read|write] ...") {
403061da546Spatrick LoadSubCommand("read",
404061da546Spatrick CommandObjectSP(new CommandObjectRegisterRead(interpreter)));
405061da546Spatrick LoadSubCommand("write",
406061da546Spatrick CommandObjectSP(new CommandObjectRegisterWrite(interpreter)));
407061da546Spatrick }
408061da546Spatrick
409061da546Spatrick CommandObjectRegister::~CommandObjectRegister() = default;
410