1 //===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
12 #include "CommandObjectMemory.h"
18 // Other libraries and framework includes
20 #include "lldb/Core/DataBufferHeap.h"
21 #include "lldb/Core/DataExtractor.h"
22 #include "lldb/Core/Debugger.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/StreamString.h"
25 #include "lldb/Core/ValueObjectMemory.h"
26 #include "lldb/DataFormatters/ValueObjectPrinter.h"
27 #include "lldb/Interpreter/Args.h"
28 #include "lldb/Interpreter/CommandReturnObject.h"
29 #include "lldb/Interpreter/CommandInterpreter.h"
30 #include "lldb/Interpreter/Options.h"
31 #include "lldb/Interpreter/OptionGroupFormat.h"
32 #include "lldb/Interpreter/OptionGroupOutputFile.h"
33 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
34 #include "lldb/Interpreter/OptionValueString.h"
35 #include "lldb/Symbol/TypeList.h"
36 #include "lldb/Target/MemoryHistory.h"
37 #include "lldb/Target/Process.h"
38 #include "lldb/Target/StackFrame.h"
39 #include "lldb/Target/Thread.h"
42 using namespace lldb_private;
44 static OptionDefinition
47 { LLDB_OPT_SET_1, false, "num-per-line" ,'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
48 { LLDB_OPT_SET_2, false, "binary" ,'b', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
49 { LLDB_OPT_SET_3, true , "type" ,'t', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
52 LLDB_OPT_SET_3, false, "force" ,'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
57 class OptionGroupReadMemory : public OptionGroup
61 OptionGroupReadMemory () :
63 m_output_as_binary (false),
69 ~OptionGroupReadMemory ()
77 return sizeof (g_option_table) / sizeof (OptionDefinition);
80 virtual const OptionDefinition*
83 return g_option_table;
87 SetOptionValue (CommandInterpreter &interpreter,
89 const char *option_arg)
92 const int short_option = g_option_table[option_idx].short_option;
97 error = m_num_per_line.SetValueFromCString (option_arg);
98 if (m_num_per_line.GetCurrentValue() == 0)
99 error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
103 m_output_as_binary = true;
107 error = m_view_as_type.SetValueFromCString (option_arg);
115 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
122 OptionParsingStarting (CommandInterpreter &interpreter)
124 m_num_per_line.Clear();
125 m_output_as_binary = false;
126 m_view_as_type.Clear();
131 FinalizeSettings (Target *target, OptionGroupFormat& format_options)
134 OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
135 OptionValueUInt64 &count_value = format_options.GetCountValue();
136 const bool byte_size_option_set = byte_size_value.OptionWasSet();
137 const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
138 const bool count_option_set = format_options.GetCountValue().OptionWasSet();
140 switch (format_options.GetFormat())
146 if (!byte_size_option_set)
148 if (!num_per_line_option_set)
150 if (!count_option_set)
151 format_options.GetCountValue() = 8;
157 case eFormatInstruction:
158 if (count_option_set)
159 byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
163 case eFormatAddressInfo:
164 if (!byte_size_option_set)
165 byte_size_value = target->GetArchitecture().GetAddressByteSize();
167 if (!count_option_set)
168 format_options.GetCountValue() = 8;
172 byte_size_value = target->GetArchitecture().GetAddressByteSize();
173 if (!num_per_line_option_set)
175 if (!count_option_set)
176 format_options.GetCountValue() = 8;
184 case eFormatUnicode16:
185 case eFormatUnicode32:
186 case eFormatUnsigned:
187 case eFormatHexFloat:
188 if (!byte_size_option_set)
190 if (!num_per_line_option_set)
192 if (!count_option_set)
193 format_options.GetCountValue() = 8;
197 case eFormatBytesWithASCII:
198 if (byte_size_option_set)
200 if (byte_size_value > 1)
201 error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
202 "\tconsider using a different display format or don't specify the byte size",
203 byte_size_value.GetCurrentValue());
207 if (!num_per_line_option_set)
209 if (!count_option_set)
210 format_options.GetCountValue() = 32;
212 case eFormatCharArray:
214 case eFormatCharPrintable:
215 if (!byte_size_option_set)
217 if (!num_per_line_option_set)
219 if (!count_option_set)
220 format_options.GetCountValue() = 64;
223 if (!byte_size_option_set)
225 if (!num_per_line_option_set)
227 if (!count_option_set)
228 format_options.GetCountValue() = 8;
230 case eFormatComplexInteger:
231 if (!byte_size_option_set)
233 if (!num_per_line_option_set)
235 if (!count_option_set)
236 format_options.GetCountValue() = 8;
239 if (!byte_size_option_set)
241 if (!num_per_line_option_set)
243 switch (byte_size_value)
260 if (!count_option_set)
264 case eFormatVectorOfChar:
265 case eFormatVectorOfSInt8:
266 case eFormatVectorOfUInt8:
267 case eFormatVectorOfSInt16:
268 case eFormatVectorOfUInt16:
269 case eFormatVectorOfSInt32:
270 case eFormatVectorOfUInt32:
271 case eFormatVectorOfSInt64:
272 case eFormatVectorOfUInt64:
273 case eFormatVectorOfFloat32:
274 case eFormatVectorOfFloat64:
275 case eFormatVectorOfUInt128:
276 if (!byte_size_option_set)
277 byte_size_value = 128;
278 if (!num_per_line_option_set)
280 if (!count_option_set)
288 AnyOptionWasSet () const
290 return m_num_per_line.OptionWasSet() ||
291 m_output_as_binary ||
292 m_view_as_type.OptionWasSet();
295 OptionValueUInt64 m_num_per_line;
296 bool m_output_as_binary;
297 OptionValueString m_view_as_type;
303 //----------------------------------------------------------------------
304 // Read memory from the inferior process
305 //----------------------------------------------------------------------
306 class CommandObjectMemoryRead : public CommandObjectParsed
310 CommandObjectMemoryRead (CommandInterpreter &interpreter) :
311 CommandObjectParsed (interpreter,
313 "Read from the memory of the process being debugged.",
315 eFlagRequiresTarget | eFlagProcessMustBePaused),
316 m_option_group (interpreter),
317 m_format_options (eFormatBytesWithASCII, 1, 8),
319 m_outfile_options (),
321 m_next_addr(LLDB_INVALID_ADDRESS),
323 m_prev_format_options (eFormatBytesWithASCII, 1, 8),
324 m_prev_memory_options (),
325 m_prev_outfile_options (),
326 m_prev_varobj_options()
328 CommandArgumentEntry arg1;
329 CommandArgumentEntry arg2;
330 CommandArgumentData start_addr_arg;
331 CommandArgumentData end_addr_arg;
333 // Define the first (and only) variant of this arg.
334 start_addr_arg.arg_type = eArgTypeAddressOrExpression;
335 start_addr_arg.arg_repetition = eArgRepeatPlain;
337 // There is only one variant this argument could be; put it into the argument entry.
338 arg1.push_back (start_addr_arg);
340 // Define the first (and only) variant of this arg.
341 end_addr_arg.arg_type = eArgTypeAddressOrExpression;
342 end_addr_arg.arg_repetition = eArgRepeatOptional;
344 // There is only one variant this argument could be; put it into the argument entry.
345 arg2.push_back (end_addr_arg);
347 // Push the data for the first argument into the m_arguments vector.
348 m_arguments.push_back (arg1);
349 m_arguments.push_back (arg2);
351 // Add the "--format" and "--count" options to group 1 and 3
352 m_option_group.Append (&m_format_options,
353 OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
354 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
355 m_option_group.Append (&m_format_options,
356 OptionGroupFormat::OPTION_GROUP_GDB_FMT,
357 LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
358 // Add the "--size" option to group 1 and 2
359 m_option_group.Append (&m_format_options,
360 OptionGroupFormat::OPTION_GROUP_SIZE,
361 LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
362 m_option_group.Append (&m_memory_options);
363 m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
364 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
365 m_option_group.Finalize();
369 ~CommandObjectMemoryRead ()
376 return &m_option_group;
379 virtual const char *GetRepeatCommand (Args ¤t_command_args, uint32_t index)
381 return m_cmd_name.c_str();
386 DoExecute (Args& command, CommandReturnObject &result)
388 // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
389 Target *target = m_exe_ctx.GetTargetPtr();
391 const size_t argc = command.GetArgumentCount();
393 if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
395 result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
396 result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
397 result.SetStatus(eReturnStatusFailed);
401 ClangASTType clang_ast_type;
404 const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
405 if (view_as_type_cstr && view_as_type_cstr[0])
407 // We are viewing memory as a type
410 const bool exact_match = false;
412 uint32_t reference_count = 0;
413 uint32_t pointer_count = 0;
416 #define ALL_KEYWORDS \
418 KEYWORD("volatile") \
419 KEYWORD("restrict") \
424 #define KEYWORD(s) s,
425 static const char *g_keywords[] =
431 #define KEYWORD(s) (sizeof(s) - 1),
432 static const int g_keyword_lengths[] =
440 static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
441 std::string type_str(view_as_type_cstr);
443 // Remove all instances of g_keywords that are followed by spaces
444 for (size_t i = 0; i < g_num_keywords; ++i)
446 const char *keyword = g_keywords[i];
447 int keyword_len = g_keyword_lengths[i];
450 while ((idx = type_str.find (keyword, idx)) != std::string::npos)
452 if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
454 type_str.erase(idx, keyword_len+1);
463 bool done = type_str.empty();
465 idx = type_str.find_first_not_of (" \t");
466 if (idx > 0 && idx != std::string::npos)
467 type_str.erase (0, idx);
470 // Strip trailing spaces
471 if (type_str.empty())
475 switch (type_str[type_str.size()-1])
482 type_str.erase(type_str.size()-1);
486 if (reference_count == 0)
489 type_str.erase(type_str.size()-1);
493 result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
494 result.SetStatus(eReturnStatusFailed);
506 ConstString lookup_type_name(type_str.c_str());
507 StackFrame *frame = m_exe_ctx.GetFramePtr();
510 sc = frame->GetSymbolContext (eSymbolContextModule);
513 sc.module_sp->FindTypes (sc,
520 if (type_list.GetSize() == 0)
522 target->GetImages().FindTypes (sc,
529 if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$')
531 clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
534 clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
538 if (clang_ast_type.IsValid() == false)
540 if (type_list.GetSize() == 0)
542 result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
543 lookup_type_name.GetCString(),
545 result.SetStatus(eReturnStatusFailed);
550 TypeSP type_sp (type_list.GetTypeAtIndex(0));
551 clang_ast_type = type_sp->GetClangFullType();
555 while (pointer_count > 0)
557 ClangASTType pointer_type = clang_ast_type.GetPointerType();
558 if (pointer_type.IsValid())
559 clang_ast_type = pointer_type;
562 result.AppendError ("unable make a pointer type\n");
563 result.SetStatus(eReturnStatusFailed);
569 m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize();
571 if (m_format_options.GetByteSizeValue() == 0)
573 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
575 result.SetStatus(eReturnStatusFailed);
579 if (!m_format_options.GetCountValue().OptionWasSet())
580 m_format_options.GetCountValue() = 1;
584 error = m_memory_options.FinalizeSettings (target, m_format_options);
587 // Look for invalid combinations of settings
590 result.AppendError(error.AsCString());
591 result.SetStatus(eReturnStatusFailed);
596 size_t total_byte_size = 0;
599 // Use the last address and byte size and all options as they were
600 // if no options have been set
602 total_byte_size = m_prev_byte_size;
603 clang_ast_type = m_prev_clang_ast_type;
604 if (!m_format_options.AnyOptionWasSet() &&
605 !m_memory_options.AnyOptionWasSet() &&
606 !m_outfile_options.AnyOptionWasSet() &&
607 !m_varobj_options.AnyOptionWasSet())
609 m_format_options = m_prev_format_options;
610 m_memory_options = m_prev_memory_options;
611 m_outfile_options = m_prev_outfile_options;
612 m_varobj_options = m_prev_varobj_options;
616 size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
618 // TODO For non-8-bit byte addressable architectures this needs to be
619 // revisited to fully support all lldb's range of formatting options.
620 // Furthermore code memory reads (for those architectures) will not
621 // be correctly formatted even w/o formatting options.
622 size_t item_byte_size =
623 target->GetArchitecture().GetDataByteSize() > 1 ?
624 target->GetArchitecture().GetDataByteSize() :
625 m_format_options.GetByteSizeValue().GetCurrentValue();
627 const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
629 if (total_byte_size == 0)
631 total_byte_size = item_count * item_byte_size;
632 if (total_byte_size == 0)
633 total_byte_size = 32;
637 addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
639 if (addr == LLDB_INVALID_ADDRESS)
641 result.AppendError("invalid start address expression.");
642 result.AppendError(error.AsCString());
643 result.SetStatus(eReturnStatusFailed);
649 lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
650 if (end_addr == LLDB_INVALID_ADDRESS)
652 result.AppendError("invalid end address expression.");
653 result.AppendError(error.AsCString());
654 result.SetStatus(eReturnStatusFailed);
657 else if (end_addr <= addr)
659 result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
660 result.SetStatus(eReturnStatusFailed);
663 else if (m_format_options.GetCountValue().OptionWasSet())
665 result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %" PRIu64 "), not both.\n", end_addr, (uint64_t)item_count);
666 result.SetStatus(eReturnStatusFailed);
670 total_byte_size = end_addr - addr;
671 item_count = total_byte_size / item_byte_size;
674 uint32_t max_unforced_size = target->GetMaximumMemReadSize();
676 if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
678 result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
679 result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
680 result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
684 DataBufferSP data_sp;
685 size_t bytes_read = 0;
686 if (clang_ast_type.GetOpaqueQualType())
688 // Make sure we don't display our type as ASCII bytes like the default memory read
689 if (m_format_options.GetFormatValue().OptionWasSet() == false)
690 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
692 bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue();
694 else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
696 data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
697 if (data_sp->GetBytes() == NULL)
699 result.AppendErrorWithFormat ("can't allocate 0x%" PRIx32 " bytes for the memory read buffer, specify a smaller size to read", (uint32_t)total_byte_size);
700 result.SetStatus(eReturnStatusFailed);
704 Address address(addr, NULL);
705 bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
708 const char *error_cstr = error.AsCString();
709 if (error_cstr && error_cstr[0])
711 result.AppendError(error_cstr);
715 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
717 result.SetStatus(eReturnStatusFailed);
721 if (bytes_read < total_byte_size)
722 result.AppendWarningWithFormat("Not all bytes (%" PRIu64 "/%" PRIu64 ") were able to be read from 0x%" PRIx64 ".\n", (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
726 // we treat c-strings as a special case because they do not have a fixed size
727 if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
728 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
730 item_byte_size = target->GetMaximumSizeOfStringSummary();
731 if (!m_format_options.GetCountValue().OptionWasSet())
733 data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
734 if (data_sp->GetBytes() == NULL)
736 result.AppendErrorWithFormat ("can't allocate 0x%" PRIx64 " bytes for the memory read buffer, specify a smaller size to read", (uint64_t)((item_byte_size+1) * item_count));
737 result.SetStatus(eReturnStatusFailed);
740 uint8_t *data_ptr = data_sp->GetBytes();
741 auto data_addr = addr;
742 auto count = item_count;
744 while (item_count < count)
747 buffer.resize(item_byte_size+1,0);
749 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
752 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
753 result.SetStatus(eReturnStatusFailed);
756 if (item_byte_size == read)
758 result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
761 read+=1; // account for final NULL byte
762 memcpy(data_ptr, &buffer[0], read);
766 item_count++; // if we break early we know we only read item_count strings
768 data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
771 m_next_addr = addr + bytes_read;
772 m_prev_byte_size = bytes_read;
773 m_prev_format_options = m_format_options;
774 m_prev_memory_options = m_memory_options;
775 m_prev_outfile_options = m_outfile_options;
776 m_prev_varobj_options = m_varobj_options;
777 m_prev_clang_ast_type = clang_ast_type;
779 StreamFile outfile_stream;
780 Stream *output_stream = NULL;
781 const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
785 outfile_spec.GetPath (path, sizeof(path));
787 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
788 const bool append = m_outfile_options.GetAppend().GetCurrentValue();
790 open_options |= File::eOpenOptionAppend;
792 if (outfile_stream.GetFile ().Open (path, open_options).Success())
794 if (m_memory_options.m_output_as_binary)
796 const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
797 if (bytes_written > 0)
799 result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
801 append ? "appended" : "written",
807 result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
808 result.SetStatus(eReturnStatusFailed);
814 // We are going to write ASCII to the file just point the
815 // output_stream to our outfile_stream...
816 output_stream = &outfile_stream;
821 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
822 result.SetStatus(eReturnStatusFailed);
828 output_stream = &result.GetOutputStream();
832 ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
833 if (clang_ast_type.GetOpaqueQualType())
835 for (uint32_t i = 0; i<item_count; ++i)
837 addr_t item_addr = addr + (i * item_byte_size);
838 Address address (item_addr);
839 StreamString name_strm;
840 name_strm.Printf ("0x%" PRIx64, item_addr);
841 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
842 name_strm.GetString().c_str(),
847 Format format = m_format_options.GetFormat();
848 if (format != eFormatDefault)
849 valobj_sp->SetFormat (format);
851 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format));
853 valobj_sp->Dump(*output_stream,options);
857 result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
859 name_strm.GetString().c_str());
860 result.SetStatus(eReturnStatusFailed);
867 result.SetStatus(eReturnStatusSuccessFinishResult);
868 DataExtractor data (data_sp,
869 target->GetArchitecture().GetByteOrder(),
870 target->GetArchitecture().GetAddressByteSize(),
871 target->GetArchitecture().GetDataByteSize());
873 Format format = m_format_options.GetFormat();
874 if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
875 && (item_byte_size != 1))
877 // if a count was not passed, or it is 1
878 if (m_format_options.GetCountValue().OptionWasSet() == false || item_count == 1)
880 // this turns requests such as
881 // memory read -fc -s10 -c1 *charPtrPtr
882 // which make no sense (what is a char of size 10?)
883 // into a request for fetching 10 chars of size 1 from the same memory location
884 format = eFormatCharArray;
885 item_count = item_byte_size;
890 // here we passed a count, and it was not 1
891 // so we have a byte_size and a count
892 // we could well multiply those, but instead let's just fail
893 result.AppendErrorWithFormat("reading memory as characters of size %" PRIu64 " is not supported", (uint64_t)item_byte_size);
894 result.SetStatus(eReturnStatusFailed);
899 assert (output_stream);
900 size_t bytes_dumped = data.Dump (output_stream,
905 num_per_line / target->GetArchitecture().GetDataByteSize(),
910 m_next_addr = addr + bytes_dumped;
911 output_stream->EOL();
915 OptionGroupOptions m_option_group;
916 OptionGroupFormat m_format_options;
917 OptionGroupReadMemory m_memory_options;
918 OptionGroupOutputFile m_outfile_options;
919 OptionGroupValueObjectDisplay m_varobj_options;
920 lldb::addr_t m_next_addr;
921 lldb::addr_t m_prev_byte_size;
922 OptionGroupFormat m_prev_format_options;
923 OptionGroupReadMemory m_prev_memory_options;
924 OptionGroupOutputFile m_prev_outfile_options;
925 OptionGroupValueObjectDisplay m_prev_varobj_options;
926 ClangASTType m_prev_clang_ast_type;
930 g_memory_find_option_table[] =
932 { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
933 { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "Use text to find a byte pattern."},
934 { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "How many times to perform the search."},
935 { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "dump-offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."},
938 //----------------------------------------------------------------------
939 // Find the specified data in memory
940 //----------------------------------------------------------------------
941 class CommandObjectMemoryFind : public CommandObjectParsed
945 class OptionGroupFindMemory : public OptionGroup
948 OptionGroupFindMemory () :
956 ~OptionGroupFindMemory ()
963 return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition);
966 virtual const OptionDefinition*
969 return g_memory_find_option_table;
973 SetOptionValue (CommandInterpreter &interpreter,
975 const char *option_arg)
978 const int short_option = g_memory_find_option_table[option_idx].short_option;
980 switch (short_option)
983 m_expr.SetValueFromCString(option_arg);
987 m_string.SetValueFromCString(option_arg);
991 if (m_count.SetValueFromCString(option_arg).Fail())
992 error.SetErrorString("unrecognized value for count");
996 if (m_offset.SetValueFromCString(option_arg).Fail())
997 error.SetErrorString("unrecognized value for dump-offset");
1001 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
1008 OptionParsingStarting (CommandInterpreter &interpreter)
1015 OptionValueString m_expr;
1016 OptionValueString m_string;
1017 OptionValueUInt64 m_count;
1018 OptionValueUInt64 m_offset;
1021 CommandObjectMemoryFind (CommandInterpreter &interpreter) :
1022 CommandObjectParsed (interpreter,
1024 "Find a value in the memory of the process being debugged.",
1026 eFlagRequiresProcess | eFlagProcessMustBeLaunched),
1027 m_option_group (interpreter),
1030 CommandArgumentEntry arg1;
1031 CommandArgumentEntry arg2;
1032 CommandArgumentData addr_arg;
1033 CommandArgumentData value_arg;
1035 // Define the first (and only) variant of this arg.
1036 addr_arg.arg_type = eArgTypeAddress;
1037 addr_arg.arg_repetition = eArgRepeatPlain;
1039 // There is only one variant this argument could be; put it into the argument entry.
1040 arg1.push_back (addr_arg);
1042 // Define the first (and only) variant of this arg.
1043 value_arg.arg_type = eArgTypeValue;
1044 value_arg.arg_repetition = eArgRepeatPlus;
1046 // There is only one variant this argument could be; put it into the argument entry.
1047 arg2.push_back (value_arg);
1049 // Push the data for the first argument into the m_arguments vector.
1050 m_arguments.push_back (arg1);
1051 m_arguments.push_back (arg2);
1053 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1054 m_option_group.Finalize();
1058 ~CommandObjectMemoryFind ()
1065 return &m_option_group;
1070 DoExecute (Args& command, CommandReturnObject &result)
1072 // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1073 Process *process = m_exe_ctx.GetProcessPtr();
1075 const size_t argc = command.GetArgumentCount();
1079 result.AppendError("two addresses needed for memory find");
1084 lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error);
1085 if (low_addr == LLDB_INVALID_ADDRESS || error.Fail())
1087 result.AppendError("invalid low address");
1090 lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error);
1091 if (high_addr == LLDB_INVALID_ADDRESS || error.Fail())
1093 result.AppendError("invalid high address");
1097 if (high_addr <= low_addr)
1099 result.AppendError("starting address must be smaller than ending address");
1103 lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1105 DataBufferHeap buffer;
1107 if (m_memory_options.m_string.OptionWasSet())
1108 buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue()));
1109 else if (m_memory_options.m_expr.OptionWasSet())
1111 StackFrame* frame = m_exe_ctx.GetFramePtr();
1112 ValueObjectSP result_sp;
1113 if (process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp) && result_sp.get())
1115 uint64_t value = result_sp->GetValueAsUnsigned(0);
1116 switch (result_sp->GetClangType().GetByteSize())
1119 uint8_t byte = (uint8_t)value;
1120 buffer.CopyData(&byte,1);
1124 uint16_t word = (uint16_t)value;
1125 buffer.CopyData(&word,2);
1129 uint32_t lword = (uint32_t)value;
1130 buffer.CopyData(&lword,4);
1134 buffer.CopyData(&value, 8);
1141 result.AppendError("unknown type. pass a string instead");
1144 result.AppendError("do not know how to deal with larger than 8 byte result types. pass a string instead");
1150 result.AppendError("expression evaluation failed. pass a string instead?");
1156 result.AppendError("please pass either a block of text, or an expression to evaluate.");
1160 size_t count = m_memory_options.m_count.GetCurrentValue();
1161 found_location = low_addr;
1162 bool ever_found = false;
1165 found_location = Search(found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
1166 if (found_location == LLDB_INVALID_ADDRESS)
1170 result.AppendMessage("Your data was not found within the range.\n");
1171 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1174 result.AppendMessage("No more matches found within the range.\n");
1177 result.AppendMessageWithFormat("Your data was found at location: 0x%" PRIx64 "\n", found_location);
1179 DataBufferHeap dumpbuffer(32,0);
1180 process->ReadMemory(found_location+m_memory_options.m_offset.GetCurrentValue(), dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
1183 DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), process->GetByteOrder(), process->GetAddressByteSize());
1184 data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1, dumpbuffer.GetByteSize(), 16, found_location+m_memory_options.m_offset.GetCurrentValue(), 0, 0);
1185 result.GetOutputStream().EOL();
1193 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1198 Search (lldb::addr_t low,
1203 Process *process = m_exe_ctx.GetProcessPtr();
1204 DataBufferHeap heap(buffer_size, 0);
1205 lldb::addr_t fictional_ptr = low;
1206 for (auto ptr = low;
1211 if (ptr == low || buffer_size == 1)
1212 process->ReadMemory(ptr, heap.GetBytes(), buffer_size, error);
1215 memmove(heap.GetBytes(), heap.GetBytes()+1, buffer_size-1);
1216 process->ReadMemory(ptr, heap.GetBytes()+buffer_size-1, 1, error);
1219 return LLDB_INVALID_ADDRESS;
1220 if (memcmp(heap.GetBytes(), buffer, buffer_size) == 0)
1221 return fictional_ptr;
1227 return LLDB_INVALID_ADDRESS;
1230 OptionGroupOptions m_option_group;
1231 OptionGroupFindMemory m_memory_options;
1236 g_memory_write_option_table[] =
1238 { LLDB_OPT_SET_1, true, "infile", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1239 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset, "Start writing bytes from an offset within the input file."},
1242 //----------------------------------------------------------------------
1243 // Write memory to the inferior process
1244 //----------------------------------------------------------------------
1245 class CommandObjectMemoryWrite : public CommandObjectParsed
1249 class OptionGroupWriteMemory : public OptionGroup
1252 OptionGroupWriteMemory () :
1258 ~OptionGroupWriteMemory ()
1263 GetNumDefinitions ()
1265 return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
1268 virtual const OptionDefinition*
1271 return g_memory_write_option_table;
1275 SetOptionValue (CommandInterpreter &interpreter,
1276 uint32_t option_idx,
1277 const char *option_arg)
1280 const int short_option = g_memory_write_option_table[option_idx].short_option;
1282 switch (short_option)
1285 m_infile.SetFile (option_arg, true);
1286 if (!m_infile.Exists())
1289 error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
1296 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
1299 error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
1305 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
1312 OptionParsingStarting (CommandInterpreter &interpreter)
1315 m_infile_offset = 0;
1319 off_t m_infile_offset;
1322 CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
1323 CommandObjectParsed (interpreter,
1325 "Write to the memory of the process being debugged.",
1327 eFlagRequiresProcess | eFlagProcessMustBeLaunched),
1328 m_option_group (interpreter),
1329 m_format_options (eFormatBytes, 1, UINT64_MAX),
1332 CommandArgumentEntry arg1;
1333 CommandArgumentEntry arg2;
1334 CommandArgumentData addr_arg;
1335 CommandArgumentData value_arg;
1337 // Define the first (and only) variant of this arg.
1338 addr_arg.arg_type = eArgTypeAddress;
1339 addr_arg.arg_repetition = eArgRepeatPlain;
1341 // There is only one variant this argument could be; put it into the argument entry.
1342 arg1.push_back (addr_arg);
1344 // Define the first (and only) variant of this arg.
1345 value_arg.arg_type = eArgTypeValue;
1346 value_arg.arg_repetition = eArgRepeatPlus;
1348 // There is only one variant this argument could be; put it into the argument entry.
1349 arg2.push_back (value_arg);
1351 // Push the data for the first argument into the m_arguments vector.
1352 m_arguments.push_back (arg1);
1353 m_arguments.push_back (arg2);
1355 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
1356 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
1357 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1358 m_option_group.Finalize();
1363 ~CommandObjectMemoryWrite ()
1370 return &m_option_group;
1374 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
1376 if (total_byte_size > 8)
1379 if (total_byte_size == 8)
1382 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1383 return uval64 <= max;
1387 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
1389 if (total_byte_size > 8)
1392 if (total_byte_size == 8)
1395 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1396 const int64_t min = ~(max);
1397 return min <= sval64 && sval64 <= max;
1402 DoExecute (Args& command, CommandReturnObject &result)
1404 // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1405 Process *process = m_exe_ctx.GetProcessPtr();
1407 const size_t argc = command.GetArgumentCount();
1409 if (m_memory_options.m_infile)
1413 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
1414 result.SetStatus(eReturnStatusFailed);
1420 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
1421 result.SetStatus(eReturnStatusFailed);
1425 StreamString buffer (Stream::eBinary,
1426 process->GetTarget().GetArchitecture().GetAddressByteSize(),
1427 process->GetTarget().GetArchitecture().GetByteOrder());
1429 OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1430 size_t item_byte_size = byte_size_value.GetCurrentValue();
1433 lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1434 command.GetArgumentAtIndex(0),
1435 LLDB_INVALID_ADDRESS,
1438 if (addr == LLDB_INVALID_ADDRESS)
1440 result.AppendError("invalid address expression\n");
1441 result.AppendError(error.AsCString());
1442 result.SetStatus(eReturnStatusFailed);
1446 if (m_memory_options.m_infile)
1448 size_t length = SIZE_MAX;
1449 if (item_byte_size > 0)
1450 length = item_byte_size;
1451 lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
1454 length = data_sp->GetByteSize();
1458 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
1460 if (bytes_written == length)
1462 // All bytes written
1463 result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
1464 result.SetStatus(eReturnStatusSuccessFinishResult);
1466 else if (bytes_written > 0)
1468 // Some byte written
1469 result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
1470 result.SetStatus(eReturnStatusSuccessFinishResult);
1474 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1475 result.SetStatus(eReturnStatusFailed);
1481 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1482 result.SetStatus(eReturnStatusFailed);
1484 return result.Succeeded();
1486 else if (item_byte_size == 0)
1488 if (m_format_options.GetFormat() == eFormatPointer)
1489 item_byte_size = buffer.GetAddressByteSize();
1494 command.Shift(); // shift off the address argument
1497 bool success = false;
1498 const size_t num_value_args = command.GetArgumentCount();
1499 for (size_t i=0; i<num_value_args; ++i)
1501 const char *value_str = command.GetArgumentAtIndex(i);
1503 switch (m_format_options.GetFormat())
1506 case eFormatFloat: // TODO: add support for floats soon
1507 case eFormatCharPrintable:
1508 case eFormatBytesWithASCII:
1509 case eFormatComplex:
1511 case eFormatUnicode16:
1512 case eFormatUnicode32:
1513 case eFormatVectorOfChar:
1514 case eFormatVectorOfSInt8:
1515 case eFormatVectorOfUInt8:
1516 case eFormatVectorOfSInt16:
1517 case eFormatVectorOfUInt16:
1518 case eFormatVectorOfSInt32:
1519 case eFormatVectorOfUInt32:
1520 case eFormatVectorOfSInt64:
1521 case eFormatVectorOfUInt64:
1522 case eFormatVectorOfFloat32:
1523 case eFormatVectorOfFloat64:
1524 case eFormatVectorOfUInt128:
1526 case eFormatComplexInteger:
1527 case eFormatAddressInfo:
1528 case eFormatHexFloat:
1529 case eFormatInstruction:
1531 result.AppendError("unsupported format for writing memory");
1532 result.SetStatus(eReturnStatusFailed);
1535 case eFormatDefault:
1538 case eFormatHexUppercase:
1539 case eFormatPointer:
1542 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1545 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1546 result.SetStatus(eReturnStatusFailed);
1549 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1551 result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1552 result.SetStatus(eReturnStatusFailed);
1555 buffer.PutMaxHex64 (uval64, item_byte_size);
1558 case eFormatBoolean:
1559 uval64 = Args::StringToBoolean(value_str, false, &success);
1562 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1563 result.SetStatus(eReturnStatusFailed);
1566 buffer.PutMaxHex64 (uval64, item_byte_size);
1570 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1573 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1574 result.SetStatus(eReturnStatusFailed);
1577 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1579 result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1580 result.SetStatus(eReturnStatusFailed);
1583 buffer.PutMaxHex64 (uval64, item_byte_size);
1586 case eFormatCharArray:
1588 case eFormatCString:
1591 size_t len = strlen (value_str);
1592 // Include the NULL for C strings...
1593 if (m_format_options.GetFormat() == eFormatCString)
1596 if (process->WriteMemory (addr, value_str, len, error) == len)
1602 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1603 result.SetStatus(eReturnStatusFailed);
1609 case eFormatDecimal:
1610 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1613 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1614 result.SetStatus(eReturnStatusFailed);
1617 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1619 result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %" PRIu64 " byte signed integer value.\n", sval64, (uint64_t)item_byte_size);
1620 result.SetStatus(eReturnStatusFailed);
1623 buffer.PutMaxHex64 (sval64, item_byte_size);
1626 case eFormatUnsigned:
1627 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1630 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1631 result.SetStatus(eReturnStatusFailed);
1634 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1636 result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1637 result.SetStatus(eReturnStatusFailed);
1640 buffer.PutMaxHex64 (uval64, item_byte_size);
1644 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1647 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1648 result.SetStatus(eReturnStatusFailed);
1651 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1653 result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1654 result.SetStatus(eReturnStatusFailed);
1657 buffer.PutMaxHex64 (uval64, item_byte_size);
1662 if (!buffer.GetString().empty())
1665 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1669 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1670 result.SetStatus(eReturnStatusFailed);
1677 OptionGroupOptions m_option_group;
1678 OptionGroupFormat m_format_options;
1679 OptionGroupWriteMemory m_memory_options;
1682 //----------------------------------------------------------------------
1683 // Get malloc/free history of a memory address.
1684 //----------------------------------------------------------------------
1685 class CommandObjectMemoryHistory : public CommandObjectParsed
1689 CommandObjectMemoryHistory (CommandInterpreter &interpreter) :
1690 CommandObjectParsed (interpreter,
1692 "Prints out the recorded stack traces for allocation/deallocation of a memory address.",
1694 eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched)
1696 CommandArgumentEntry arg1;
1697 CommandArgumentData addr_arg;
1699 // Define the first (and only) variant of this arg.
1700 addr_arg.arg_type = eArgTypeAddress;
1701 addr_arg.arg_repetition = eArgRepeatPlain;
1703 // There is only one variant this argument could be; put it into the argument entry.
1704 arg1.push_back (addr_arg);
1706 // Push the data for the first argument into the m_arguments vector.
1707 m_arguments.push_back (arg1);
1711 ~CommandObjectMemoryHistory ()
1715 virtual const char *GetRepeatCommand (Args ¤t_command_args, uint32_t index)
1717 return m_cmd_name.c_str();
1722 DoExecute (Args& command, CommandReturnObject &result)
1724 const size_t argc = command.GetArgumentCount();
1726 if (argc == 0 || argc > 1)
1728 result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str());
1729 result.SetStatus(eReturnStatusFailed);
1734 lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1735 command.GetArgumentAtIndex(0),
1736 LLDB_INVALID_ADDRESS,
1739 if (addr == LLDB_INVALID_ADDRESS)
1741 result.AppendError("invalid address expression");
1742 result.AppendError(error.AsCString());
1743 result.SetStatus(eReturnStatusFailed);
1747 Stream *output_stream = &result.GetOutputStream();
1749 const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
1750 const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp);
1752 if (! memory_history.get())
1754 result.AppendError("no available memory history provider");
1755 result.SetStatus(eReturnStatusFailed);
1759 HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1761 for (auto thread : thread_list) {
1762 thread->GetStatus(*output_stream, 0, UINT32_MAX, 0);
1765 result.SetStatus(eReturnStatusSuccessFinishResult);
1773 //-------------------------------------------------------------------------
1774 // CommandObjectMemory
1775 //-------------------------------------------------------------------------
1777 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1778 CommandObjectMultiword (interpreter,
1780 "A set of commands for operating on memory.",
1781 "memory <subcommand> [<subcommand-options>]")
1783 LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
1784 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1785 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1786 LoadSubCommand ("history", CommandObjectSP (new CommandObjectMemoryHistory (interpreter)));
1789 CommandObjectMemory::~CommandObjectMemory ()