1 //===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectMemory.h"
10 #include "lldb/Core/DumpDataExtractor.h"
11 #include "lldb/Core/Section.h"
12 #include "lldb/Core/ValueObjectMemory.h"
13 #include "lldb/Expression/ExpressionVariable.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandReturnObject.h"
16 #include "lldb/Interpreter/OptionArgParser.h"
17 #include "lldb/Interpreter/OptionGroupFormat.h"
18 #include "lldb/Interpreter/OptionGroupOutputFile.h"
19 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
20 #include "lldb/Interpreter/OptionValueLanguage.h"
21 #include "lldb/Interpreter/OptionValueString.h"
22 #include "lldb/Interpreter/Options.h"
23 #include "lldb/Symbol/SymbolFile.h"
24 #include "lldb/Symbol/TypeList.h"
25 #include "lldb/Target/Language.h"
26 #include "lldb/Target/MemoryHistory.h"
27 #include "lldb/Target/MemoryRegionInfo.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/StackFrame.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Target/Thread.h"
32 #include "lldb/Utility/Args.h"
33 #include "lldb/Utility/DataBufferHeap.h"
34 #include "lldb/Utility/DataBufferLLVM.h"
35 #include "lldb/Utility/StreamString.h"
42 using namespace lldb_private
;
44 #define LLDB_OPTIONS_memory_read
45 #include "CommandOptions.inc"
47 class OptionGroupReadMemory
: public OptionGroup
{
49 OptionGroupReadMemory()
50 : m_num_per_line(1, 1), m_output_as_binary(false), m_view_as_type(),
51 m_offset(0, 0), m_language_for_type(eLanguageTypeUnknown
) {}
53 ~OptionGroupReadMemory() override
= default;
55 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
56 return llvm::makeArrayRef(g_memory_read_options
);
59 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_value
,
60 ExecutionContext
*execution_context
) override
{
62 const int short_option
= g_memory_read_options
[option_idx
].short_option
;
64 switch (short_option
) {
66 error
= m_num_per_line
.SetValueFromString(option_value
);
67 if (m_num_per_line
.GetCurrentValue() == 0)
68 error
.SetErrorStringWithFormat(
69 "invalid value for --num-per-line option '%s'",
70 option_value
.str().c_str());
74 m_output_as_binary
= true;
78 error
= m_view_as_type
.SetValueFromString(option_value
);
86 error
= m_language_for_type
.SetValueFromString(option_value
);
90 error
= m_offset
.SetValueFromString(option_value
);
94 llvm_unreachable("Unimplemented option");
99 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
100 m_num_per_line
.Clear();
101 m_output_as_binary
= false;
102 m_view_as_type
.Clear();
105 m_language_for_type
.Clear();
108 Status
FinalizeSettings(Target
*target
, OptionGroupFormat
&format_options
) {
110 OptionValueUInt64
&byte_size_value
= format_options
.GetByteSizeValue();
111 OptionValueUInt64
&count_value
= format_options
.GetCountValue();
112 const bool byte_size_option_set
= byte_size_value
.OptionWasSet();
113 const bool num_per_line_option_set
= m_num_per_line
.OptionWasSet();
114 const bool count_option_set
= format_options
.GetCountValue().OptionWasSet();
116 switch (format_options
.GetFormat()) {
121 if (!byte_size_option_set
)
123 if (!num_per_line_option_set
)
125 if (!count_option_set
)
126 format_options
.GetCountValue() = 8;
132 case eFormatInstruction
:
133 if (count_option_set
)
134 byte_size_value
= target
->GetArchitecture().GetMaximumOpcodeByteSize();
138 case eFormatAddressInfo
:
139 if (!byte_size_option_set
)
140 byte_size_value
= target
->GetArchitecture().GetAddressByteSize();
142 if (!count_option_set
)
143 format_options
.GetCountValue() = 8;
147 byte_size_value
= target
->GetArchitecture().GetAddressByteSize();
148 if (!num_per_line_option_set
)
150 if (!count_option_set
)
151 format_options
.GetCountValue() = 8;
159 case eFormatUnicode8
:
160 case eFormatUnicode16
:
161 case eFormatUnicode32
:
162 case eFormatUnsigned
:
163 case eFormatHexFloat
:
164 if (!byte_size_option_set
)
166 if (!num_per_line_option_set
)
168 if (!count_option_set
)
169 format_options
.GetCountValue() = 8;
173 case eFormatBytesWithASCII
:
174 if (byte_size_option_set
) {
175 if (byte_size_value
> 1)
176 error
.SetErrorStringWithFormat(
177 "display format (bytes/bytes with ASCII) conflicts with the "
178 "specified byte size %" PRIu64
"\n"
179 "\tconsider using a different display format or don't specify "
181 byte_size_value
.GetCurrentValue());
184 if (!num_per_line_option_set
)
186 if (!count_option_set
)
187 format_options
.GetCountValue() = 32;
190 case eFormatCharArray
:
192 case eFormatCharPrintable
:
193 if (!byte_size_option_set
)
195 if (!num_per_line_option_set
)
197 if (!count_option_set
)
198 format_options
.GetCountValue() = 64;
202 if (!byte_size_option_set
)
204 if (!num_per_line_option_set
)
206 if (!count_option_set
)
207 format_options
.GetCountValue() = 8;
210 case eFormatComplexInteger
:
211 if (!byte_size_option_set
)
213 if (!num_per_line_option_set
)
215 if (!count_option_set
)
216 format_options
.GetCountValue() = 8;
220 if (!byte_size_option_set
)
222 if (!num_per_line_option_set
) {
223 switch (byte_size_value
) {
239 if (!count_option_set
)
243 case eFormatVectorOfChar
:
244 case eFormatVectorOfSInt8
:
245 case eFormatVectorOfUInt8
:
246 case eFormatVectorOfSInt16
:
247 case eFormatVectorOfUInt16
:
248 case eFormatVectorOfSInt32
:
249 case eFormatVectorOfUInt32
:
250 case eFormatVectorOfSInt64
:
251 case eFormatVectorOfUInt64
:
252 case eFormatVectorOfFloat16
:
253 case eFormatVectorOfFloat32
:
254 case eFormatVectorOfFloat64
:
255 case eFormatVectorOfUInt128
:
256 if (!byte_size_option_set
)
257 byte_size_value
= 128;
258 if (!num_per_line_option_set
)
260 if (!count_option_set
)
267 bool AnyOptionWasSet() const {
268 return m_num_per_line
.OptionWasSet() || m_output_as_binary
||
269 m_view_as_type
.OptionWasSet() || m_offset
.OptionWasSet() ||
270 m_language_for_type
.OptionWasSet();
273 OptionValueUInt64 m_num_per_line
;
274 bool m_output_as_binary
;
275 OptionValueString m_view_as_type
;
277 OptionValueUInt64 m_offset
;
278 OptionValueLanguage m_language_for_type
;
281 // Read memory from the inferior process
282 class CommandObjectMemoryRead
: public CommandObjectParsed
{
284 CommandObjectMemoryRead(CommandInterpreter
&interpreter
)
285 : CommandObjectParsed(
286 interpreter
, "memory read",
287 "Read from the memory of the current target process.", nullptr,
288 eCommandRequiresTarget
| eCommandProcessMustBePaused
),
289 m_option_group(), m_format_options(eFormatBytesWithASCII
, 1, 8),
290 m_memory_options(), m_outfile_options(), m_varobj_options(),
291 m_next_addr(LLDB_INVALID_ADDRESS
), m_prev_byte_size(0),
292 m_prev_format_options(eFormatBytesWithASCII
, 1, 8),
293 m_prev_memory_options(), m_prev_outfile_options(),
294 m_prev_varobj_options() {
295 CommandArgumentEntry arg1
;
296 CommandArgumentEntry arg2
;
297 CommandArgumentData start_addr_arg
;
298 CommandArgumentData end_addr_arg
;
300 // Define the first (and only) variant of this arg.
301 start_addr_arg
.arg_type
= eArgTypeAddressOrExpression
;
302 start_addr_arg
.arg_repetition
= eArgRepeatPlain
;
304 // There is only one variant this argument could be; put it into the
306 arg1
.push_back(start_addr_arg
);
308 // Define the first (and only) variant of this arg.
309 end_addr_arg
.arg_type
= eArgTypeAddressOrExpression
;
310 end_addr_arg
.arg_repetition
= eArgRepeatOptional
;
312 // There is only one variant this argument could be; put it into the
314 arg2
.push_back(end_addr_arg
);
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
);
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
.Finalize();
339 ~CommandObjectMemoryRead() override
= default;
341 Options
*GetOptions() override
{ return &m_option_group
; }
343 const char *GetRepeatCommand(Args
¤t_command_args
,
344 uint32_t index
) override
{
345 return m_cmd_name
.c_str();
349 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
350 // No need to check "target" for validity as eCommandRequiresTarget ensures
352 Target
*target
= m_exe_ctx
.GetTargetPtr();
354 const size_t argc
= command
.GetArgumentCount();
356 if ((argc
== 0 && m_next_addr
== LLDB_INVALID_ADDRESS
) || argc
> 2) {
357 result
.AppendErrorWithFormat("%s takes a start address expression with "
358 "an optional end address expression.\n",
360 result
.AppendRawWarning("Expressions should be quoted if they contain "
361 "spaces or other special characters.\n");
362 result
.SetStatus(eReturnStatusFailed
);
366 CompilerType compiler_type
;
369 const char *view_as_type_cstr
=
370 m_memory_options
.m_view_as_type
.GetCurrentValue();
371 if (view_as_type_cstr
&& view_as_type_cstr
[0]) {
372 // We are viewing memory as a type
374 const bool exact_match
= false;
376 uint32_t reference_count
= 0;
377 uint32_t pointer_count
= 0;
380 #define ALL_KEYWORDS \
382 KEYWORD("volatile") \
383 KEYWORD("restrict") \
388 #define KEYWORD(s) s,
389 static const char *g_keywords
[] = {ALL_KEYWORDS
};
392 #define KEYWORD(s) (sizeof(s) - 1),
393 static const int g_keyword_lengths
[] = {ALL_KEYWORDS
};
398 static size_t g_num_keywords
= sizeof(g_keywords
) / sizeof(const char *);
399 std::string
type_str(view_as_type_cstr
);
401 // Remove all instances of g_keywords that are followed by spaces
402 for (size_t i
= 0; i
< g_num_keywords
; ++i
) {
403 const char *keyword
= g_keywords
[i
];
404 int keyword_len
= g_keyword_lengths
[i
];
407 while ((idx
= type_str
.find(keyword
, idx
)) != std::string::npos
) {
408 if (type_str
[idx
+ keyword_len
] == ' ' ||
409 type_str
[idx
+ keyword_len
] == '\t') {
410 type_str
.erase(idx
, keyword_len
+ 1);
417 bool done
= type_str
.empty();
419 idx
= type_str
.find_first_not_of(" \t");
420 if (idx
> 0 && idx
!= std::string::npos
)
421 type_str
.erase(0, idx
);
423 // Strip trailing spaces
424 if (type_str
.empty())
427 switch (type_str
[type_str
.size() - 1]) {
433 type_str
.erase(type_str
.size() - 1);
437 if (reference_count
== 0) {
439 type_str
.erase(type_str
.size() - 1);
441 result
.AppendErrorWithFormat("invalid type string: '%s'\n",
443 result
.SetStatus(eReturnStatusFailed
);
455 llvm::DenseSet
<lldb_private::SymbolFile
*> searched_symbol_files
;
456 ConstString
lookup_type_name(type_str
.c_str());
457 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
458 ModuleSP search_first
;
460 search_first
= frame
->GetSymbolContext(eSymbolContextModule
).module_sp
;
462 target
->GetImages().FindTypes(search_first
.get(), lookup_type_name
,
463 exact_match
, 1, searched_symbol_files
,
466 if (type_list
.GetSize() == 0 && lookup_type_name
.GetCString()) {
467 LanguageType language_for_type
=
468 m_memory_options
.m_language_for_type
.GetCurrentValue();
469 std::set
<LanguageType
> languages_to_check
;
470 if (language_for_type
!= eLanguageTypeUnknown
) {
471 languages_to_check
.insert(language_for_type
);
473 languages_to_check
= Language::GetSupportedLanguages();
476 std::set
<CompilerType
> user_defined_types
;
477 for (auto lang
: languages_to_check
) {
478 if (auto *persistent_vars
=
479 target
->GetPersistentExpressionStateForLanguage(lang
)) {
480 if (llvm::Optional
<CompilerType
> type
=
481 persistent_vars
->GetCompilerTypeFromPersistentDecl(
483 user_defined_types
.emplace(*type
);
488 if (user_defined_types
.size() > 1) {
489 result
.AppendErrorWithFormat(
490 "Mutiple types found matching raw type '%s', please disambiguate "
491 "by specifying the language with -x",
492 lookup_type_name
.GetCString());
493 result
.SetStatus(eReturnStatusFailed
);
497 if (user_defined_types
.size() == 1) {
498 compiler_type
= *user_defined_types
.begin();
502 if (!compiler_type
.IsValid()) {
503 if (type_list
.GetSize() == 0) {
504 result
.AppendErrorWithFormat("unable to find any types that match "
505 "the raw type '%s' for full type '%s'\n",
506 lookup_type_name
.GetCString(),
508 result
.SetStatus(eReturnStatusFailed
);
511 TypeSP
type_sp(type_list
.GetTypeAtIndex(0));
512 compiler_type
= type_sp
->GetFullCompilerType();
516 while (pointer_count
> 0) {
517 CompilerType pointer_type
= compiler_type
.GetPointerType();
518 if (pointer_type
.IsValid())
519 compiler_type
= pointer_type
;
521 result
.AppendError("unable make a pointer type\n");
522 result
.SetStatus(eReturnStatusFailed
);
528 llvm::Optional
<uint64_t> size
= compiler_type
.GetByteSize(nullptr);
530 result
.AppendErrorWithFormat(
531 "unable to get the byte size of the type '%s'\n",
533 result
.SetStatus(eReturnStatusFailed
);
536 m_format_options
.GetByteSizeValue() = *size
;
538 if (!m_format_options
.GetCountValue().OptionWasSet())
539 m_format_options
.GetCountValue() = 1;
541 error
= m_memory_options
.FinalizeSettings(target
, m_format_options
);
544 // Look for invalid combinations of settings
546 result
.AppendError(error
.AsCString());
547 result
.SetStatus(eReturnStatusFailed
);
552 size_t total_byte_size
= 0;
554 // Use the last address and byte size and all options as they were if no
555 // options have been set
557 total_byte_size
= m_prev_byte_size
;
558 compiler_type
= m_prev_compiler_type
;
559 if (!m_format_options
.AnyOptionWasSet() &&
560 !m_memory_options
.AnyOptionWasSet() &&
561 !m_outfile_options
.AnyOptionWasSet() &&
562 !m_varobj_options
.AnyOptionWasSet()) {
563 m_format_options
= m_prev_format_options
;
564 m_memory_options
= m_prev_memory_options
;
565 m_outfile_options
= m_prev_outfile_options
;
566 m_varobj_options
= m_prev_varobj_options
;
570 size_t item_count
= m_format_options
.GetCountValue().GetCurrentValue();
572 // TODO For non-8-bit byte addressable architectures this needs to be
573 // revisited to fully support all lldb's range of formatting options.
574 // Furthermore code memory reads (for those architectures) will not be
575 // correctly formatted even w/o formatting options.
576 size_t item_byte_size
=
577 target
->GetArchitecture().GetDataByteSize() > 1
578 ? target
->GetArchitecture().GetDataByteSize()
579 : m_format_options
.GetByteSizeValue().GetCurrentValue();
581 const size_t num_per_line
=
582 m_memory_options
.m_num_per_line
.GetCurrentValue();
584 if (total_byte_size
== 0) {
585 total_byte_size
= item_count
* item_byte_size
;
586 if (total_byte_size
== 0)
587 total_byte_size
= 32;
591 addr
= OptionArgParser::ToAddress(&m_exe_ctx
, command
[0].ref(),
592 LLDB_INVALID_ADDRESS
, &error
);
594 if (addr
== LLDB_INVALID_ADDRESS
) {
595 result
.AppendError("invalid start address expression.");
596 result
.AppendError(error
.AsCString());
597 result
.SetStatus(eReturnStatusFailed
);
602 lldb::addr_t end_addr
= OptionArgParser::ToAddress(
603 &m_exe_ctx
, command
[1].ref(), LLDB_INVALID_ADDRESS
, nullptr);
604 if (end_addr
== LLDB_INVALID_ADDRESS
) {
605 result
.AppendError("invalid end address expression.");
606 result
.AppendError(error
.AsCString());
607 result
.SetStatus(eReturnStatusFailed
);
609 } else if (end_addr
<= addr
) {
610 result
.AppendErrorWithFormat(
611 "end address (0x%" PRIx64
612 ") must be greater that the start address (0x%" PRIx64
").\n",
614 result
.SetStatus(eReturnStatusFailed
);
616 } else if (m_format_options
.GetCountValue().OptionWasSet()) {
617 result
.AppendErrorWithFormat(
618 "specify either the end address (0x%" PRIx64
619 ") or the count (--count %" PRIu64
"), not both.\n",
620 end_addr
, (uint64_t)item_count
);
621 result
.SetStatus(eReturnStatusFailed
);
625 total_byte_size
= end_addr
- addr
;
626 item_count
= total_byte_size
/ item_byte_size
;
629 uint32_t max_unforced_size
= target
->GetMaximumMemReadSize();
631 if (total_byte_size
> max_unforced_size
&& !m_memory_options
.m_force
) {
632 result
.AppendErrorWithFormat(
633 "Normally, \'memory read\' will not read over %" PRIu32
636 result
.AppendErrorWithFormat(
637 "Please use --force to override this restriction just once.\n");
638 result
.AppendErrorWithFormat("or set target.max-memory-read-size if you "
639 "will often need a larger limit.\n");
643 DataBufferSP data_sp
;
644 size_t bytes_read
= 0;
645 if (compiler_type
.GetOpaqueQualType()) {
646 // Make sure we don't display our type as ASCII bytes like the default
648 if (!m_format_options
.GetFormatValue().OptionWasSet())
649 m_format_options
.GetFormatValue().SetCurrentValue(eFormatDefault
);
651 llvm::Optional
<uint64_t> size
= compiler_type
.GetByteSize(nullptr);
653 result
.AppendError("can't get size of type");
656 bytes_read
= *size
* m_format_options
.GetCountValue().GetCurrentValue();
659 addr
= addr
+ (*size
* m_memory_options
.m_offset
.GetCurrentValue());
660 } else if (m_format_options
.GetFormatValue().GetCurrentValue() !=
662 data_sp
= std::make_shared
<DataBufferHeap
>(total_byte_size
, '\0');
663 if (data_sp
->GetBytes() == nullptr) {
664 result
.AppendErrorWithFormat(
665 "can't allocate 0x%" PRIx32
666 " bytes for the memory read buffer, specify a smaller size to read",
667 (uint32_t)total_byte_size
);
668 result
.SetStatus(eReturnStatusFailed
);
672 Address
address(addr
, nullptr);
673 bytes_read
= target
->ReadMemory(address
, false, data_sp
->GetBytes(),
674 data_sp
->GetByteSize(), error
);
675 if (bytes_read
== 0) {
676 const char *error_cstr
= error
.AsCString();
677 if (error_cstr
&& error_cstr
[0]) {
678 result
.AppendError(error_cstr
);
680 result
.AppendErrorWithFormat(
681 "failed to read memory from 0x%" PRIx64
".\n", addr
);
683 result
.SetStatus(eReturnStatusFailed
);
687 if (bytes_read
< total_byte_size
)
688 result
.AppendWarningWithFormat(
689 "Not all bytes (%" PRIu64
"/%" PRIu64
690 ") were able to be read from 0x%" PRIx64
".\n",
691 (uint64_t)bytes_read
, (uint64_t)total_byte_size
, addr
);
693 // we treat c-strings as a special case because they do not have a fixed
695 if (m_format_options
.GetByteSizeValue().OptionWasSet() &&
696 !m_format_options
.HasGDBFormat())
697 item_byte_size
= m_format_options
.GetByteSizeValue().GetCurrentValue();
699 item_byte_size
= target
->GetMaximumSizeOfStringSummary();
700 if (!m_format_options
.GetCountValue().OptionWasSet())
702 data_sp
= std::make_shared
<DataBufferHeap
>(
703 (item_byte_size
+ 1) * item_count
,
704 '\0'); // account for NULLs as necessary
705 if (data_sp
->GetBytes() == nullptr) {
706 result
.AppendErrorWithFormat(
707 "can't allocate 0x%" PRIx64
708 " bytes for the memory read buffer, specify a smaller size to read",
709 (uint64_t)((item_byte_size
+ 1) * item_count
));
710 result
.SetStatus(eReturnStatusFailed
);
713 uint8_t *data_ptr
= data_sp
->GetBytes();
714 auto data_addr
= addr
;
715 auto count
= item_count
;
717 bool break_on_no_NULL
= false;
718 while (item_count
< count
) {
720 buffer
.resize(item_byte_size
+ 1, 0);
722 size_t read
= target
->ReadCStringFromMemory(data_addr
, &buffer
[0],
723 item_byte_size
+ 1, error
);
725 result
.AppendErrorWithFormat(
726 "failed to read memory from 0x%" PRIx64
".\n", addr
);
727 result
.SetStatus(eReturnStatusFailed
);
731 if (item_byte_size
== read
) {
732 result
.AppendWarningWithFormat(
733 "unable to find a NULL terminated string at 0x%" PRIx64
734 ".Consider increasing the maximum read length.\n",
737 break_on_no_NULL
= true;
739 ++read
; // account for final NULL byte
741 memcpy(data_ptr
, &buffer
[0], read
);
745 item_count
++; // if we break early we know we only read item_count
748 if (break_on_no_NULL
)
752 std::make_shared
<DataBufferHeap
>(data_sp
->GetBytes(), bytes_read
+ 1);
755 m_next_addr
= addr
+ bytes_read
;
756 m_prev_byte_size
= bytes_read
;
757 m_prev_format_options
= m_format_options
;
758 m_prev_memory_options
= m_memory_options
;
759 m_prev_outfile_options
= m_outfile_options
;
760 m_prev_varobj_options
= m_varobj_options
;
761 m_prev_compiler_type
= compiler_type
;
763 std::unique_ptr
<Stream
> output_stream_storage
;
764 Stream
*output_stream_p
= nullptr;
765 const FileSpec
&outfile_spec
=
766 m_outfile_options
.GetFile().GetCurrentValue();
768 std::string path
= outfile_spec
.GetPath();
771 auto open_options
= File::eOpenOptionWrite
| File::eOpenOptionCanCreate
;
772 const bool append
= m_outfile_options
.GetAppend().GetCurrentValue();
774 open_options
|= File::eOpenOptionAppend
;
776 auto outfile
= FileSystem::Instance().Open(outfile_spec
, open_options
);
779 auto outfile_stream_up
=
780 std::make_unique
<StreamFile
>(std::move(outfile
.get()));
781 if (m_memory_options
.m_output_as_binary
) {
782 const size_t bytes_written
=
783 outfile_stream_up
->Write(data_sp
->GetBytes(), bytes_read
);
784 if (bytes_written
> 0) {
785 result
.GetOutputStream().Printf(
786 "%zi bytes %s to '%s'\n", bytes_written
,
787 append
? "appended" : "written", path
.c_str());
790 result
.AppendErrorWithFormat("Failed to write %" PRIu64
792 (uint64_t)bytes_read
, path
.c_str());
793 result
.SetStatus(eReturnStatusFailed
);
797 // We are going to write ASCII to the file just point the
798 // output_stream to our outfile_stream...
799 output_stream_storage
= std::move(outfile_stream_up
);
800 output_stream_p
= output_stream_storage
.get();
803 result
.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",
804 path
.c_str(), append
? "append" : "write");
806 result
.AppendError(llvm::toString(outfile
.takeError()));
807 result
.SetStatus(eReturnStatusFailed
);
811 output_stream_p
= &result
.GetOutputStream();
814 ExecutionContextScope
*exe_scope
= m_exe_ctx
.GetBestExecutionContextScope();
815 if (compiler_type
.GetOpaqueQualType()) {
816 for (uint32_t i
= 0; i
< item_count
; ++i
) {
817 addr_t item_addr
= addr
+ (i
* item_byte_size
);
818 Address
address(item_addr
);
819 StreamString name_strm
;
820 name_strm
.Printf("0x%" PRIx64
, item_addr
);
821 ValueObjectSP
valobj_sp(ValueObjectMemory::Create(
822 exe_scope
, name_strm
.GetString(), address
, compiler_type
));
824 Format format
= m_format_options
.GetFormat();
825 if (format
!= eFormatDefault
)
826 valobj_sp
->SetFormat(format
);
828 DumpValueObjectOptions
options(m_varobj_options
.GetAsDumpOptions(
829 eLanguageRuntimeDescriptionDisplayVerbosityFull
, format
));
831 valobj_sp
->Dump(*output_stream_p
, options
);
833 result
.AppendErrorWithFormat(
834 "failed to create a value object for: (%s) %s\n",
835 view_as_type_cstr
, name_strm
.GetData());
836 result
.SetStatus(eReturnStatusFailed
);
843 result
.SetStatus(eReturnStatusSuccessFinishResult
);
844 DataExtractor
data(data_sp
, target
->GetArchitecture().GetByteOrder(),
845 target
->GetArchitecture().GetAddressByteSize(),
846 target
->GetArchitecture().GetDataByteSize());
848 Format format
= m_format_options
.GetFormat();
849 if (((format
== eFormatChar
) || (format
== eFormatCharPrintable
)) &&
850 (item_byte_size
!= 1)) {
851 // if a count was not passed, or it is 1
852 if (!m_format_options
.GetCountValue().OptionWasSet() || item_count
== 1) {
853 // this turns requests such as
854 // memory read -fc -s10 -c1 *charPtrPtr
855 // which make no sense (what is a char of size 10?) into a request for
856 // fetching 10 chars of size 1 from the same memory location
857 format
= eFormatCharArray
;
858 item_count
= item_byte_size
;
861 // here we passed a count, and it was not 1 so we have a byte_size and
862 // a count we could well multiply those, but instead let's just fail
863 result
.AppendErrorWithFormat(
864 "reading memory as characters of size %" PRIu64
" is not supported",
865 (uint64_t)item_byte_size
);
866 result
.SetStatus(eReturnStatusFailed
);
871 assert(output_stream_p
);
872 size_t bytes_dumped
= DumpDataExtractor(
873 data
, output_stream_p
, 0, format
, item_byte_size
, item_count
,
874 num_per_line
/ target
->GetArchitecture().GetDataByteSize(), addr
, 0, 0,
876 m_next_addr
= addr
+ bytes_dumped
;
877 output_stream_p
->EOL();
881 OptionGroupOptions m_option_group
;
882 OptionGroupFormat m_format_options
;
883 OptionGroupReadMemory m_memory_options
;
884 OptionGroupOutputFile m_outfile_options
;
885 OptionGroupValueObjectDisplay m_varobj_options
;
886 lldb::addr_t m_next_addr
;
887 lldb::addr_t m_prev_byte_size
;
888 OptionGroupFormat m_prev_format_options
;
889 OptionGroupReadMemory m_prev_memory_options
;
890 OptionGroupOutputFile m_prev_outfile_options
;
891 OptionGroupValueObjectDisplay m_prev_varobj_options
;
892 CompilerType m_prev_compiler_type
;
895 #define LLDB_OPTIONS_memory_find
896 #include "CommandOptions.inc"
898 // Find the specified data in memory
899 class CommandObjectMemoryFind
: public CommandObjectParsed
{
901 class OptionGroupFindMemory
: public OptionGroup
{
903 OptionGroupFindMemory() : OptionGroup(), m_count(1), m_offset(0) {}
905 ~OptionGroupFindMemory() override
= default;
907 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
908 return llvm::makeArrayRef(g_memory_find_options
);
911 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_value
,
912 ExecutionContext
*execution_context
) override
{
914 const int short_option
= g_memory_find_options
[option_idx
].short_option
;
916 switch (short_option
) {
918 m_expr
.SetValueFromString(option_value
);
922 m_string
.SetValueFromString(option_value
);
926 if (m_count
.SetValueFromString(option_value
).Fail())
927 error
.SetErrorString("unrecognized value for count");
931 if (m_offset
.SetValueFromString(option_value
).Fail())
932 error
.SetErrorString("unrecognized value for dump-offset");
936 llvm_unreachable("Unimplemented option");
941 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
947 OptionValueString m_expr
;
948 OptionValueString m_string
;
949 OptionValueUInt64 m_count
;
950 OptionValueUInt64 m_offset
;
953 CommandObjectMemoryFind(CommandInterpreter
&interpreter
)
954 : CommandObjectParsed(
955 interpreter
, "memory find",
956 "Find a value in the memory of the current target process.",
957 nullptr, eCommandRequiresProcess
| eCommandProcessMustBeLaunched
),
958 m_option_group(), m_memory_options() {
959 CommandArgumentEntry arg1
;
960 CommandArgumentEntry arg2
;
961 CommandArgumentData addr_arg
;
962 CommandArgumentData value_arg
;
964 // Define the first (and only) variant of this arg.
965 addr_arg
.arg_type
= eArgTypeAddressOrExpression
;
966 addr_arg
.arg_repetition
= eArgRepeatPlain
;
968 // There is only one variant this argument could be; put it into the
970 arg1
.push_back(addr_arg
);
972 // Define the first (and only) variant of this arg.
973 value_arg
.arg_type
= eArgTypeAddressOrExpression
;
974 value_arg
.arg_repetition
= eArgRepeatPlain
;
976 // There is only one variant this argument could be; put it into the
978 arg2
.push_back(value_arg
);
980 // Push the data for the first argument into the m_arguments vector.
981 m_arguments
.push_back(arg1
);
982 m_arguments
.push_back(arg2
);
984 m_option_group
.Append(&m_memory_options
);
985 m_option_group
.Finalize();
988 ~CommandObjectMemoryFind() override
= default;
990 Options
*GetOptions() override
{ return &m_option_group
; }
993 class ProcessMemoryIterator
{
995 ProcessMemoryIterator(ProcessSP process_sp
, lldb::addr_t base
)
996 : m_process_sp(process_sp
), m_base_addr(base
), m_is_valid(true) {
997 lldbassert(process_sp
.get() != nullptr);
1000 bool IsValid() { return m_is_valid
; }
1002 uint8_t operator[](lldb::addr_t offset
) {
1009 m_process_sp
->ReadMemory(m_base_addr
+ offset
, &retval
, 1, error
)) {
1018 ProcessSP m_process_sp
;
1019 lldb::addr_t m_base_addr
;
1022 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1023 // No need to check "process" for validity as eCommandRequiresProcess
1024 // ensures it is valid
1025 Process
*process
= m_exe_ctx
.GetProcessPtr();
1027 const size_t argc
= command
.GetArgumentCount();
1030 result
.AppendError("two addresses needed for memory find");
1035 lldb::addr_t low_addr
= OptionArgParser::ToAddress(
1036 &m_exe_ctx
, command
[0].ref(), LLDB_INVALID_ADDRESS
, &error
);
1037 if (low_addr
== LLDB_INVALID_ADDRESS
|| error
.Fail()) {
1038 result
.AppendError("invalid low address");
1041 lldb::addr_t high_addr
= OptionArgParser::ToAddress(
1042 &m_exe_ctx
, command
[1].ref(), LLDB_INVALID_ADDRESS
, &error
);
1043 if (high_addr
== LLDB_INVALID_ADDRESS
|| error
.Fail()) {
1044 result
.AppendError("invalid high address");
1048 if (high_addr
<= low_addr
) {
1050 "starting address must be smaller than ending address");
1054 lldb::addr_t found_location
= LLDB_INVALID_ADDRESS
;
1056 DataBufferHeap buffer
;
1058 if (m_memory_options
.m_string
.OptionWasSet())
1059 buffer
.CopyData(m_memory_options
.m_string
.GetStringValue());
1060 else if (m_memory_options
.m_expr
.OptionWasSet()) {
1061 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
1062 ValueObjectSP result_sp
;
1063 if ((eExpressionCompleted
==
1064 process
->GetTarget().EvaluateExpression(
1065 m_memory_options
.m_expr
.GetStringValue(), frame
, result_sp
)) &&
1067 uint64_t value
= result_sp
->GetValueAsUnsigned(0);
1068 llvm::Optional
<uint64_t> size
=
1069 result_sp
->GetCompilerType().GetByteSize(nullptr);
1074 uint8_t byte
= (uint8_t)value
;
1075 buffer
.CopyData(&byte
, 1);
1078 uint16_t word
= (uint16_t)value
;
1079 buffer
.CopyData(&word
, 2);
1082 uint32_t lword
= (uint32_t)value
;
1083 buffer
.CopyData(&lword
, 4);
1086 buffer
.CopyData(&value
, 8);
1092 result
.AppendError("unknown type. pass a string instead");
1096 "result size larger than 8 bytes. pass a string instead");
1101 "expression evaluation failed. pass a string instead");
1106 "please pass either a block of text, or an expression to evaluate.");
1110 size_t count
= m_memory_options
.m_count
.GetCurrentValue();
1111 found_location
= low_addr
;
1112 bool ever_found
= false;
1114 found_location
= FastSearch(found_location
, high_addr
, buffer
.GetBytes(),
1115 buffer
.GetByteSize());
1116 if (found_location
== LLDB_INVALID_ADDRESS
) {
1118 result
.AppendMessage("data not found within the range.\n");
1119 result
.SetStatus(lldb::eReturnStatusSuccessFinishNoResult
);
1121 result
.AppendMessage("no more matches within the range.\n");
1124 result
.AppendMessageWithFormat("data found at location: 0x%" PRIx64
"\n",
1127 DataBufferHeap
dumpbuffer(32, 0);
1128 process
->ReadMemory(
1129 found_location
+ m_memory_options
.m_offset
.GetCurrentValue(),
1130 dumpbuffer
.GetBytes(), dumpbuffer
.GetByteSize(), error
);
1131 if (!error
.Fail()) {
1132 DataExtractor
data(dumpbuffer
.GetBytes(), dumpbuffer
.GetByteSize(),
1133 process
->GetByteOrder(),
1134 process
->GetAddressByteSize());
1136 data
, &result
.GetOutputStream(), 0, lldb::eFormatBytesWithASCII
, 1,
1137 dumpbuffer
.GetByteSize(), 16,
1138 found_location
+ m_memory_options
.m_offset
.GetCurrentValue(), 0, 0);
1139 result
.GetOutputStream().EOL();
1147 result
.SetStatus(lldb::eReturnStatusSuccessFinishResult
);
1151 lldb::addr_t
FastSearch(lldb::addr_t low
, lldb::addr_t high
, uint8_t *buffer
,
1152 size_t buffer_size
) {
1153 const size_t region_size
= high
- low
;
1155 if (region_size
< buffer_size
)
1156 return LLDB_INVALID_ADDRESS
;
1158 std::vector
<size_t> bad_char_heuristic(256, buffer_size
);
1159 ProcessSP process_sp
= m_exe_ctx
.GetProcessSP();
1160 ProcessMemoryIterator
iterator(process_sp
, low
);
1162 for (size_t idx
= 0; idx
< buffer_size
- 1; idx
++) {
1163 decltype(bad_char_heuristic
)::size_type bcu_idx
= buffer
[idx
];
1164 bad_char_heuristic
[bcu_idx
] = buffer_size
- idx
- 1;
1166 for (size_t s
= 0; s
<= (region_size
- buffer_size
);) {
1167 int64_t j
= buffer_size
- 1;
1168 while (j
>= 0 && buffer
[j
] == iterator
[s
+ j
])
1173 s
+= bad_char_heuristic
[iterator
[s
+ buffer_size
- 1]];
1176 return LLDB_INVALID_ADDRESS
;
1179 OptionGroupOptions m_option_group
;
1180 OptionGroupFindMemory m_memory_options
;
1183 #define LLDB_OPTIONS_memory_write
1184 #include "CommandOptions.inc"
1186 // Write memory to the inferior process
1187 class CommandObjectMemoryWrite
: public CommandObjectParsed
{
1189 class OptionGroupWriteMemory
: public OptionGroup
{
1191 OptionGroupWriteMemory() : OptionGroup() {}
1193 ~OptionGroupWriteMemory() override
= default;
1195 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
1196 return llvm::makeArrayRef(g_memory_write_options
);
1199 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_value
,
1200 ExecutionContext
*execution_context
) override
{
1202 const int short_option
= g_memory_write_options
[option_idx
].short_option
;
1204 switch (short_option
) {
1206 m_infile
.SetFile(option_value
, FileSpec::Style::native
);
1207 FileSystem::Instance().Resolve(m_infile
);
1208 if (!FileSystem::Instance().Exists(m_infile
)) {
1210 error
.SetErrorStringWithFormat("input file does not exist: '%s'",
1211 option_value
.str().c_str());
1216 if (option_value
.getAsInteger(0, m_infile_offset
)) {
1217 m_infile_offset
= 0;
1218 error
.SetErrorStringWithFormat("invalid offset string '%s'",
1219 option_value
.str().c_str());
1224 llvm_unreachable("Unimplemented option");
1229 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
1231 m_infile_offset
= 0;
1235 off_t m_infile_offset
;
1238 CommandObjectMemoryWrite(CommandInterpreter
&interpreter
)
1239 : CommandObjectParsed(
1240 interpreter
, "memory write",
1241 "Write to the memory of the current target process.", nullptr,
1242 eCommandRequiresProcess
| eCommandProcessMustBeLaunched
),
1243 m_option_group(), m_format_options(eFormatBytes
, 1, UINT64_MAX
),
1244 m_memory_options() {
1245 CommandArgumentEntry arg1
;
1246 CommandArgumentEntry arg2
;
1247 CommandArgumentData addr_arg
;
1248 CommandArgumentData value_arg
;
1250 // Define the first (and only) variant of this arg.
1251 addr_arg
.arg_type
= eArgTypeAddress
;
1252 addr_arg
.arg_repetition
= eArgRepeatPlain
;
1254 // There is only one variant this argument could be; put it into the
1256 arg1
.push_back(addr_arg
);
1258 // Define the first (and only) variant of this arg.
1259 value_arg
.arg_type
= eArgTypeValue
;
1260 value_arg
.arg_repetition
= eArgRepeatPlus
;
1262 // There is only one variant this argument could be; put it into the
1264 arg2
.push_back(value_arg
);
1266 // Push the data for the first argument into the m_arguments vector.
1267 m_arguments
.push_back(arg1
);
1268 m_arguments
.push_back(arg2
);
1270 m_option_group
.Append(&m_format_options
,
1271 OptionGroupFormat::OPTION_GROUP_FORMAT
,
1273 m_option_group
.Append(&m_format_options
,
1274 OptionGroupFormat::OPTION_GROUP_SIZE
,
1275 LLDB_OPT_SET_1
| LLDB_OPT_SET_2
);
1276 m_option_group
.Append(&m_memory_options
, LLDB_OPT_SET_ALL
, LLDB_OPT_SET_2
);
1277 m_option_group
.Finalize();
1280 ~CommandObjectMemoryWrite() override
= default;
1282 Options
*GetOptions() override
{ return &m_option_group
; }
1284 bool UIntValueIsValidForSize(uint64_t uval64
, size_t total_byte_size
) {
1285 if (total_byte_size
> 8)
1288 if (total_byte_size
== 8)
1291 const uint64_t max
= ((uint64_t)1 << (uint64_t)(total_byte_size
* 8)) - 1;
1292 return uval64
<= max
;
1295 bool SIntValueIsValidForSize(int64_t sval64
, size_t total_byte_size
) {
1296 if (total_byte_size
> 8)
1299 if (total_byte_size
== 8)
1302 const int64_t max
= ((int64_t)1 << (uint64_t)(total_byte_size
* 8 - 1)) - 1;
1303 const int64_t min
= ~(max
);
1304 return min
<= sval64
&& sval64
<= max
;
1308 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1309 // No need to check "process" for validity as eCommandRequiresProcess
1310 // ensures it is valid
1311 Process
*process
= m_exe_ctx
.GetProcessPtr();
1313 const size_t argc
= command
.GetArgumentCount();
1315 if (m_memory_options
.m_infile
) {
1317 result
.AppendErrorWithFormat(
1318 "%s takes a destination address when writing file contents.\n",
1319 m_cmd_name
.c_str());
1320 result
.SetStatus(eReturnStatusFailed
);
1323 } else if (argc
< 2) {
1324 result
.AppendErrorWithFormat(
1325 "%s takes a destination address and at least one value.\n",
1326 m_cmd_name
.c_str());
1327 result
.SetStatus(eReturnStatusFailed
);
1331 StreamString
buffer(
1333 process
->GetTarget().GetArchitecture().GetAddressByteSize(),
1334 process
->GetTarget().GetArchitecture().GetByteOrder());
1336 OptionValueUInt64
&byte_size_value
= m_format_options
.GetByteSizeValue();
1337 size_t item_byte_size
= byte_size_value
.GetCurrentValue();
1340 lldb::addr_t addr
= OptionArgParser::ToAddress(
1341 &m_exe_ctx
, command
[0].ref(), LLDB_INVALID_ADDRESS
, &error
);
1343 if (addr
== LLDB_INVALID_ADDRESS
) {
1344 result
.AppendError("invalid address expression\n");
1345 result
.AppendError(error
.AsCString());
1346 result
.SetStatus(eReturnStatusFailed
);
1350 if (m_memory_options
.m_infile
) {
1351 size_t length
= SIZE_MAX
;
1352 if (item_byte_size
> 1)
1353 length
= item_byte_size
;
1354 auto data_sp
= FileSystem::Instance().CreateDataBuffer(
1355 m_memory_options
.m_infile
.GetPath(), length
,
1356 m_memory_options
.m_infile_offset
);
1358 length
= data_sp
->GetByteSize();
1361 size_t bytes_written
=
1362 process
->WriteMemory(addr
, data_sp
->GetBytes(), length
, error
);
1364 if (bytes_written
== length
) {
1365 // All bytes written
1366 result
.GetOutputStream().Printf(
1367 "%" PRIu64
" bytes were written to 0x%" PRIx64
"\n",
1368 (uint64_t)bytes_written
, addr
);
1369 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1370 } else if (bytes_written
> 0) {
1371 // Some byte written
1372 result
.GetOutputStream().Printf(
1373 "%" PRIu64
" bytes of %" PRIu64
1374 " requested were written to 0x%" PRIx64
"\n",
1375 (uint64_t)bytes_written
, (uint64_t)length
, addr
);
1376 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1378 result
.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1380 addr
, error
.AsCString());
1381 result
.SetStatus(eReturnStatusFailed
);
1385 result
.AppendErrorWithFormat("Unable to read contents of file.\n");
1386 result
.SetStatus(eReturnStatusFailed
);
1388 return result
.Succeeded();
1389 } else if (item_byte_size
== 0) {
1390 if (m_format_options
.GetFormat() == eFormatPointer
)
1391 item_byte_size
= buffer
.GetAddressByteSize();
1396 command
.Shift(); // shift off the address argument
1399 bool success
= false;
1400 for (auto &entry
: command
) {
1401 switch (m_format_options
.GetFormat()) {
1403 case eFormatFloat
: // TODO: add support for floats soon
1404 case eFormatCharPrintable
:
1405 case eFormatBytesWithASCII
:
1406 case eFormatComplex
:
1408 case eFormatUnicode8
:
1409 case eFormatUnicode16
:
1410 case eFormatUnicode32
:
1411 case eFormatVectorOfChar
:
1412 case eFormatVectorOfSInt8
:
1413 case eFormatVectorOfUInt8
:
1414 case eFormatVectorOfSInt16
:
1415 case eFormatVectorOfUInt16
:
1416 case eFormatVectorOfSInt32
:
1417 case eFormatVectorOfUInt32
:
1418 case eFormatVectorOfSInt64
:
1419 case eFormatVectorOfUInt64
:
1420 case eFormatVectorOfFloat16
:
1421 case eFormatVectorOfFloat32
:
1422 case eFormatVectorOfFloat64
:
1423 case eFormatVectorOfUInt128
:
1425 case eFormatComplexInteger
:
1426 case eFormatAddressInfo
:
1427 case eFormatHexFloat
:
1428 case eFormatInstruction
:
1430 result
.AppendError("unsupported format for writing memory");
1431 result
.SetStatus(eReturnStatusFailed
);
1434 case eFormatDefault
:
1437 case eFormatHexUppercase
:
1438 case eFormatPointer
: {
1440 // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
1441 // have to special case that:
1442 bool success
= false;
1443 if (entry
.ref().startswith("0x"))
1444 success
= !entry
.ref().getAsInteger(0, uval64
);
1446 success
= !entry
.ref().getAsInteger(16, uval64
);
1448 result
.AppendErrorWithFormat(
1449 "'%s' is not a valid hex string value.\n", entry
.c_str());
1450 result
.SetStatus(eReturnStatusFailed
);
1452 } else if (!UIntValueIsValidForSize(uval64
, item_byte_size
)) {
1453 result
.AppendErrorWithFormat("Value 0x%" PRIx64
1454 " is too large to fit in a %" PRIu64
1455 " byte unsigned integer value.\n",
1456 uval64
, (uint64_t)item_byte_size
);
1457 result
.SetStatus(eReturnStatusFailed
);
1460 buffer
.PutMaxHex64(uval64
, item_byte_size
);
1463 case eFormatBoolean
:
1464 uval64
= OptionArgParser::ToBoolean(entry
.ref(), false, &success
);
1466 result
.AppendErrorWithFormat(
1467 "'%s' is not a valid boolean string value.\n", entry
.c_str());
1468 result
.SetStatus(eReturnStatusFailed
);
1471 buffer
.PutMaxHex64(uval64
, item_byte_size
);
1475 if (entry
.ref().getAsInteger(2, uval64
)) {
1476 result
.AppendErrorWithFormat(
1477 "'%s' is not a valid binary string value.\n", entry
.c_str());
1478 result
.SetStatus(eReturnStatusFailed
);
1480 } else if (!UIntValueIsValidForSize(uval64
, item_byte_size
)) {
1481 result
.AppendErrorWithFormat("Value 0x%" PRIx64
1482 " is too large to fit in a %" PRIu64
1483 " byte unsigned integer value.\n",
1484 uval64
, (uint64_t)item_byte_size
);
1485 result
.SetStatus(eReturnStatusFailed
);
1488 buffer
.PutMaxHex64(uval64
, item_byte_size
);
1491 case eFormatCharArray
:
1493 case eFormatCString
: {
1494 if (entry
.ref().empty())
1497 size_t len
= entry
.ref().size();
1498 // Include the NULL for C strings...
1499 if (m_format_options
.GetFormat() == eFormatCString
)
1502 if (process
->WriteMemory(addr
, entry
.c_str(), len
, error
) == len
) {
1505 result
.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1507 addr
, error
.AsCString());
1508 result
.SetStatus(eReturnStatusFailed
);
1513 case eFormatDecimal
:
1514 if (entry
.ref().getAsInteger(0, sval64
)) {
1515 result
.AppendErrorWithFormat(
1516 "'%s' is not a valid signed decimal value.\n", entry
.c_str());
1517 result
.SetStatus(eReturnStatusFailed
);
1519 } else if (!SIntValueIsValidForSize(sval64
, item_byte_size
)) {
1520 result
.AppendErrorWithFormat(
1521 "Value %" PRIi64
" is too large or small to fit in a %" PRIu64
1522 " byte signed integer value.\n",
1523 sval64
, (uint64_t)item_byte_size
);
1524 result
.SetStatus(eReturnStatusFailed
);
1527 buffer
.PutMaxHex64(sval64
, item_byte_size
);
1530 case eFormatUnsigned
:
1532 if (!entry
.ref().getAsInteger(0, uval64
)) {
1533 result
.AppendErrorWithFormat(
1534 "'%s' is not a valid unsigned decimal string value.\n",
1536 result
.SetStatus(eReturnStatusFailed
);
1538 } else if (!UIntValueIsValidForSize(uval64
, item_byte_size
)) {
1539 result
.AppendErrorWithFormat("Value %" PRIu64
1540 " is too large to fit in a %" PRIu64
1541 " byte unsigned integer value.\n",
1542 uval64
, (uint64_t)item_byte_size
);
1543 result
.SetStatus(eReturnStatusFailed
);
1546 buffer
.PutMaxHex64(uval64
, item_byte_size
);
1550 if (entry
.ref().getAsInteger(8, uval64
)) {
1551 result
.AppendErrorWithFormat(
1552 "'%s' is not a valid octal string value.\n", entry
.c_str());
1553 result
.SetStatus(eReturnStatusFailed
);
1555 } else if (!UIntValueIsValidForSize(uval64
, item_byte_size
)) {
1556 result
.AppendErrorWithFormat("Value %" PRIo64
1557 " is too large to fit in a %" PRIu64
1558 " byte unsigned integer value.\n",
1559 uval64
, (uint64_t)item_byte_size
);
1560 result
.SetStatus(eReturnStatusFailed
);
1563 buffer
.PutMaxHex64(uval64
, item_byte_size
);
1568 if (!buffer
.GetString().empty()) {
1570 if (process
->WriteMemory(addr
, buffer
.GetString().data(),
1571 buffer
.GetString().size(),
1572 error
) == buffer
.GetString().size())
1575 result
.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1577 addr
, error
.AsCString());
1578 result
.SetStatus(eReturnStatusFailed
);
1585 OptionGroupOptions m_option_group
;
1586 OptionGroupFormat m_format_options
;
1587 OptionGroupWriteMemory m_memory_options
;
1590 // Get malloc/free history of a memory address.
1591 class CommandObjectMemoryHistory
: public CommandObjectParsed
{
1593 CommandObjectMemoryHistory(CommandInterpreter
&interpreter
)
1594 : CommandObjectParsed(interpreter
, "memory history",
1595 "Print recorded stack traces for "
1596 "allocation/deallocation events "
1597 "associated with an address.",
1599 eCommandRequiresTarget
| eCommandRequiresProcess
|
1600 eCommandProcessMustBePaused
|
1601 eCommandProcessMustBeLaunched
) {
1602 CommandArgumentEntry arg1
;
1603 CommandArgumentData addr_arg
;
1605 // Define the first (and only) variant of this arg.
1606 addr_arg
.arg_type
= eArgTypeAddress
;
1607 addr_arg
.arg_repetition
= eArgRepeatPlain
;
1609 // There is only one variant this argument could be; put it into the
1611 arg1
.push_back(addr_arg
);
1613 // Push the data for the first argument into the m_arguments vector.
1614 m_arguments
.push_back(arg1
);
1617 ~CommandObjectMemoryHistory() override
= default;
1619 const char *GetRepeatCommand(Args
¤t_command_args
,
1620 uint32_t index
) override
{
1621 return m_cmd_name
.c_str();
1625 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1626 const size_t argc
= command
.GetArgumentCount();
1628 if (argc
== 0 || argc
> 1) {
1629 result
.AppendErrorWithFormat("%s takes an address expression",
1630 m_cmd_name
.c_str());
1631 result
.SetStatus(eReturnStatusFailed
);
1636 lldb::addr_t addr
= OptionArgParser::ToAddress(
1637 &m_exe_ctx
, command
[0].ref(), LLDB_INVALID_ADDRESS
, &error
);
1639 if (addr
== LLDB_INVALID_ADDRESS
) {
1640 result
.AppendError("invalid address expression");
1641 result
.AppendError(error
.AsCString());
1642 result
.SetStatus(eReturnStatusFailed
);
1646 Stream
*output_stream
= &result
.GetOutputStream();
1648 const ProcessSP
&process_sp
= m_exe_ctx
.GetProcessSP();
1649 const MemoryHistorySP
&memory_history
=
1650 MemoryHistory::FindPlugin(process_sp
);
1652 if (!memory_history
) {
1653 result
.AppendError("no available memory history provider");
1654 result
.SetStatus(eReturnStatusFailed
);
1658 HistoryThreads thread_list
= memory_history
->GetHistoryThreads(addr
);
1660 const bool stop_format
= false;
1661 for (auto thread
: thread_list
) {
1662 thread
->GetStatus(*output_stream
, 0, UINT32_MAX
, 0, stop_format
);
1665 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1671 // CommandObjectMemoryRegion
1672 #pragma mark CommandObjectMemoryRegion
1674 class CommandObjectMemoryRegion
: public CommandObjectParsed
{
1676 CommandObjectMemoryRegion(CommandInterpreter
&interpreter
)
1677 : CommandObjectParsed(interpreter
, "memory region",
1678 "Get information on the memory region containing "
1679 "an address in the current target process.",
1680 "memory region ADDR",
1681 eCommandRequiresProcess
| eCommandTryTargetAPILock
|
1682 eCommandProcessMustBeLaunched
),
1683 m_prev_end_addr(LLDB_INVALID_ADDRESS
) {}
1685 ~CommandObjectMemoryRegion() override
= default;
1688 bool DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
1689 ProcessSP process_sp
= m_exe_ctx
.GetProcessSP();
1692 lldb::addr_t load_addr
= m_prev_end_addr
;
1693 m_prev_end_addr
= LLDB_INVALID_ADDRESS
;
1695 const size_t argc
= command
.GetArgumentCount();
1696 if (argc
> 1 || (argc
== 0 && load_addr
== LLDB_INVALID_ADDRESS
)) {
1697 result
.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n",
1698 m_cmd_name
.c_str(), m_cmd_syntax
.c_str());
1699 result
.SetStatus(eReturnStatusFailed
);
1701 if (command
.GetArgumentCount() == 1) {
1702 auto load_addr_str
= command
[0].ref();
1703 load_addr
= OptionArgParser::ToAddress(&m_exe_ctx
, load_addr_str
,
1704 LLDB_INVALID_ADDRESS
, &error
);
1705 if (error
.Fail() || load_addr
== LLDB_INVALID_ADDRESS
) {
1706 result
.AppendErrorWithFormat(
1707 "invalid address argument \"%s\": %s\n", command
[0].c_str(),
1709 result
.SetStatus(eReturnStatusFailed
);
1713 lldb_private::MemoryRegionInfo range_info
;
1714 error
= process_sp
->GetMemoryRegionInfo(load_addr
, range_info
);
1715 if (error
.Success()) {
1716 lldb_private::Address addr
;
1717 ConstString name
= range_info
.GetName();
1718 ConstString section_name
;
1719 if (process_sp
->GetTarget().ResolveLoadAddress(load_addr
, addr
)) {
1720 SectionSP
section_sp(addr
.GetSection());
1722 // Got the top most section, not the deepest section
1723 while (section_sp
->GetParent())
1724 section_sp
= section_sp
->GetParent();
1725 section_name
= section_sp
->GetName();
1728 result
.AppendMessageWithFormatv(
1729 "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}\n",
1730 range_info
.GetRange().GetRangeBase(),
1731 range_info
.GetRange().GetRangeEnd(), range_info
.GetReadable(),
1732 range_info
.GetWritable(), range_info
.GetExecutable(),
1733 name
? " " : "", name
, section_name
? " " : "", section_name
);
1734 m_prev_end_addr
= range_info
.GetRange().GetRangeEnd();
1735 result
.SetStatus(eReturnStatusSuccessFinishResult
);
1737 result
.SetStatus(eReturnStatusFailed
);
1738 result
.AppendErrorWithFormat("%s\n", error
.AsCString());
1742 m_prev_end_addr
= LLDB_INVALID_ADDRESS
;
1743 result
.AppendError("invalid process");
1744 result
.SetStatus(eReturnStatusFailed
);
1746 return result
.Succeeded();
1749 const char *GetRepeatCommand(Args
¤t_command_args
,
1750 uint32_t index
) override
{
1751 // If we repeat this command, repeat it without any arguments so we can
1752 // show the next memory range
1753 return m_cmd_name
.c_str();
1756 lldb::addr_t m_prev_end_addr
;
1759 // CommandObjectMemory
1761 CommandObjectMemory::CommandObjectMemory(CommandInterpreter
&interpreter
)
1762 : CommandObjectMultiword(
1763 interpreter
, "memory",
1764 "Commands for operating on memory in the current target process.",
1765 "memory <subcommand> [<subcommand-options>]") {
1766 LoadSubCommand("find",
1767 CommandObjectSP(new CommandObjectMemoryFind(interpreter
)));
1768 LoadSubCommand("read",
1769 CommandObjectSP(new CommandObjectMemoryRead(interpreter
)));
1770 LoadSubCommand("write",
1771 CommandObjectSP(new CommandObjectMemoryWrite(interpreter
)));
1772 LoadSubCommand("history",
1773 CommandObjectSP(new CommandObjectMemoryHistory(interpreter
)));
1774 LoadSubCommand("region",
1775 CommandObjectSP(new CommandObjectMemoryRegion(interpreter
)));
1778 CommandObjectMemory::~CommandObjectMemory() = default;