Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp
96333 views
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().GetSectionLoadList().ResolveLoadAddress(
99
reg_addr, 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
463