Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp
39587 views
1
//===-- CommandObjectMemory.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 "CommandObjectMemory.h"
10
#include "CommandObjectMemoryTag.h"
11
#include "lldb/Core/DumpDataExtractor.h"
12
#include "lldb/Core/Section.h"
13
#include "lldb/Core/ValueObjectMemory.h"
14
#include "lldb/Expression/ExpressionVariable.h"
15
#include "lldb/Host/OptionParser.h"
16
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
17
#include "lldb/Interpreter/CommandReturnObject.h"
18
#include "lldb/Interpreter/OptionArgParser.h"
19
#include "lldb/Interpreter/OptionGroupFormat.h"
20
#include "lldb/Interpreter/OptionGroupMemoryTag.h"
21
#include "lldb/Interpreter/OptionGroupOutputFile.h"
22
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
23
#include "lldb/Interpreter/OptionValueLanguage.h"
24
#include "lldb/Interpreter/OptionValueString.h"
25
#include "lldb/Interpreter/Options.h"
26
#include "lldb/Symbol/SymbolFile.h"
27
#include "lldb/Symbol/TypeList.h"
28
#include "lldb/Target/ABI.h"
29
#include "lldb/Target/Language.h"
30
#include "lldb/Target/MemoryHistory.h"
31
#include "lldb/Target/MemoryRegionInfo.h"
32
#include "lldb/Target/Process.h"
33
#include "lldb/Target/StackFrame.h"
34
#include "lldb/Target/Target.h"
35
#include "lldb/Target/Thread.h"
36
#include "lldb/Utility/Args.h"
37
#include "lldb/Utility/DataBufferHeap.h"
38
#include "lldb/Utility/StreamString.h"
39
#include "llvm/Support/MathExtras.h"
40
#include <cinttypes>
41
#include <memory>
42
#include <optional>
43
44
using namespace lldb;
45
using namespace lldb_private;
46
47
#define LLDB_OPTIONS_memory_read
48
#include "CommandOptions.inc"
49
50
class OptionGroupReadMemory : public OptionGroup {
51
public:
52
OptionGroupReadMemory()
53
: m_num_per_line(1, 1), m_offset(0, 0),
54
m_language_for_type(eLanguageTypeUnknown) {}
55
56
~OptionGroupReadMemory() override = default;
57
58
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59
return llvm::ArrayRef(g_memory_read_options);
60
}
61
62
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
63
ExecutionContext *execution_context) override {
64
Status error;
65
const int short_option = g_memory_read_options[option_idx].short_option;
66
67
switch (short_option) {
68
case 'l':
69
error = m_num_per_line.SetValueFromString(option_value);
70
if (m_num_per_line.GetCurrentValue() == 0)
71
error.SetErrorStringWithFormat(
72
"invalid value for --num-per-line option '%s'",
73
option_value.str().c_str());
74
break;
75
76
case 'b':
77
m_output_as_binary = true;
78
break;
79
80
case 't':
81
error = m_view_as_type.SetValueFromString(option_value);
82
break;
83
84
case 'r':
85
m_force = true;
86
break;
87
88
case 'x':
89
error = m_language_for_type.SetValueFromString(option_value);
90
break;
91
92
case 'E':
93
error = m_offset.SetValueFromString(option_value);
94
break;
95
96
default:
97
llvm_unreachable("Unimplemented option");
98
}
99
return error;
100
}
101
102
void OptionParsingStarting(ExecutionContext *execution_context) override {
103
m_num_per_line.Clear();
104
m_output_as_binary = false;
105
m_view_as_type.Clear();
106
m_force = false;
107
m_offset.Clear();
108
m_language_for_type.Clear();
109
}
110
111
Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
112
Status error;
113
OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
114
OptionValueUInt64 &count_value = format_options.GetCountValue();
115
const bool byte_size_option_set = byte_size_value.OptionWasSet();
116
const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
117
const bool count_option_set = format_options.GetCountValue().OptionWasSet();
118
119
switch (format_options.GetFormat()) {
120
default:
121
break;
122
123
case eFormatBoolean:
124
if (!byte_size_option_set)
125
byte_size_value = 1;
126
if (!num_per_line_option_set)
127
m_num_per_line = 1;
128
if (!count_option_set)
129
format_options.GetCountValue() = 8;
130
break;
131
132
case eFormatCString:
133
break;
134
135
case eFormatInstruction:
136
if (count_option_set)
137
byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
138
m_num_per_line = 1;
139
break;
140
141
case eFormatAddressInfo:
142
if (!byte_size_option_set)
143
byte_size_value = target->GetArchitecture().GetAddressByteSize();
144
m_num_per_line = 1;
145
if (!count_option_set)
146
format_options.GetCountValue() = 8;
147
break;
148
149
case eFormatPointer:
150
byte_size_value = target->GetArchitecture().GetAddressByteSize();
151
if (!num_per_line_option_set)
152
m_num_per_line = 4;
153
if (!count_option_set)
154
format_options.GetCountValue() = 8;
155
break;
156
157
case eFormatBinary:
158
case eFormatFloat:
159
case eFormatOctal:
160
case eFormatDecimal:
161
case eFormatEnum:
162
case eFormatUnicode8:
163
case eFormatUnicode16:
164
case eFormatUnicode32:
165
case eFormatUnsigned:
166
case eFormatHexFloat:
167
if (!byte_size_option_set)
168
byte_size_value = 4;
169
if (!num_per_line_option_set)
170
m_num_per_line = 1;
171
if (!count_option_set)
172
format_options.GetCountValue() = 8;
173
break;
174
175
case eFormatBytes:
176
case eFormatBytesWithASCII:
177
if (byte_size_option_set) {
178
if (byte_size_value > 1)
179
error.SetErrorStringWithFormat(
180
"display format (bytes/bytes with ASCII) conflicts with the "
181
"specified byte size %" PRIu64 "\n"
182
"\tconsider using a different display format or don't specify "
183
"the byte size.",
184
byte_size_value.GetCurrentValue());
185
} else
186
byte_size_value = 1;
187
if (!num_per_line_option_set)
188
m_num_per_line = 16;
189
if (!count_option_set)
190
format_options.GetCountValue() = 32;
191
break;
192
193
case eFormatCharArray:
194
case eFormatChar:
195
case eFormatCharPrintable:
196
if (!byte_size_option_set)
197
byte_size_value = 1;
198
if (!num_per_line_option_set)
199
m_num_per_line = 32;
200
if (!count_option_set)
201
format_options.GetCountValue() = 64;
202
break;
203
204
case eFormatComplex:
205
if (!byte_size_option_set)
206
byte_size_value = 8;
207
if (!num_per_line_option_set)
208
m_num_per_line = 1;
209
if (!count_option_set)
210
format_options.GetCountValue() = 8;
211
break;
212
213
case eFormatComplexInteger:
214
if (!byte_size_option_set)
215
byte_size_value = 8;
216
if (!num_per_line_option_set)
217
m_num_per_line = 1;
218
if (!count_option_set)
219
format_options.GetCountValue() = 8;
220
break;
221
222
case eFormatHex:
223
if (!byte_size_option_set)
224
byte_size_value = 4;
225
if (!num_per_line_option_set) {
226
switch (byte_size_value) {
227
case 1:
228
case 2:
229
m_num_per_line = 8;
230
break;
231
case 4:
232
m_num_per_line = 4;
233
break;
234
case 8:
235
m_num_per_line = 2;
236
break;
237
default:
238
m_num_per_line = 1;
239
break;
240
}
241
}
242
if (!count_option_set)
243
count_value = 8;
244
break;
245
246
case eFormatVectorOfChar:
247
case eFormatVectorOfSInt8:
248
case eFormatVectorOfUInt8:
249
case eFormatVectorOfSInt16:
250
case eFormatVectorOfUInt16:
251
case eFormatVectorOfSInt32:
252
case eFormatVectorOfUInt32:
253
case eFormatVectorOfSInt64:
254
case eFormatVectorOfUInt64:
255
case eFormatVectorOfFloat16:
256
case eFormatVectorOfFloat32:
257
case eFormatVectorOfFloat64:
258
case eFormatVectorOfUInt128:
259
if (!byte_size_option_set)
260
byte_size_value = 128;
261
if (!num_per_line_option_set)
262
m_num_per_line = 1;
263
if (!count_option_set)
264
count_value = 4;
265
break;
266
}
267
return error;
268
}
269
270
bool AnyOptionWasSet() const {
271
return m_num_per_line.OptionWasSet() || m_output_as_binary ||
272
m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||
273
m_language_for_type.OptionWasSet();
274
}
275
276
OptionValueUInt64 m_num_per_line;
277
bool m_output_as_binary = false;
278
OptionValueString m_view_as_type;
279
bool m_force = false;
280
OptionValueUInt64 m_offset;
281
OptionValueLanguage m_language_for_type;
282
};
283
284
// Read memory from the inferior process
285
class CommandObjectMemoryRead : public CommandObjectParsed {
286
public:
287
CommandObjectMemoryRead(CommandInterpreter &interpreter)
288
: CommandObjectParsed(
289
interpreter, "memory read",
290
"Read from the memory of the current target process.", nullptr,
291
eCommandRequiresTarget | eCommandProcessMustBePaused),
292
m_format_options(eFormatBytesWithASCII, 1, 8),
293
m_memory_tag_options(/*note_binary=*/true),
294
m_prev_format_options(eFormatBytesWithASCII, 1, 8) {
295
CommandArgumentEntry arg1;
296
CommandArgumentEntry arg2;
297
CommandArgumentData start_addr_arg;
298
CommandArgumentData end_addr_arg;
299
300
// Define the first (and only) variant of this arg.
301
start_addr_arg.arg_type = eArgTypeAddressOrExpression;
302
start_addr_arg.arg_repetition = eArgRepeatPlain;
303
304
// There is only one variant this argument could be; put it into the
305
// argument entry.
306
arg1.push_back(start_addr_arg);
307
308
// Define the first (and only) variant of this arg.
309
end_addr_arg.arg_type = eArgTypeAddressOrExpression;
310
end_addr_arg.arg_repetition = eArgRepeatOptional;
311
312
// There is only one variant this argument could be; put it into the
313
// argument entry.
314
arg2.push_back(end_addr_arg);
315
316
// Push the data for the first argument into the m_arguments vector.
317
m_arguments.push_back(arg1);
318
m_arguments.push_back(arg2);
319
320
// Add the "--format" and "--count" options to group 1 and 3
321
m_option_group.Append(&m_format_options,
322
OptionGroupFormat::OPTION_GROUP_FORMAT |
323
OptionGroupFormat::OPTION_GROUP_COUNT,
324
LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
325
m_option_group.Append(&m_format_options,
326
OptionGroupFormat::OPTION_GROUP_GDB_FMT,
327
LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
328
// Add the "--size" option to group 1 and 2
329
m_option_group.Append(&m_format_options,
330
OptionGroupFormat::OPTION_GROUP_SIZE,
331
LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
332
m_option_group.Append(&m_memory_options);
333
m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,
334
LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
335
m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
336
m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
337
LLDB_OPT_SET_ALL);
338
m_option_group.Finalize();
339
}
340
341
~CommandObjectMemoryRead() override = default;
342
343
Options *GetOptions() override { return &m_option_group; }
344
345
std::optional<std::string> GetRepeatCommand(Args &current_command_args,
346
uint32_t index) override {
347
return m_cmd_name;
348
}
349
350
protected:
351
void DoExecute(Args &command, CommandReturnObject &result) override {
352
// No need to check "target" for validity as eCommandRequiresTarget ensures
353
// it is valid
354
Target *target = m_exe_ctx.GetTargetPtr();
355
356
const size_t argc = command.GetArgumentCount();
357
358
if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {
359
result.AppendErrorWithFormat("%s takes a start address expression with "
360
"an optional end address expression.\n",
361
m_cmd_name.c_str());
362
result.AppendWarning("Expressions should be quoted if they contain "
363
"spaces or other special characters.");
364
return;
365
}
366
367
CompilerType compiler_type;
368
Status error;
369
370
const char *view_as_type_cstr =
371
m_memory_options.m_view_as_type.GetCurrentValue();
372
if (view_as_type_cstr && view_as_type_cstr[0]) {
373
// We are viewing memory as a type
374
375
uint32_t reference_count = 0;
376
uint32_t pointer_count = 0;
377
size_t idx;
378
379
#define ALL_KEYWORDS \
380
KEYWORD("const") \
381
KEYWORD("volatile") \
382
KEYWORD("restrict") \
383
KEYWORD("struct") \
384
KEYWORD("class") \
385
KEYWORD("union")
386
387
#define KEYWORD(s) s,
388
static const char *g_keywords[] = {ALL_KEYWORDS};
389
#undef KEYWORD
390
391
#define KEYWORD(s) (sizeof(s) - 1),
392
static const int g_keyword_lengths[] = {ALL_KEYWORDS};
393
#undef KEYWORD
394
395
#undef ALL_KEYWORDS
396
397
static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
398
std::string type_str(view_as_type_cstr);
399
400
// Remove all instances of g_keywords that are followed by spaces
401
for (size_t i = 0; i < g_num_keywords; ++i) {
402
const char *keyword = g_keywords[i];
403
int keyword_len = g_keyword_lengths[i];
404
405
idx = 0;
406
while ((idx = type_str.find(keyword, idx)) != std::string::npos) {
407
if (type_str[idx + keyword_len] == ' ' ||
408
type_str[idx + keyword_len] == '\t') {
409
type_str.erase(idx, keyword_len + 1);
410
idx = 0;
411
} else {
412
idx += keyword_len;
413
}
414
}
415
}
416
bool done = type_str.empty();
417
//
418
idx = type_str.find_first_not_of(" \t");
419
if (idx > 0 && idx != std::string::npos)
420
type_str.erase(0, idx);
421
while (!done) {
422
// Strip trailing spaces
423
if (type_str.empty())
424
done = true;
425
else {
426
switch (type_str[type_str.size() - 1]) {
427
case '*':
428
++pointer_count;
429
[[fallthrough]];
430
case ' ':
431
case '\t':
432
type_str.erase(type_str.size() - 1);
433
break;
434
435
case '&':
436
if (reference_count == 0) {
437
reference_count = 1;
438
type_str.erase(type_str.size() - 1);
439
} else {
440
result.AppendErrorWithFormat("invalid type string: '%s'\n",
441
view_as_type_cstr);
442
return;
443
}
444
break;
445
446
default:
447
done = true;
448
break;
449
}
450
}
451
}
452
453
ConstString lookup_type_name(type_str.c_str());
454
StackFrame *frame = m_exe_ctx.GetFramePtr();
455
ModuleSP search_first;
456
if (frame)
457
search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;
458
TypeQuery query(lookup_type_name.GetStringRef(),
459
TypeQueryOptions::e_find_one);
460
TypeResults results;
461
target->GetImages().FindTypes(search_first.get(), query, results);
462
TypeSP type_sp = results.GetFirstType();
463
464
if (!type_sp && lookup_type_name.GetCString()) {
465
LanguageType language_for_type =
466
m_memory_options.m_language_for_type.GetCurrentValue();
467
std::set<LanguageType> languages_to_check;
468
if (language_for_type != eLanguageTypeUnknown) {
469
languages_to_check.insert(language_for_type);
470
} else {
471
languages_to_check = Language::GetSupportedLanguages();
472
}
473
474
std::set<CompilerType> user_defined_types;
475
for (auto lang : languages_to_check) {
476
if (auto *persistent_vars =
477
target->GetPersistentExpressionStateForLanguage(lang)) {
478
if (std::optional<CompilerType> type =
479
persistent_vars->GetCompilerTypeFromPersistentDecl(
480
lookup_type_name)) {
481
user_defined_types.emplace(*type);
482
}
483
}
484
}
485
486
if (user_defined_types.size() > 1) {
487
result.AppendErrorWithFormat(
488
"Mutiple types found matching raw type '%s', please disambiguate "
489
"by specifying the language with -x",
490
lookup_type_name.GetCString());
491
return;
492
}
493
494
if (user_defined_types.size() == 1) {
495
compiler_type = *user_defined_types.begin();
496
}
497
}
498
499
if (!compiler_type.IsValid()) {
500
if (type_sp) {
501
compiler_type = type_sp->GetFullCompilerType();
502
} else {
503
result.AppendErrorWithFormat("unable to find any types that match "
504
"the raw type '%s' for full type '%s'\n",
505
lookup_type_name.GetCString(),
506
view_as_type_cstr);
507
return;
508
}
509
}
510
511
while (pointer_count > 0) {
512
CompilerType pointer_type = compiler_type.GetPointerType();
513
if (pointer_type.IsValid())
514
compiler_type = pointer_type;
515
else {
516
result.AppendError("unable make a pointer type\n");
517
return;
518
}
519
--pointer_count;
520
}
521
522
std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
523
if (!size) {
524
result.AppendErrorWithFormat(
525
"unable to get the byte size of the type '%s'\n",
526
view_as_type_cstr);
527
return;
528
}
529
m_format_options.GetByteSizeValue() = *size;
530
531
if (!m_format_options.GetCountValue().OptionWasSet())
532
m_format_options.GetCountValue() = 1;
533
} else {
534
error = m_memory_options.FinalizeSettings(target, m_format_options);
535
}
536
537
// Look for invalid combinations of settings
538
if (error.Fail()) {
539
result.AppendError(error.AsCString());
540
return;
541
}
542
543
lldb::addr_t addr;
544
size_t total_byte_size = 0;
545
if (argc == 0) {
546
// Use the last address and byte size and all options as they were if no
547
// options have been set
548
addr = m_next_addr;
549
total_byte_size = m_prev_byte_size;
550
compiler_type = m_prev_compiler_type;
551
if (!m_format_options.AnyOptionWasSet() &&
552
!m_memory_options.AnyOptionWasSet() &&
553
!m_outfile_options.AnyOptionWasSet() &&
554
!m_varobj_options.AnyOptionWasSet() &&
555
!m_memory_tag_options.AnyOptionWasSet()) {
556
m_format_options = m_prev_format_options;
557
m_memory_options = m_prev_memory_options;
558
m_outfile_options = m_prev_outfile_options;
559
m_varobj_options = m_prev_varobj_options;
560
m_memory_tag_options = m_prev_memory_tag_options;
561
}
562
}
563
564
size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
565
566
// TODO For non-8-bit byte addressable architectures this needs to be
567
// revisited to fully support all lldb's range of formatting options.
568
// Furthermore code memory reads (for those architectures) will not be
569
// correctly formatted even w/o formatting options.
570
size_t item_byte_size =
571
target->GetArchitecture().GetDataByteSize() > 1
572
? target->GetArchitecture().GetDataByteSize()
573
: m_format_options.GetByteSizeValue().GetCurrentValue();
574
575
const size_t num_per_line =
576
m_memory_options.m_num_per_line.GetCurrentValue();
577
578
if (total_byte_size == 0) {
579
total_byte_size = item_count * item_byte_size;
580
if (total_byte_size == 0)
581
total_byte_size = 32;
582
}
583
584
if (argc > 0)
585
addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(),
586
LLDB_INVALID_ADDRESS, &error);
587
588
if (addr == LLDB_INVALID_ADDRESS) {
589
result.AppendError("invalid start address expression.");
590
result.AppendError(error.AsCString());
591
return;
592
}
593
594
if (argc == 2) {
595
lldb::addr_t end_addr = OptionArgParser::ToAddress(
596
&m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, nullptr);
597
598
if (end_addr == LLDB_INVALID_ADDRESS) {
599
result.AppendError("invalid end address expression.");
600
result.AppendError(error.AsCString());
601
return;
602
} else if (end_addr <= addr) {
603
result.AppendErrorWithFormat(
604
"end address (0x%" PRIx64
605
") must be greater than the start address (0x%" PRIx64 ").\n",
606
end_addr, addr);
607
return;
608
} else if (m_format_options.GetCountValue().OptionWasSet()) {
609
result.AppendErrorWithFormat(
610
"specify either the end address (0x%" PRIx64
611
") or the count (--count %" PRIu64 "), not both.\n",
612
end_addr, (uint64_t)item_count);
613
return;
614
}
615
616
total_byte_size = end_addr - addr;
617
item_count = total_byte_size / item_byte_size;
618
}
619
620
uint32_t max_unforced_size = target->GetMaximumMemReadSize();
621
622
if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {
623
result.AppendErrorWithFormat(
624
"Normally, \'memory read\' will not read over %" PRIu32
625
" bytes of data.\n",
626
max_unforced_size);
627
result.AppendErrorWithFormat(
628
"Please use --force to override this restriction just once.\n");
629
result.AppendErrorWithFormat("or set target.max-memory-read-size if you "
630
"will often need a larger limit.\n");
631
return;
632
}
633
634
WritableDataBufferSP data_sp;
635
size_t bytes_read = 0;
636
if (compiler_type.GetOpaqueQualType()) {
637
// Make sure we don't display our type as ASCII bytes like the default
638
// memory read
639
if (!m_format_options.GetFormatValue().OptionWasSet())
640
m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
641
642
std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
643
if (!size) {
644
result.AppendError("can't get size of type");
645
return;
646
}
647
bytes_read = *size * m_format_options.GetCountValue().GetCurrentValue();
648
649
if (argc > 0)
650
addr = addr + (*size * m_memory_options.m_offset.GetCurrentValue());
651
} else if (m_format_options.GetFormatValue().GetCurrentValue() !=
652
eFormatCString) {
653
data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');
654
if (data_sp->GetBytes() == nullptr) {
655
result.AppendErrorWithFormat(
656
"can't allocate 0x%" PRIx32
657
" bytes for the memory read buffer, specify a smaller size to read",
658
(uint32_t)total_byte_size);
659
return;
660
}
661
662
Address address(addr, nullptr);
663
bytes_read = target->ReadMemory(address, data_sp->GetBytes(),
664
data_sp->GetByteSize(), error, true);
665
if (bytes_read == 0) {
666
const char *error_cstr = error.AsCString();
667
if (error_cstr && error_cstr[0]) {
668
result.AppendError(error_cstr);
669
} else {
670
result.AppendErrorWithFormat(
671
"failed to read memory from 0x%" PRIx64 ".\n", addr);
672
}
673
return;
674
}
675
676
if (bytes_read < total_byte_size)
677
result.AppendWarningWithFormat(
678
"Not all bytes (%" PRIu64 "/%" PRIu64
679
") were able to be read from 0x%" PRIx64 ".\n",
680
(uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
681
} else {
682
// we treat c-strings as a special case because they do not have a fixed
683
// size
684
if (m_format_options.GetByteSizeValue().OptionWasSet() &&
685
!m_format_options.HasGDBFormat())
686
item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
687
else
688
item_byte_size = target->GetMaximumSizeOfStringSummary();
689
if (!m_format_options.GetCountValue().OptionWasSet())
690
item_count = 1;
691
data_sp = std::make_shared<DataBufferHeap>(
692
(item_byte_size + 1) * item_count,
693
'\0'); // account for NULLs as necessary
694
if (data_sp->GetBytes() == nullptr) {
695
result.AppendErrorWithFormat(
696
"can't allocate 0x%" PRIx64
697
" bytes for the memory read buffer, specify a smaller size to read",
698
(uint64_t)((item_byte_size + 1) * item_count));
699
return;
700
}
701
uint8_t *data_ptr = data_sp->GetBytes();
702
auto data_addr = addr;
703
auto count = item_count;
704
item_count = 0;
705
bool break_on_no_NULL = false;
706
while (item_count < count) {
707
std::string buffer;
708
buffer.resize(item_byte_size + 1, 0);
709
Status error;
710
size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],
711
item_byte_size + 1, error);
712
if (error.Fail()) {
713
result.AppendErrorWithFormat(
714
"failed to read memory from 0x%" PRIx64 ".\n", addr);
715
return;
716
}
717
718
if (item_byte_size == read) {
719
result.AppendWarningWithFormat(
720
"unable to find a NULL terminated string at 0x%" PRIx64
721
". Consider increasing the maximum read length.\n",
722
data_addr);
723
--read;
724
break_on_no_NULL = true;
725
} else
726
++read; // account for final NULL byte
727
728
memcpy(data_ptr, &buffer[0], read);
729
data_ptr += read;
730
data_addr += read;
731
bytes_read += read;
732
item_count++; // if we break early we know we only read item_count
733
// strings
734
735
if (break_on_no_NULL)
736
break;
737
}
738
data_sp =
739
std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);
740
}
741
742
m_next_addr = addr + bytes_read;
743
m_prev_byte_size = bytes_read;
744
m_prev_format_options = m_format_options;
745
m_prev_memory_options = m_memory_options;
746
m_prev_outfile_options = m_outfile_options;
747
m_prev_varobj_options = m_varobj_options;
748
m_prev_memory_tag_options = m_memory_tag_options;
749
m_prev_compiler_type = compiler_type;
750
751
std::unique_ptr<Stream> output_stream_storage;
752
Stream *output_stream_p = nullptr;
753
const FileSpec &outfile_spec =
754
m_outfile_options.GetFile().GetCurrentValue();
755
756
std::string path = outfile_spec.GetPath();
757
if (outfile_spec) {
758
759
File::OpenOptions open_options =
760
File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
761
const bool append = m_outfile_options.GetAppend().GetCurrentValue();
762
open_options |=
763
append ? File::eOpenOptionAppend : File::eOpenOptionTruncate;
764
765
auto outfile = FileSystem::Instance().Open(outfile_spec, open_options);
766
767
if (outfile) {
768
auto outfile_stream_up =
769
std::make_unique<StreamFile>(std::move(outfile.get()));
770
if (m_memory_options.m_output_as_binary) {
771
const size_t bytes_written =
772
outfile_stream_up->Write(data_sp->GetBytes(), bytes_read);
773
if (bytes_written > 0) {
774
result.GetOutputStream().Printf(
775
"%zi bytes %s to '%s'\n", bytes_written,
776
append ? "appended" : "written", path.c_str());
777
return;
778
} else {
779
result.AppendErrorWithFormat("Failed to write %" PRIu64
780
" bytes to '%s'.\n",
781
(uint64_t)bytes_read, path.c_str());
782
return;
783
}
784
} else {
785
// We are going to write ASCII to the file just point the
786
// output_stream to our outfile_stream...
787
output_stream_storage = std::move(outfile_stream_up);
788
output_stream_p = output_stream_storage.get();
789
}
790
} else {
791
result.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",
792
path.c_str(), append ? "append" : "write");
793
794
result.AppendError(llvm::toString(outfile.takeError()));
795
return;
796
}
797
} else {
798
output_stream_p = &result.GetOutputStream();
799
}
800
801
ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
802
if (compiler_type.GetOpaqueQualType()) {
803
for (uint32_t i = 0; i < item_count; ++i) {
804
addr_t item_addr = addr + (i * item_byte_size);
805
Address address(item_addr);
806
StreamString name_strm;
807
name_strm.Printf("0x%" PRIx64, item_addr);
808
ValueObjectSP valobj_sp(ValueObjectMemory::Create(
809
exe_scope, name_strm.GetString(), address, compiler_type));
810
if (valobj_sp) {
811
Format format = m_format_options.GetFormat();
812
if (format != eFormatDefault)
813
valobj_sp->SetFormat(format);
814
815
DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
816
eLanguageRuntimeDescriptionDisplayVerbosityFull, format));
817
818
if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) {
819
result.AppendError(toString(std::move(error)));
820
return;
821
}
822
} else {
823
result.AppendErrorWithFormat(
824
"failed to create a value object for: (%s) %s\n",
825
view_as_type_cstr, name_strm.GetData());
826
return;
827
}
828
}
829
return;
830
}
831
832
result.SetStatus(eReturnStatusSuccessFinishResult);
833
DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),
834
target->GetArchitecture().GetAddressByteSize(),
835
target->GetArchitecture().GetDataByteSize());
836
837
Format format = m_format_options.GetFormat();
838
if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&
839
(item_byte_size != 1)) {
840
// if a count was not passed, or it is 1
841
if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {
842
// this turns requests such as
843
// memory read -fc -s10 -c1 *charPtrPtr
844
// which make no sense (what is a char of size 10?) into a request for
845
// fetching 10 chars of size 1 from the same memory location
846
format = eFormatCharArray;
847
item_count = item_byte_size;
848
item_byte_size = 1;
849
} else {
850
// here we passed a count, and it was not 1 so we have a byte_size and
851
// a count we could well multiply those, but instead let's just fail
852
result.AppendErrorWithFormat(
853
"reading memory as characters of size %" PRIu64 " is not supported",
854
(uint64_t)item_byte_size);
855
return;
856
}
857
}
858
859
assert(output_stream_p);
860
size_t bytes_dumped = DumpDataExtractor(
861
data, output_stream_p, 0, format, item_byte_size, item_count,
862
num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,
863
exe_scope, m_memory_tag_options.GetShowTags().GetCurrentValue());
864
m_next_addr = addr + bytes_dumped;
865
output_stream_p->EOL();
866
}
867
868
OptionGroupOptions m_option_group;
869
OptionGroupFormat m_format_options;
870
OptionGroupReadMemory m_memory_options;
871
OptionGroupOutputFile m_outfile_options;
872
OptionGroupValueObjectDisplay m_varobj_options;
873
OptionGroupMemoryTag m_memory_tag_options;
874
lldb::addr_t m_next_addr = LLDB_INVALID_ADDRESS;
875
lldb::addr_t m_prev_byte_size = 0;
876
OptionGroupFormat m_prev_format_options;
877
OptionGroupReadMemory m_prev_memory_options;
878
OptionGroupOutputFile m_prev_outfile_options;
879
OptionGroupValueObjectDisplay m_prev_varobj_options;
880
OptionGroupMemoryTag m_prev_memory_tag_options;
881
CompilerType m_prev_compiler_type;
882
};
883
884
#define LLDB_OPTIONS_memory_find
885
#include "CommandOptions.inc"
886
887
// Find the specified data in memory
888
class CommandObjectMemoryFind : public CommandObjectParsed {
889
public:
890
class OptionGroupFindMemory : public OptionGroup {
891
public:
892
OptionGroupFindMemory() : m_count(1), m_offset(0) {}
893
894
~OptionGroupFindMemory() override = default;
895
896
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
897
return llvm::ArrayRef(g_memory_find_options);
898
}
899
900
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
901
ExecutionContext *execution_context) override {
902
Status error;
903
const int short_option = g_memory_find_options[option_idx].short_option;
904
905
switch (short_option) {
906
case 'e':
907
m_expr.SetValueFromString(option_value);
908
break;
909
910
case 's':
911
m_string.SetValueFromString(option_value);
912
break;
913
914
case 'c':
915
if (m_count.SetValueFromString(option_value).Fail())
916
error.SetErrorString("unrecognized value for count");
917
break;
918
919
case 'o':
920
if (m_offset.SetValueFromString(option_value).Fail())
921
error.SetErrorString("unrecognized value for dump-offset");
922
break;
923
924
default:
925
llvm_unreachable("Unimplemented option");
926
}
927
return error;
928
}
929
930
void OptionParsingStarting(ExecutionContext *execution_context) override {
931
m_expr.Clear();
932
m_string.Clear();
933
m_count.Clear();
934
}
935
936
OptionValueString m_expr;
937
OptionValueString m_string;
938
OptionValueUInt64 m_count;
939
OptionValueUInt64 m_offset;
940
};
941
942
CommandObjectMemoryFind(CommandInterpreter &interpreter)
943
: CommandObjectParsed(
944
interpreter, "memory find",
945
"Find a value in the memory of the current target process.",
946
nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
947
CommandArgumentEntry arg1;
948
CommandArgumentEntry arg2;
949
CommandArgumentData addr_arg;
950
CommandArgumentData value_arg;
951
952
// Define the first (and only) variant of this arg.
953
addr_arg.arg_type = eArgTypeAddressOrExpression;
954
addr_arg.arg_repetition = eArgRepeatPlain;
955
956
// There is only one variant this argument could be; put it into the
957
// argument entry.
958
arg1.push_back(addr_arg);
959
960
// Define the first (and only) variant of this arg.
961
value_arg.arg_type = eArgTypeAddressOrExpression;
962
value_arg.arg_repetition = eArgRepeatPlain;
963
964
// There is only one variant this argument could be; put it into the
965
// argument entry.
966
arg2.push_back(value_arg);
967
968
// Push the data for the first argument into the m_arguments vector.
969
m_arguments.push_back(arg1);
970
m_arguments.push_back(arg2);
971
972
m_option_group.Append(&m_memory_options);
973
m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
974
LLDB_OPT_SET_ALL);
975
m_option_group.Finalize();
976
}
977
978
~CommandObjectMemoryFind() override = default;
979
980
Options *GetOptions() override { return &m_option_group; }
981
982
protected:
983
void DoExecute(Args &command, CommandReturnObject &result) override {
984
// No need to check "process" for validity as eCommandRequiresProcess
985
// ensures it is valid
986
Process *process = m_exe_ctx.GetProcessPtr();
987
988
const size_t argc = command.GetArgumentCount();
989
990
if (argc != 2) {
991
result.AppendError("two addresses needed for memory find");
992
return;
993
}
994
995
Status error;
996
lldb::addr_t low_addr = OptionArgParser::ToAddress(
997
&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
998
if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
999
result.AppendError("invalid low address");
1000
return;
1001
}
1002
lldb::addr_t high_addr = OptionArgParser::ToAddress(
1003
&m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, &error);
1004
if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1005
result.AppendError("invalid high address");
1006
return;
1007
}
1008
1009
if (high_addr <= low_addr) {
1010
result.AppendError(
1011
"starting address must be smaller than ending address");
1012
return;
1013
}
1014
1015
lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1016
1017
DataBufferHeap buffer;
1018
1019
if (m_memory_options.m_string.OptionWasSet()) {
1020
llvm::StringRef str =
1021
m_memory_options.m_string.GetValueAs<llvm::StringRef>().value_or("");
1022
if (str.empty()) {
1023
result.AppendError("search string must have non-zero length.");
1024
return;
1025
}
1026
buffer.CopyData(str);
1027
} else if (m_memory_options.m_expr.OptionWasSet()) {
1028
StackFrame *frame = m_exe_ctx.GetFramePtr();
1029
ValueObjectSP result_sp;
1030
if ((eExpressionCompleted ==
1031
process->GetTarget().EvaluateExpression(
1032
m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(
1033
""),
1034
frame, result_sp)) &&
1035
result_sp) {
1036
uint64_t value = result_sp->GetValueAsUnsigned(0);
1037
std::optional<uint64_t> size =
1038
result_sp->GetCompilerType().GetByteSize(nullptr);
1039
if (!size)
1040
return;
1041
switch (*size) {
1042
case 1: {
1043
uint8_t byte = (uint8_t)value;
1044
buffer.CopyData(&byte, 1);
1045
} break;
1046
case 2: {
1047
uint16_t word = (uint16_t)value;
1048
buffer.CopyData(&word, 2);
1049
} break;
1050
case 4: {
1051
uint32_t lword = (uint32_t)value;
1052
buffer.CopyData(&lword, 4);
1053
} break;
1054
case 8: {
1055
buffer.CopyData(&value, 8);
1056
} break;
1057
case 3:
1058
case 5:
1059
case 6:
1060
case 7:
1061
result.AppendError("unknown type. pass a string instead");
1062
return;
1063
default:
1064
result.AppendError(
1065
"result size larger than 8 bytes. pass a string instead");
1066
return;
1067
}
1068
} else {
1069
result.AppendError(
1070
"expression evaluation failed. pass a string instead");
1071
return;
1072
}
1073
} else {
1074
result.AppendError(
1075
"please pass either a block of text, or an expression to evaluate.");
1076
return;
1077
}
1078
1079
size_t count = m_memory_options.m_count.GetCurrentValue();
1080
found_location = low_addr;
1081
bool ever_found = false;
1082
while (count) {
1083
found_location = process->FindInMemory(
1084
found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
1085
if (found_location == LLDB_INVALID_ADDRESS) {
1086
if (!ever_found) {
1087
result.AppendMessage("data not found within the range.\n");
1088
result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1089
} else
1090
result.AppendMessage("no more matches within the range.\n");
1091
break;
1092
}
1093
result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",
1094
found_location);
1095
1096
DataBufferHeap dumpbuffer(32, 0);
1097
process->ReadMemory(
1098
found_location + m_memory_options.m_offset.GetCurrentValue(),
1099
dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
1100
if (!error.Fail()) {
1101
DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
1102
process->GetByteOrder(),
1103
process->GetAddressByteSize());
1104
DumpDataExtractor(
1105
data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
1106
dumpbuffer.GetByteSize(), 16,
1107
found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0,
1108
m_exe_ctx.GetBestExecutionContextScope(),
1109
m_memory_tag_options.GetShowTags().GetCurrentValue());
1110
result.GetOutputStream().EOL();
1111
}
1112
1113
--count;
1114
found_location++;
1115
ever_found = true;
1116
}
1117
1118
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1119
}
1120
1121
OptionGroupOptions m_option_group;
1122
OptionGroupFindMemory m_memory_options;
1123
OptionGroupMemoryTag m_memory_tag_options;
1124
};
1125
1126
#define LLDB_OPTIONS_memory_write
1127
#include "CommandOptions.inc"
1128
1129
// Write memory to the inferior process
1130
class CommandObjectMemoryWrite : public CommandObjectParsed {
1131
public:
1132
class OptionGroupWriteMemory : public OptionGroup {
1133
public:
1134
OptionGroupWriteMemory() = default;
1135
1136
~OptionGroupWriteMemory() override = default;
1137
1138
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1139
return llvm::ArrayRef(g_memory_write_options);
1140
}
1141
1142
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1143
ExecutionContext *execution_context) override {
1144
Status error;
1145
const int short_option = g_memory_write_options[option_idx].short_option;
1146
1147
switch (short_option) {
1148
case 'i':
1149
m_infile.SetFile(option_value, FileSpec::Style::native);
1150
FileSystem::Instance().Resolve(m_infile);
1151
if (!FileSystem::Instance().Exists(m_infile)) {
1152
m_infile.Clear();
1153
error.SetErrorStringWithFormat("input file does not exist: '%s'",
1154
option_value.str().c_str());
1155
}
1156
break;
1157
1158
case 'o': {
1159
if (option_value.getAsInteger(0, m_infile_offset)) {
1160
m_infile_offset = 0;
1161
error.SetErrorStringWithFormat("invalid offset string '%s'",
1162
option_value.str().c_str());
1163
}
1164
} break;
1165
1166
default:
1167
llvm_unreachable("Unimplemented option");
1168
}
1169
return error;
1170
}
1171
1172
void OptionParsingStarting(ExecutionContext *execution_context) override {
1173
m_infile.Clear();
1174
m_infile_offset = 0;
1175
}
1176
1177
FileSpec m_infile;
1178
off_t m_infile_offset;
1179
};
1180
1181
CommandObjectMemoryWrite(CommandInterpreter &interpreter)
1182
: CommandObjectParsed(
1183
interpreter, "memory write",
1184
"Write to the memory of the current target process.", nullptr,
1185
eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1186
m_format_options(
1187
eFormatBytes, 1, UINT64_MAX,
1188
{std::make_tuple(
1189
eArgTypeFormat,
1190
"The format to use for each of the value to be written."),
1191
std::make_tuple(eArgTypeByteSize,
1192
"The size in bytes to write from input file or "
1193
"each value.")}) {
1194
CommandArgumentEntry arg1;
1195
CommandArgumentEntry arg2;
1196
CommandArgumentData addr_arg;
1197
CommandArgumentData value_arg;
1198
1199
// Define the first (and only) variant of this arg.
1200
addr_arg.arg_type = eArgTypeAddress;
1201
addr_arg.arg_repetition = eArgRepeatPlain;
1202
1203
// There is only one variant this argument could be; put it into the
1204
// argument entry.
1205
arg1.push_back(addr_arg);
1206
1207
// Define the first (and only) variant of this arg.
1208
value_arg.arg_type = eArgTypeValue;
1209
value_arg.arg_repetition = eArgRepeatPlus;
1210
value_arg.arg_opt_set_association = LLDB_OPT_SET_1;
1211
1212
// There is only one variant this argument could be; put it into the
1213
// argument entry.
1214
arg2.push_back(value_arg);
1215
1216
// Push the data for the first argument into the m_arguments vector.
1217
m_arguments.push_back(arg1);
1218
m_arguments.push_back(arg2);
1219
1220
m_option_group.Append(&m_format_options,
1221
OptionGroupFormat::OPTION_GROUP_FORMAT,
1222
LLDB_OPT_SET_1);
1223
m_option_group.Append(&m_format_options,
1224
OptionGroupFormat::OPTION_GROUP_SIZE,
1225
LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
1226
m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1227
m_option_group.Finalize();
1228
}
1229
1230
~CommandObjectMemoryWrite() override = default;
1231
1232
Options *GetOptions() override { return &m_option_group; }
1233
1234
protected:
1235
void DoExecute(Args &command, CommandReturnObject &result) override {
1236
// No need to check "process" for validity as eCommandRequiresProcess
1237
// ensures it is valid
1238
Process *process = m_exe_ctx.GetProcessPtr();
1239
1240
const size_t argc = command.GetArgumentCount();
1241
1242
if (m_memory_options.m_infile) {
1243
if (argc < 1) {
1244
result.AppendErrorWithFormat(
1245
"%s takes a destination address when writing file contents.\n",
1246
m_cmd_name.c_str());
1247
return;
1248
}
1249
if (argc > 1) {
1250
result.AppendErrorWithFormat(
1251
"%s takes only a destination address when writing file contents.\n",
1252
m_cmd_name.c_str());
1253
return;
1254
}
1255
} else if (argc < 2) {
1256
result.AppendErrorWithFormat(
1257
"%s takes a destination address and at least one value.\n",
1258
m_cmd_name.c_str());
1259
return;
1260
}
1261
1262
StreamString buffer(
1263
Stream::eBinary,
1264
process->GetTarget().GetArchitecture().GetAddressByteSize(),
1265
process->GetTarget().GetArchitecture().GetByteOrder());
1266
1267
OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1268
size_t item_byte_size = byte_size_value.GetCurrentValue();
1269
1270
Status error;
1271
lldb::addr_t addr = OptionArgParser::ToAddress(
1272
&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1273
1274
if (addr == LLDB_INVALID_ADDRESS) {
1275
result.AppendError("invalid address expression\n");
1276
result.AppendError(error.AsCString());
1277
return;
1278
}
1279
1280
if (m_memory_options.m_infile) {
1281
size_t length = SIZE_MAX;
1282
if (item_byte_size > 1)
1283
length = item_byte_size;
1284
auto data_sp = FileSystem::Instance().CreateDataBuffer(
1285
m_memory_options.m_infile.GetPath(), length,
1286
m_memory_options.m_infile_offset);
1287
if (data_sp) {
1288
length = data_sp->GetByteSize();
1289
if (length > 0) {
1290
Status error;
1291
size_t bytes_written =
1292
process->WriteMemory(addr, data_sp->GetBytes(), length, error);
1293
1294
if (bytes_written == length) {
1295
// All bytes written
1296
result.GetOutputStream().Printf(
1297
"%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",
1298
(uint64_t)bytes_written, addr);
1299
result.SetStatus(eReturnStatusSuccessFinishResult);
1300
} else if (bytes_written > 0) {
1301
// Some byte written
1302
result.GetOutputStream().Printf(
1303
"%" PRIu64 " bytes of %" PRIu64
1304
" requested were written to 0x%" PRIx64 "\n",
1305
(uint64_t)bytes_written, (uint64_t)length, addr);
1306
result.SetStatus(eReturnStatusSuccessFinishResult);
1307
} else {
1308
result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1309
" failed: %s.\n",
1310
addr, error.AsCString());
1311
}
1312
}
1313
} else {
1314
result.AppendErrorWithFormat("Unable to read contents of file.\n");
1315
}
1316
return;
1317
} else if (item_byte_size == 0) {
1318
if (m_format_options.GetFormat() == eFormatPointer)
1319
item_byte_size = buffer.GetAddressByteSize();
1320
else
1321
item_byte_size = 1;
1322
}
1323
1324
command.Shift(); // shift off the address argument
1325
uint64_t uval64;
1326
int64_t sval64;
1327
bool success = false;
1328
for (auto &entry : command) {
1329
switch (m_format_options.GetFormat()) {
1330
case kNumFormats:
1331
case eFormatFloat: // TODO: add support for floats soon
1332
case eFormatCharPrintable:
1333
case eFormatBytesWithASCII:
1334
case eFormatComplex:
1335
case eFormatEnum:
1336
case eFormatUnicode8:
1337
case eFormatUnicode16:
1338
case eFormatUnicode32:
1339
case eFormatVectorOfChar:
1340
case eFormatVectorOfSInt8:
1341
case eFormatVectorOfUInt8:
1342
case eFormatVectorOfSInt16:
1343
case eFormatVectorOfUInt16:
1344
case eFormatVectorOfSInt32:
1345
case eFormatVectorOfUInt32:
1346
case eFormatVectorOfSInt64:
1347
case eFormatVectorOfUInt64:
1348
case eFormatVectorOfFloat16:
1349
case eFormatVectorOfFloat32:
1350
case eFormatVectorOfFloat64:
1351
case eFormatVectorOfUInt128:
1352
case eFormatOSType:
1353
case eFormatComplexInteger:
1354
case eFormatAddressInfo:
1355
case eFormatHexFloat:
1356
case eFormatInstruction:
1357
case eFormatVoid:
1358
result.AppendError("unsupported format for writing memory");
1359
return;
1360
1361
case eFormatDefault:
1362
case eFormatBytes:
1363
case eFormatHex:
1364
case eFormatHexUppercase:
1365
case eFormatPointer: {
1366
// Decode hex bytes
1367
// Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
1368
// have to special case that:
1369
bool success = false;
1370
if (entry.ref().starts_with("0x"))
1371
success = !entry.ref().getAsInteger(0, uval64);
1372
if (!success)
1373
success = !entry.ref().getAsInteger(16, uval64);
1374
if (!success) {
1375
result.AppendErrorWithFormat(
1376
"'%s' is not a valid hex string value.\n", entry.c_str());
1377
return;
1378
} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1379
result.AppendErrorWithFormat("Value 0x%" PRIx64
1380
" is too large to fit in a %" PRIu64
1381
" byte unsigned integer value.\n",
1382
uval64, (uint64_t)item_byte_size);
1383
return;
1384
}
1385
buffer.PutMaxHex64(uval64, item_byte_size);
1386
break;
1387
}
1388
case eFormatBoolean:
1389
uval64 = OptionArgParser::ToBoolean(entry.ref(), false, &success);
1390
if (!success) {
1391
result.AppendErrorWithFormat(
1392
"'%s' is not a valid boolean string value.\n", entry.c_str());
1393
return;
1394
}
1395
buffer.PutMaxHex64(uval64, item_byte_size);
1396
break;
1397
1398
case eFormatBinary:
1399
if (entry.ref().getAsInteger(2, uval64)) {
1400
result.AppendErrorWithFormat(
1401
"'%s' is not a valid binary string value.\n", entry.c_str());
1402
return;
1403
} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1404
result.AppendErrorWithFormat("Value 0x%" PRIx64
1405
" is too large to fit in a %" PRIu64
1406
" byte unsigned integer value.\n",
1407
uval64, (uint64_t)item_byte_size);
1408
return;
1409
}
1410
buffer.PutMaxHex64(uval64, item_byte_size);
1411
break;
1412
1413
case eFormatCharArray:
1414
case eFormatChar:
1415
case eFormatCString: {
1416
if (entry.ref().empty())
1417
break;
1418
1419
size_t len = entry.ref().size();
1420
// Include the NULL for C strings...
1421
if (m_format_options.GetFormat() == eFormatCString)
1422
++len;
1423
Status error;
1424
if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {
1425
addr += len;
1426
} else {
1427
result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1428
" failed: %s.\n",
1429
addr, error.AsCString());
1430
return;
1431
}
1432
break;
1433
}
1434
case eFormatDecimal:
1435
if (entry.ref().getAsInteger(0, sval64)) {
1436
result.AppendErrorWithFormat(
1437
"'%s' is not a valid signed decimal value.\n", entry.c_str());
1438
return;
1439
} else if (!llvm::isIntN(item_byte_size * 8, sval64)) {
1440
result.AppendErrorWithFormat(
1441
"Value %" PRIi64 " is too large or small to fit in a %" PRIu64
1442
" byte signed integer value.\n",
1443
sval64, (uint64_t)item_byte_size);
1444
return;
1445
}
1446
buffer.PutMaxHex64(sval64, item_byte_size);
1447
break;
1448
1449
case eFormatUnsigned:
1450
1451
if (entry.ref().getAsInteger(0, uval64)) {
1452
result.AppendErrorWithFormat(
1453
"'%s' is not a valid unsigned decimal string value.\n",
1454
entry.c_str());
1455
return;
1456
} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1457
result.AppendErrorWithFormat("Value %" PRIu64
1458
" is too large to fit in a %" PRIu64
1459
" byte unsigned integer value.\n",
1460
uval64, (uint64_t)item_byte_size);
1461
return;
1462
}
1463
buffer.PutMaxHex64(uval64, item_byte_size);
1464
break;
1465
1466
case eFormatOctal:
1467
if (entry.ref().getAsInteger(8, uval64)) {
1468
result.AppendErrorWithFormat(
1469
"'%s' is not a valid octal string value.\n", entry.c_str());
1470
return;
1471
} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1472
result.AppendErrorWithFormat("Value %" PRIo64
1473
" is too large to fit in a %" PRIu64
1474
" byte unsigned integer value.\n",
1475
uval64, (uint64_t)item_byte_size);
1476
return;
1477
}
1478
buffer.PutMaxHex64(uval64, item_byte_size);
1479
break;
1480
}
1481
}
1482
1483
if (!buffer.GetString().empty()) {
1484
Status error;
1485
const char *buffer_data = buffer.GetString().data();
1486
const size_t buffer_size = buffer.GetString().size();
1487
const size_t write_size =
1488
process->WriteMemory(addr, buffer_data, buffer_size, error);
1489
1490
if (write_size != buffer_size) {
1491
result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1492
" failed: %s.\n",
1493
addr, error.AsCString());
1494
return;
1495
}
1496
}
1497
}
1498
1499
OptionGroupOptions m_option_group;
1500
OptionGroupFormat m_format_options;
1501
OptionGroupWriteMemory m_memory_options;
1502
};
1503
1504
// Get malloc/free history of a memory address.
1505
class CommandObjectMemoryHistory : public CommandObjectParsed {
1506
public:
1507
CommandObjectMemoryHistory(CommandInterpreter &interpreter)
1508
: CommandObjectParsed(interpreter, "memory history",
1509
"Print recorded stack traces for "
1510
"allocation/deallocation events "
1511
"associated with an address.",
1512
nullptr,
1513
eCommandRequiresTarget | eCommandRequiresProcess |
1514
eCommandProcessMustBePaused |
1515
eCommandProcessMustBeLaunched) {
1516
CommandArgumentEntry arg1;
1517
CommandArgumentData addr_arg;
1518
1519
// Define the first (and only) variant of this arg.
1520
addr_arg.arg_type = eArgTypeAddress;
1521
addr_arg.arg_repetition = eArgRepeatPlain;
1522
1523
// There is only one variant this argument could be; put it into the
1524
// argument entry.
1525
arg1.push_back(addr_arg);
1526
1527
// Push the data for the first argument into the m_arguments vector.
1528
m_arguments.push_back(arg1);
1529
}
1530
1531
~CommandObjectMemoryHistory() override = default;
1532
1533
std::optional<std::string> GetRepeatCommand(Args &current_command_args,
1534
uint32_t index) override {
1535
return m_cmd_name;
1536
}
1537
1538
protected:
1539
void DoExecute(Args &command, CommandReturnObject &result) override {
1540
const size_t argc = command.GetArgumentCount();
1541
1542
if (argc == 0 || argc > 1) {
1543
result.AppendErrorWithFormat("%s takes an address expression",
1544
m_cmd_name.c_str());
1545
return;
1546
}
1547
1548
Status error;
1549
lldb::addr_t addr = OptionArgParser::ToAddress(
1550
&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1551
1552
if (addr == LLDB_INVALID_ADDRESS) {
1553
result.AppendError("invalid address expression");
1554
result.AppendError(error.AsCString());
1555
return;
1556
}
1557
1558
Stream *output_stream = &result.GetOutputStream();
1559
1560
const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
1561
const MemoryHistorySP &memory_history =
1562
MemoryHistory::FindPlugin(process_sp);
1563
1564
if (!memory_history) {
1565
result.AppendError("no available memory history provider");
1566
return;
1567
}
1568
1569
HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1570
1571
const bool stop_format = false;
1572
for (auto thread : thread_list) {
1573
thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format);
1574
}
1575
1576
result.SetStatus(eReturnStatusSuccessFinishResult);
1577
}
1578
};
1579
1580
// CommandObjectMemoryRegion
1581
#pragma mark CommandObjectMemoryRegion
1582
1583
#define LLDB_OPTIONS_memory_region
1584
#include "CommandOptions.inc"
1585
1586
class CommandObjectMemoryRegion : public CommandObjectParsed {
1587
public:
1588
class OptionGroupMemoryRegion : public OptionGroup {
1589
public:
1590
OptionGroupMemoryRegion() : m_all(false, false) {}
1591
1592
~OptionGroupMemoryRegion() override = default;
1593
1594
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1595
return llvm::ArrayRef(g_memory_region_options);
1596
}
1597
1598
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1599
ExecutionContext *execution_context) override {
1600
Status status;
1601
const int short_option = g_memory_region_options[option_idx].short_option;
1602
1603
switch (short_option) {
1604
case 'a':
1605
m_all.SetCurrentValue(true);
1606
m_all.SetOptionWasSet();
1607
break;
1608
default:
1609
llvm_unreachable("Unimplemented option");
1610
}
1611
1612
return status;
1613
}
1614
1615
void OptionParsingStarting(ExecutionContext *execution_context) override {
1616
m_all.Clear();
1617
}
1618
1619
OptionValueBoolean m_all;
1620
};
1621
1622
CommandObjectMemoryRegion(CommandInterpreter &interpreter)
1623
: CommandObjectParsed(interpreter, "memory region",
1624
"Get information on the memory region containing "
1625
"an address in the current target process.",
1626
"memory region <address-expression> (or --all)",
1627
eCommandRequiresProcess | eCommandTryTargetAPILock |
1628
eCommandProcessMustBeLaunched) {
1629
// Address in option set 1.
1630
m_arguments.push_back(CommandArgumentEntry{CommandArgumentData(
1631
eArgTypeAddressOrExpression, eArgRepeatPlain, LLDB_OPT_SET_1)});
1632
// "--all" will go in option set 2.
1633
m_option_group.Append(&m_memory_region_options);
1634
m_option_group.Finalize();
1635
}
1636
1637
~CommandObjectMemoryRegion() override = default;
1638
1639
Options *GetOptions() override { return &m_option_group; }
1640
1641
protected:
1642
void DumpRegion(CommandReturnObject &result, Target &target,
1643
const MemoryRegionInfo &range_info, lldb::addr_t load_addr) {
1644
lldb_private::Address addr;
1645
ConstString section_name;
1646
if (target.ResolveLoadAddress(load_addr, addr)) {
1647
SectionSP section_sp(addr.GetSection());
1648
if (section_sp) {
1649
// Got the top most section, not the deepest section
1650
while (section_sp->GetParent())
1651
section_sp = section_sp->GetParent();
1652
section_name = section_sp->GetName();
1653
}
1654
}
1655
1656
ConstString name = range_info.GetName();
1657
result.AppendMessageWithFormatv(
1658
"[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",
1659
range_info.GetRange().GetRangeBase(),
1660
range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),
1661
range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",
1662
name, section_name ? " " : "", section_name);
1663
MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged();
1664
if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)
1665
result.AppendMessage("memory tagging: enabled");
1666
1667
const std::optional<std::vector<addr_t>> &dirty_page_list =
1668
range_info.GetDirtyPageList();
1669
if (dirty_page_list) {
1670
const size_t page_count = dirty_page_list->size();
1671
result.AppendMessageWithFormat(
1672
"Modified memory (dirty) page list provided, %zu entries.\n",
1673
page_count);
1674
if (page_count > 0) {
1675
bool print_comma = false;
1676
result.AppendMessageWithFormat("Dirty pages: ");
1677
for (size_t i = 0; i < page_count; i++) {
1678
if (print_comma)
1679
result.AppendMessageWithFormat(", ");
1680
else
1681
print_comma = true;
1682
result.AppendMessageWithFormat("0x%" PRIx64, (*dirty_page_list)[i]);
1683
}
1684
result.AppendMessageWithFormat(".\n");
1685
}
1686
}
1687
}
1688
1689
void DoExecute(Args &command, CommandReturnObject &result) override {
1690
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1691
if (!process_sp) {
1692
m_prev_end_addr = LLDB_INVALID_ADDRESS;
1693
result.AppendError("invalid process");
1694
return;
1695
}
1696
1697
Status error;
1698
lldb::addr_t load_addr = m_prev_end_addr;
1699
m_prev_end_addr = LLDB_INVALID_ADDRESS;
1700
1701
const size_t argc = command.GetArgumentCount();
1702
const lldb::ABISP &abi = process_sp->GetABI();
1703
1704
if (argc == 1) {
1705
if (m_memory_region_options.m_all) {
1706
result.AppendError(
1707
"The \"--all\" option cannot be used when an address "
1708
"argument is given");
1709
return;
1710
}
1711
1712
auto load_addr_str = command[0].ref();
1713
load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,
1714
LLDB_INVALID_ADDRESS, &error);
1715
if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {
1716
result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n",
1717
command[0].c_str(), error.AsCString());
1718
return;
1719
}
1720
} else if (argc > 1 ||
1721
// When we're repeating the command, the previous end address is
1722
// used for load_addr. If that was 0xF...F then we must have
1723
// reached the end of memory.
1724
(argc == 0 && !m_memory_region_options.m_all &&
1725
load_addr == LLDB_INVALID_ADDRESS) ||
1726
// If the target has non-address bits (tags, limited virtual
1727
// address size, etc.), the end of mappable memory will be lower
1728
// than that. So if we find any non-address bit set, we must be
1729
// at the end of the mappable range.
1730
(abi && (abi->FixAnyAddress(load_addr) != load_addr))) {
1731
result.AppendErrorWithFormat(
1732
"'%s' takes one argument or \"--all\" option:\nUsage: %s\n",
1733
m_cmd_name.c_str(), m_cmd_syntax.c_str());
1734
return;
1735
}
1736
1737
// It is important that we track the address used to request the region as
1738
// this will give the correct section name in the case that regions overlap.
1739
// On Windows we get mutliple regions that start at the same place but are
1740
// different sizes and refer to different sections.
1741
std::vector<std::pair<lldb_private::MemoryRegionInfo, lldb::addr_t>>
1742
region_list;
1743
if (m_memory_region_options.m_all) {
1744
// We don't use GetMemoryRegions here because it doesn't include unmapped
1745
// areas like repeating the command would. So instead, emulate doing that.
1746
lldb::addr_t addr = 0;
1747
while (error.Success() && addr != LLDB_INVALID_ADDRESS &&
1748
// When there are non-address bits the last range will not extend
1749
// to LLDB_INVALID_ADDRESS but to the max virtual address.
1750
// This prevents us looping forever if that is the case.
1751
(!abi || (abi->FixAnyAddress(addr) == addr))) {
1752
lldb_private::MemoryRegionInfo region_info;
1753
error = process_sp->GetMemoryRegionInfo(addr, region_info);
1754
1755
if (error.Success()) {
1756
region_list.push_back({region_info, addr});
1757
addr = region_info.GetRange().GetRangeEnd();
1758
}
1759
}
1760
} else {
1761
lldb_private::MemoryRegionInfo region_info;
1762
error = process_sp->GetMemoryRegionInfo(load_addr, region_info);
1763
if (error.Success())
1764
region_list.push_back({region_info, load_addr});
1765
}
1766
1767
if (error.Success()) {
1768
for (std::pair<MemoryRegionInfo, addr_t> &range : region_list) {
1769
DumpRegion(result, process_sp->GetTarget(), range.first, range.second);
1770
m_prev_end_addr = range.first.GetRange().GetRangeEnd();
1771
}
1772
1773
result.SetStatus(eReturnStatusSuccessFinishResult);
1774
return;
1775
}
1776
1777
result.AppendErrorWithFormat("%s\n", error.AsCString());
1778
}
1779
1780
std::optional<std::string> GetRepeatCommand(Args &current_command_args,
1781
uint32_t index) override {
1782
// If we repeat this command, repeat it without any arguments so we can
1783
// show the next memory range
1784
return m_cmd_name;
1785
}
1786
1787
lldb::addr_t m_prev_end_addr = LLDB_INVALID_ADDRESS;
1788
1789
OptionGroupOptions m_option_group;
1790
OptionGroupMemoryRegion m_memory_region_options;
1791
};
1792
1793
// CommandObjectMemory
1794
1795
CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)
1796
: CommandObjectMultiword(
1797
interpreter, "memory",
1798
"Commands for operating on memory in the current target process.",
1799
"memory <subcommand> [<subcommand-options>]") {
1800
LoadSubCommand("find",
1801
CommandObjectSP(new CommandObjectMemoryFind(interpreter)));
1802
LoadSubCommand("read",
1803
CommandObjectSP(new CommandObjectMemoryRead(interpreter)));
1804
LoadSubCommand("write",
1805
CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));
1806
LoadSubCommand("history",
1807
CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));
1808
LoadSubCommand("region",
1809
CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));
1810
LoadSubCommand("tag",
1811
CommandObjectSP(new CommandObjectMemoryTag(interpreter)));
1812
}
1813
1814
CommandObjectMemory::~CommandObjectMemory() = default;
1815
1816