1 //===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/lldb-python.h"
11
12 #include "CommandObjectMemory.h"
13
14 // C Includes
15 #include <inttypes.h>
16
17 // C++ Includes
18 // Other libraries and framework includes
19 // Project 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/Process.h"
37 #include "lldb/Target/StackFrame.h"
38
39 using namespace lldb;
40 using namespace lldb_private;
41
42 static OptionDefinition
43 g_option_table[] =
44 {
45 { LLDB_OPT_SET_1, false, "num-per-line" ,'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
46 { LLDB_OPT_SET_2, false, "binary" ,'b', OptionParser::eNoArgument , 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."},
47 { LLDB_OPT_SET_3, true , "type" ,'t', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
48 { LLDB_OPT_SET_1|
49 LLDB_OPT_SET_2|
50 LLDB_OPT_SET_3, false, "force" ,'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
51 };
52
53
54
55 class OptionGroupReadMemory : public OptionGroup
56 {
57 public:
58
OptionGroupReadMemory()59 OptionGroupReadMemory () :
60 m_num_per_line (1,1),
61 m_output_as_binary (false),
62 m_view_as_type()
63 {
64 }
65
66 virtual
~OptionGroupReadMemory()67 ~OptionGroupReadMemory ()
68 {
69 }
70
71
72 virtual uint32_t
GetNumDefinitions()73 GetNumDefinitions ()
74 {
75 return sizeof (g_option_table) / sizeof (OptionDefinition);
76 }
77
78 virtual const OptionDefinition*
GetDefinitions()79 GetDefinitions ()
80 {
81 return g_option_table;
82 }
83
84 virtual Error
SetOptionValue(CommandInterpreter & interpreter,uint32_t option_idx,const char * option_arg)85 SetOptionValue (CommandInterpreter &interpreter,
86 uint32_t option_idx,
87 const char *option_arg)
88 {
89 Error error;
90 const int short_option = g_option_table[option_idx].short_option;
91
92 switch (short_option)
93 {
94 case 'l':
95 error = m_num_per_line.SetValueFromCString (option_arg);
96 if (m_num_per_line.GetCurrentValue() == 0)
97 error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
98 break;
99
100 case 'b':
101 m_output_as_binary = true;
102 break;
103
104 case 't':
105 error = m_view_as_type.SetValueFromCString (option_arg);
106 break;
107
108 case 'r':
109 m_force = true;
110 break;
111
112 default:
113 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
114 break;
115 }
116 return error;
117 }
118
119 virtual void
OptionParsingStarting(CommandInterpreter & interpreter)120 OptionParsingStarting (CommandInterpreter &interpreter)
121 {
122 m_num_per_line.Clear();
123 m_output_as_binary = false;
124 m_view_as_type.Clear();
125 m_force = false;
126 }
127
128 Error
FinalizeSettings(Target * target,OptionGroupFormat & format_options)129 FinalizeSettings (Target *target, OptionGroupFormat& format_options)
130 {
131 Error error;
132 OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
133 OptionValueUInt64 &count_value = format_options.GetCountValue();
134 const bool byte_size_option_set = byte_size_value.OptionWasSet();
135 const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
136 const bool count_option_set = format_options.GetCountValue().OptionWasSet();
137
138 switch (format_options.GetFormat())
139 {
140 default:
141 break;
142
143 case eFormatBoolean:
144 if (!byte_size_option_set)
145 byte_size_value = 1;
146 if (!num_per_line_option_set)
147 m_num_per_line = 1;
148 if (!count_option_set)
149 format_options.GetCountValue() = 8;
150 break;
151
152 case eFormatCString:
153 break;
154
155 case eFormatInstruction:
156 if (count_option_set)
157 byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
158 m_num_per_line = 1;
159 break;
160
161 case eFormatAddressInfo:
162 if (!byte_size_option_set)
163 byte_size_value = target->GetArchitecture().GetAddressByteSize();
164 m_num_per_line = 1;
165 if (!count_option_set)
166 format_options.GetCountValue() = 8;
167 break;
168
169 case eFormatPointer:
170 byte_size_value = target->GetArchitecture().GetAddressByteSize();
171 if (!num_per_line_option_set)
172 m_num_per_line = 4;
173 if (!count_option_set)
174 format_options.GetCountValue() = 8;
175 break;
176
177 case eFormatBinary:
178 case eFormatFloat:
179 case eFormatOctal:
180 case eFormatDecimal:
181 case eFormatEnum:
182 case eFormatUnicode16:
183 case eFormatUnicode32:
184 case eFormatUnsigned:
185 case eFormatHexFloat:
186 if (!byte_size_option_set)
187 byte_size_value = 4;
188 if (!num_per_line_option_set)
189 m_num_per_line = 1;
190 if (!count_option_set)
191 format_options.GetCountValue() = 8;
192 break;
193
194 case eFormatBytes:
195 case eFormatBytesWithASCII:
196 if (byte_size_option_set)
197 {
198 if (byte_size_value > 1)
199 error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
200 "\tconsider using a different display format or don't specify the byte size",
201 byte_size_value.GetCurrentValue());
202 }
203 else
204 byte_size_value = 1;
205 if (!num_per_line_option_set)
206 m_num_per_line = 16;
207 if (!count_option_set)
208 format_options.GetCountValue() = 32;
209 break;
210 case eFormatCharArray:
211 case eFormatChar:
212 case eFormatCharPrintable:
213 if (!byte_size_option_set)
214 byte_size_value = 1;
215 if (!num_per_line_option_set)
216 m_num_per_line = 32;
217 if (!count_option_set)
218 format_options.GetCountValue() = 64;
219 break;
220 case eFormatComplex:
221 if (!byte_size_option_set)
222 byte_size_value = 8;
223 if (!num_per_line_option_set)
224 m_num_per_line = 1;
225 if (!count_option_set)
226 format_options.GetCountValue() = 8;
227 break;
228 case eFormatComplexInteger:
229 if (!byte_size_option_set)
230 byte_size_value = 8;
231 if (!num_per_line_option_set)
232 m_num_per_line = 1;
233 if (!count_option_set)
234 format_options.GetCountValue() = 8;
235 break;
236 case eFormatHex:
237 if (!byte_size_option_set)
238 byte_size_value = 4;
239 if (!num_per_line_option_set)
240 {
241 switch (byte_size_value)
242 {
243 case 1:
244 case 2:
245 m_num_per_line = 8;
246 break;
247 case 4:
248 m_num_per_line = 4;
249 break;
250 case 8:
251 m_num_per_line = 2;
252 break;
253 default:
254 m_num_per_line = 1;
255 break;
256 }
257 }
258 if (!count_option_set)
259 count_value = 8;
260 break;
261
262 case eFormatVectorOfChar:
263 case eFormatVectorOfSInt8:
264 case eFormatVectorOfUInt8:
265 case eFormatVectorOfSInt16:
266 case eFormatVectorOfUInt16:
267 case eFormatVectorOfSInt32:
268 case eFormatVectorOfUInt32:
269 case eFormatVectorOfSInt64:
270 case eFormatVectorOfUInt64:
271 case eFormatVectorOfFloat32:
272 case eFormatVectorOfFloat64:
273 case eFormatVectorOfUInt128:
274 if (!byte_size_option_set)
275 byte_size_value = 128;
276 if (!num_per_line_option_set)
277 m_num_per_line = 1;
278 if (!count_option_set)
279 count_value = 4;
280 break;
281 }
282 return error;
283 }
284
285 bool
AnyOptionWasSet() const286 AnyOptionWasSet () const
287 {
288 return m_num_per_line.OptionWasSet() ||
289 m_output_as_binary ||
290 m_view_as_type.OptionWasSet();
291 }
292
293 OptionValueUInt64 m_num_per_line;
294 bool m_output_as_binary;
295 OptionValueString m_view_as_type;
296 bool m_force;
297 };
298
299
300
301 //----------------------------------------------------------------------
302 // Read memory from the inferior process
303 //----------------------------------------------------------------------
304 class CommandObjectMemoryRead : public CommandObjectParsed
305 {
306 public:
307
CommandObjectMemoryRead(CommandInterpreter & interpreter)308 CommandObjectMemoryRead (CommandInterpreter &interpreter) :
309 CommandObjectParsed (interpreter,
310 "memory read",
311 "Read from the memory of the process being debugged.",
312 NULL,
313 eFlagRequiresTarget | eFlagProcessMustBePaused),
314 m_option_group (interpreter),
315 m_format_options (eFormatBytesWithASCII, 1, 8),
316 m_memory_options (),
317 m_outfile_options (),
318 m_varobj_options(),
319 m_next_addr(LLDB_INVALID_ADDRESS),
320 m_prev_byte_size(0),
321 m_prev_format_options (eFormatBytesWithASCII, 1, 8),
322 m_prev_memory_options (),
323 m_prev_outfile_options (),
324 m_prev_varobj_options()
325 {
326 CommandArgumentEntry arg1;
327 CommandArgumentEntry arg2;
328 CommandArgumentData start_addr_arg;
329 CommandArgumentData end_addr_arg;
330
331 // Define the first (and only) variant of this arg.
332 start_addr_arg.arg_type = eArgTypeAddressOrExpression;
333 start_addr_arg.arg_repetition = eArgRepeatPlain;
334
335 // There is only one variant this argument could be; put it into the argument entry.
336 arg1.push_back (start_addr_arg);
337
338 // Define the first (and only) variant of this arg.
339 end_addr_arg.arg_type = eArgTypeAddressOrExpression;
340 end_addr_arg.arg_repetition = eArgRepeatOptional;
341
342 // There is only one variant this argument could be; put it into the argument entry.
343 arg2.push_back (end_addr_arg);
344
345 // Push the data for the first argument into the m_arguments vector.
346 m_arguments.push_back (arg1);
347 m_arguments.push_back (arg2);
348
349 // Add the "--format" and "--count" options to group 1 and 3
350 m_option_group.Append (&m_format_options,
351 OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
352 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
353 m_option_group.Append (&m_format_options,
354 OptionGroupFormat::OPTION_GROUP_GDB_FMT,
355 LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
356 // Add the "--size" option to group 1 and 2
357 m_option_group.Append (&m_format_options,
358 OptionGroupFormat::OPTION_GROUP_SIZE,
359 LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
360 m_option_group.Append (&m_memory_options);
361 m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
362 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
363 m_option_group.Finalize();
364 }
365
366 virtual
~CommandObjectMemoryRead()367 ~CommandObjectMemoryRead ()
368 {
369 }
370
371 Options *
GetOptions()372 GetOptions ()
373 {
374 return &m_option_group;
375 }
376
GetRepeatCommand(Args & current_command_args,uint32_t index)377 virtual const char *GetRepeatCommand (Args ¤t_command_args, uint32_t index)
378 {
379 return m_cmd_name.c_str();
380 }
381
382 protected:
383 virtual bool
DoExecute(Args & command,CommandReturnObject & result)384 DoExecute (Args& command, CommandReturnObject &result)
385 {
386 // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
387 Target *target = m_exe_ctx.GetTargetPtr();
388
389 const size_t argc = command.GetArgumentCount();
390
391 if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
392 {
393 result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
394 result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
395 result.SetStatus(eReturnStatusFailed);
396 return false;
397 }
398
399 ClangASTType clang_ast_type;
400 Error error;
401
402 const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
403 if (view_as_type_cstr && view_as_type_cstr[0])
404 {
405 // We are viewing memory as a type
406
407 SymbolContext sc;
408 const bool exact_match = false;
409 TypeList type_list;
410 uint32_t reference_count = 0;
411 uint32_t pointer_count = 0;
412 size_t idx;
413
414 #define ALL_KEYWORDS \
415 KEYWORD("const") \
416 KEYWORD("volatile") \
417 KEYWORD("restrict") \
418 KEYWORD("struct") \
419 KEYWORD("class") \
420 KEYWORD("union")
421
422 #define KEYWORD(s) s,
423 static const char *g_keywords[] =
424 {
425 ALL_KEYWORDS
426 };
427 #undef KEYWORD
428
429 #define KEYWORD(s) (sizeof(s) - 1),
430 static const int g_keyword_lengths[] =
431 {
432 ALL_KEYWORDS
433 };
434 #undef KEYWORD
435
436 #undef ALL_KEYWORDS
437
438 static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
439 std::string type_str(view_as_type_cstr);
440
441 // Remove all instances of g_keywords that are followed by spaces
442 for (size_t i = 0; i < g_num_keywords; ++i)
443 {
444 const char *keyword = g_keywords[i];
445 int keyword_len = g_keyword_lengths[i];
446
447 idx = 0;
448 while ((idx = type_str.find (keyword, idx)) != std::string::npos)
449 {
450 if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
451 {
452 type_str.erase(idx, keyword_len+1);
453 idx = 0;
454 }
455 else
456 {
457 idx += keyword_len;
458 }
459 }
460 }
461 bool done = type_str.empty();
462 //
463 idx = type_str.find_first_not_of (" \t");
464 if (idx > 0 && idx != std::string::npos)
465 type_str.erase (0, idx);
466 while (!done)
467 {
468 // Strip trailing spaces
469 if (type_str.empty())
470 done = true;
471 else
472 {
473 switch (type_str[type_str.size()-1])
474 {
475 case '*':
476 ++pointer_count;
477 // fall through...
478 case ' ':
479 case '\t':
480 type_str.erase(type_str.size()-1);
481 break;
482
483 case '&':
484 if (reference_count == 0)
485 {
486 reference_count = 1;
487 type_str.erase(type_str.size()-1);
488 }
489 else
490 {
491 result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
492 result.SetStatus(eReturnStatusFailed);
493 return false;
494 }
495 break;
496
497 default:
498 done = true;
499 break;
500 }
501 }
502 }
503
504 ConstString lookup_type_name(type_str.c_str());
505 StackFrame *frame = m_exe_ctx.GetFramePtr();
506 if (frame)
507 {
508 sc = frame->GetSymbolContext (eSymbolContextModule);
509 if (sc.module_sp)
510 {
511 sc.module_sp->FindTypes (sc,
512 lookup_type_name,
513 exact_match,
514 1,
515 type_list);
516 }
517 }
518 if (type_list.GetSize() == 0)
519 {
520 target->GetImages().FindTypes (sc,
521 lookup_type_name,
522 exact_match,
523 1,
524 type_list);
525 }
526
527 if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$')
528 {
529 clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
530 if (tdecl)
531 {
532 clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
533 }
534 }
535
536 if (clang_ast_type.IsValid() == false)
537 {
538 if (type_list.GetSize() == 0)
539 {
540 result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
541 lookup_type_name.GetCString(),
542 view_as_type_cstr);
543 result.SetStatus(eReturnStatusFailed);
544 return false;
545 }
546 else
547 {
548 TypeSP type_sp (type_list.GetTypeAtIndex(0));
549 clang_ast_type = type_sp->GetClangFullType();
550 }
551 }
552
553 while (pointer_count > 0)
554 {
555 ClangASTType pointer_type = clang_ast_type.GetPointerType();
556 if (pointer_type.IsValid())
557 clang_ast_type = pointer_type;
558 else
559 {
560 result.AppendError ("unable make a pointer type\n");
561 result.SetStatus(eReturnStatusFailed);
562 return false;
563 }
564 --pointer_count;
565 }
566
567 m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize();
568
569 if (m_format_options.GetByteSizeValue() == 0)
570 {
571 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
572 view_as_type_cstr);
573 result.SetStatus(eReturnStatusFailed);
574 return false;
575 }
576
577 if (!m_format_options.GetCountValue().OptionWasSet())
578 m_format_options.GetCountValue() = 1;
579 }
580 else
581 {
582 error = m_memory_options.FinalizeSettings (target, m_format_options);
583 }
584
585 // Look for invalid combinations of settings
586 if (error.Fail())
587 {
588 result.AppendError(error.AsCString());
589 result.SetStatus(eReturnStatusFailed);
590 return false;
591 }
592
593 lldb::addr_t addr;
594 size_t total_byte_size = 0;
595 if (argc == 0)
596 {
597 // Use the last address and byte size and all options as they were
598 // if no options have been set
599 addr = m_next_addr;
600 total_byte_size = m_prev_byte_size;
601 clang_ast_type = m_prev_clang_ast_type;
602 if (!m_format_options.AnyOptionWasSet() &&
603 !m_memory_options.AnyOptionWasSet() &&
604 !m_outfile_options.AnyOptionWasSet() &&
605 !m_varobj_options.AnyOptionWasSet())
606 {
607 m_format_options = m_prev_format_options;
608 m_memory_options = m_prev_memory_options;
609 m_outfile_options = m_prev_outfile_options;
610 m_varobj_options = m_prev_varobj_options;
611 }
612 }
613
614 size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
615 size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
616 const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
617
618 if (total_byte_size == 0)
619 {
620 total_byte_size = item_count * item_byte_size;
621 if (total_byte_size == 0)
622 total_byte_size = 32;
623 }
624
625 if (argc > 0)
626 addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
627
628 if (addr == LLDB_INVALID_ADDRESS)
629 {
630 result.AppendError("invalid start address expression.");
631 result.AppendError(error.AsCString());
632 result.SetStatus(eReturnStatusFailed);
633 return false;
634 }
635
636 if (argc == 2)
637 {
638 lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
639 if (end_addr == LLDB_INVALID_ADDRESS)
640 {
641 result.AppendError("invalid end address expression.");
642 result.AppendError(error.AsCString());
643 result.SetStatus(eReturnStatusFailed);
644 return false;
645 }
646 else if (end_addr <= addr)
647 {
648 result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
649 result.SetStatus(eReturnStatusFailed);
650 return false;
651 }
652 else if (m_format_options.GetCountValue().OptionWasSet())
653 {
654 result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %zu), not both.\n", end_addr, item_count);
655 result.SetStatus(eReturnStatusFailed);
656 return false;
657 }
658
659 total_byte_size = end_addr - addr;
660 item_count = total_byte_size / item_byte_size;
661 }
662
663 uint32_t max_unforced_size = target->GetMaximumMemReadSize();
664
665 if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
666 {
667 result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
668 result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
669 result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
670 return false;
671 }
672
673 DataBufferSP data_sp;
674 size_t bytes_read = 0;
675 if (clang_ast_type.GetOpaqueQualType())
676 {
677 // Make sure we don't display our type as ASCII bytes like the default memory read
678 if (m_format_options.GetFormatValue().OptionWasSet() == false)
679 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
680
681 bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue();
682 }
683 else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
684 {
685 data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
686 if (data_sp->GetBytes() == NULL)
687 {
688 result.AppendErrorWithFormat ("can't allocate 0x%zx bytes for the memory read buffer, specify a smaller size to read", total_byte_size);
689 result.SetStatus(eReturnStatusFailed);
690 return false;
691 }
692
693 Address address(addr, NULL);
694 bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
695 if (bytes_read == 0)
696 {
697 const char *error_cstr = error.AsCString();
698 if (error_cstr && error_cstr[0])
699 {
700 result.AppendError(error_cstr);
701 }
702 else
703 {
704 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
705 }
706 result.SetStatus(eReturnStatusFailed);
707 return false;
708 }
709
710 if (bytes_read < total_byte_size)
711 result.AppendWarningWithFormat("Not all bytes (%zu/%zu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
712 }
713 else
714 {
715 // we treat c-strings as a special case because they do not have a fixed size
716 if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
717 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
718 else
719 item_byte_size = target->GetMaximumSizeOfStringSummary();
720 if (!m_format_options.GetCountValue().OptionWasSet())
721 item_count = 1;
722 data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
723 if (data_sp->GetBytes() == NULL)
724 {
725 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));
726 result.SetStatus(eReturnStatusFailed);
727 return false;
728 }
729 uint8_t *data_ptr = data_sp->GetBytes();
730 auto data_addr = addr;
731 auto count = item_count;
732 item_count = 0;
733 while (item_count < count)
734 {
735 std::string buffer;
736 buffer.resize(item_byte_size+1,0);
737 Error error;
738 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
739 if (error.Fail())
740 {
741 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
742 result.SetStatus(eReturnStatusFailed);
743 return false;
744 }
745 if (item_byte_size == read)
746 {
747 result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
748 break;
749 }
750 read+=1; // account for final NULL byte
751 memcpy(data_ptr, &buffer[0], read);
752 data_ptr += read;
753 data_addr += read;
754 bytes_read += read;
755 item_count++; // if we break early we know we only read item_count strings
756 }
757 data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
758 }
759
760 m_next_addr = addr + bytes_read;
761 m_prev_byte_size = bytes_read;
762 m_prev_format_options = m_format_options;
763 m_prev_memory_options = m_memory_options;
764 m_prev_outfile_options = m_outfile_options;
765 m_prev_varobj_options = m_varobj_options;
766 m_prev_clang_ast_type = clang_ast_type;
767
768 StreamFile outfile_stream;
769 Stream *output_stream = NULL;
770 const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
771 if (outfile_spec)
772 {
773 char path[PATH_MAX];
774 outfile_spec.GetPath (path, sizeof(path));
775
776 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
777 const bool append = m_outfile_options.GetAppend().GetCurrentValue();
778 if (append)
779 open_options |= File::eOpenOptionAppend;
780
781 if (outfile_stream.GetFile ().Open (path, open_options).Success())
782 {
783 if (m_memory_options.m_output_as_binary)
784 {
785 const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
786 if (bytes_written > 0)
787 {
788 result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
789 bytes_written,
790 append ? "appended" : "written",
791 path);
792 return true;
793 }
794 else
795 {
796 result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
797 result.SetStatus(eReturnStatusFailed);
798 return false;
799 }
800 }
801 else
802 {
803 // We are going to write ASCII to the file just point the
804 // output_stream to our outfile_stream...
805 output_stream = &outfile_stream;
806 }
807 }
808 else
809 {
810 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
811 result.SetStatus(eReturnStatusFailed);
812 return false;
813 }
814 }
815 else
816 {
817 output_stream = &result.GetOutputStream();
818 }
819
820
821 ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
822 if (clang_ast_type.GetOpaqueQualType())
823 {
824 for (uint32_t i = 0; i<item_count; ++i)
825 {
826 addr_t item_addr = addr + (i * item_byte_size);
827 Address address (item_addr);
828 StreamString name_strm;
829 name_strm.Printf ("0x%" PRIx64, item_addr);
830 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
831 name_strm.GetString().c_str(),
832 address,
833 clang_ast_type));
834 if (valobj_sp)
835 {
836 Format format = m_format_options.GetFormat();
837 if (format != eFormatDefault)
838 valobj_sp->SetFormat (format);
839
840 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format));
841
842 valobj_sp->Dump(*output_stream,options);
843 }
844 else
845 {
846 result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
847 view_as_type_cstr,
848 name_strm.GetString().c_str());
849 result.SetStatus(eReturnStatusFailed);
850 return false;
851 }
852 }
853 return true;
854 }
855
856 result.SetStatus(eReturnStatusSuccessFinishResult);
857 DataExtractor data (data_sp,
858 target->GetArchitecture().GetByteOrder(),
859 target->GetArchitecture().GetAddressByteSize());
860
861 Format format = m_format_options.GetFormat();
862 if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
863 && (item_byte_size != 1))
864 {
865 // if a count was not passed, or it is 1
866 if (m_format_options.GetCountValue().OptionWasSet() == false || item_count == 1)
867 {
868 // this turns requests such as
869 // memory read -fc -s10 -c1 *charPtrPtr
870 // which make no sense (what is a char of size 10?)
871 // into a request for fetching 10 chars of size 1 from the same memory location
872 format = eFormatCharArray;
873 item_count = item_byte_size;
874 item_byte_size = 1;
875 }
876 else
877 {
878 // here we passed a count, and it was not 1
879 // so we have a byte_size and a count
880 // we could well multiply those, but instead let's just fail
881 result.AppendErrorWithFormat("reading memory as characters of size %zu is not supported", item_byte_size);
882 result.SetStatus(eReturnStatusFailed);
883 return false;
884 }
885 }
886
887 assert (output_stream);
888 size_t bytes_dumped = data.Dump (output_stream,
889 0,
890 format,
891 item_byte_size,
892 item_count,
893 num_per_line,
894 addr,
895 0,
896 0,
897 exe_scope);
898 m_next_addr = addr + bytes_dumped;
899 output_stream->EOL();
900 return true;
901 }
902
903 OptionGroupOptions m_option_group;
904 OptionGroupFormat m_format_options;
905 OptionGroupReadMemory m_memory_options;
906 OptionGroupOutputFile m_outfile_options;
907 OptionGroupValueObjectDisplay m_varobj_options;
908 lldb::addr_t m_next_addr;
909 lldb::addr_t m_prev_byte_size;
910 OptionGroupFormat m_prev_format_options;
911 OptionGroupReadMemory m_prev_memory_options;
912 OptionGroupOutputFile m_prev_outfile_options;
913 OptionGroupValueObjectDisplay m_prev_varobj_options;
914 ClangASTType m_prev_clang_ast_type;
915 };
916
917 OptionDefinition
918 g_memory_find_option_table[] =
919 {
920 { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
921 { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Use text to find a byte pattern."},
922 { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many times to perform the search."},
923 { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "dump-offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."},
924 };
925
926 //----------------------------------------------------------------------
927 // Find the specified data in memory
928 //----------------------------------------------------------------------
929 class CommandObjectMemoryFind : public CommandObjectParsed
930 {
931 public:
932
933 class OptionGroupFindMemory : public OptionGroup
934 {
935 public:
OptionGroupFindMemory()936 OptionGroupFindMemory () :
937 OptionGroup(),
938 m_count(1),
939 m_offset(0)
940 {
941 }
942
943 virtual
~OptionGroupFindMemory()944 ~OptionGroupFindMemory ()
945 {
946 }
947
948 virtual uint32_t
GetNumDefinitions()949 GetNumDefinitions ()
950 {
951 return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition);
952 }
953
954 virtual const OptionDefinition*
GetDefinitions()955 GetDefinitions ()
956 {
957 return g_memory_find_option_table;
958 }
959
960 virtual Error
SetOptionValue(CommandInterpreter & interpreter,uint32_t option_idx,const char * option_arg)961 SetOptionValue (CommandInterpreter &interpreter,
962 uint32_t option_idx,
963 const char *option_arg)
964 {
965 Error error;
966 const int short_option = g_memory_find_option_table[option_idx].short_option;
967
968 switch (short_option)
969 {
970 case 'e':
971 m_expr.SetValueFromCString(option_arg);
972 break;
973
974 case 's':
975 m_string.SetValueFromCString(option_arg);
976 break;
977
978 case 'c':
979 if (m_count.SetValueFromCString(option_arg).Fail())
980 error.SetErrorString("unrecognized value for count");
981 break;
982
983 case 'o':
984 if (m_offset.SetValueFromCString(option_arg).Fail())
985 error.SetErrorString("unrecognized value for dump-offset");
986 break;
987
988 default:
989 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
990 break;
991 }
992 return error;
993 }
994
995 virtual void
OptionParsingStarting(CommandInterpreter & interpreter)996 OptionParsingStarting (CommandInterpreter &interpreter)
997 {
998 m_expr.Clear();
999 m_string.Clear();
1000 m_count.Clear();
1001 }
1002
1003 OptionValueString m_expr;
1004 OptionValueString m_string;
1005 OptionValueUInt64 m_count;
1006 OptionValueUInt64 m_offset;
1007 };
1008
CommandObjectMemoryFind(CommandInterpreter & interpreter)1009 CommandObjectMemoryFind (CommandInterpreter &interpreter) :
1010 CommandObjectParsed (interpreter,
1011 "memory find",
1012 "Find a value in the memory of the process being debugged.",
1013 NULL,
1014 eFlagRequiresProcess | eFlagProcessMustBeLaunched),
1015 m_option_group (interpreter),
1016 m_memory_options ()
1017 {
1018 CommandArgumentEntry arg1;
1019 CommandArgumentEntry arg2;
1020 CommandArgumentData addr_arg;
1021 CommandArgumentData value_arg;
1022
1023 // Define the first (and only) variant of this arg.
1024 addr_arg.arg_type = eArgTypeAddress;
1025 addr_arg.arg_repetition = eArgRepeatPlain;
1026
1027 // There is only one variant this argument could be; put it into the argument entry.
1028 arg1.push_back (addr_arg);
1029
1030 // Define the first (and only) variant of this arg.
1031 value_arg.arg_type = eArgTypeValue;
1032 value_arg.arg_repetition = eArgRepeatPlus;
1033
1034 // There is only one variant this argument could be; put it into the argument entry.
1035 arg2.push_back (value_arg);
1036
1037 // Push the data for the first argument into the m_arguments vector.
1038 m_arguments.push_back (arg1);
1039 m_arguments.push_back (arg2);
1040
1041 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1042 m_option_group.Finalize();
1043 }
1044
1045 virtual
~CommandObjectMemoryFind()1046 ~CommandObjectMemoryFind ()
1047 {
1048 }
1049
1050 Options *
GetOptions()1051 GetOptions ()
1052 {
1053 return &m_option_group;
1054 }
1055
1056 protected:
1057 virtual bool
DoExecute(Args & command,CommandReturnObject & result)1058 DoExecute (Args& command, CommandReturnObject &result)
1059 {
1060 // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1061 Process *process = m_exe_ctx.GetProcessPtr();
1062
1063 const size_t argc = command.GetArgumentCount();
1064
1065 if (argc != 2)
1066 {
1067 result.AppendError("two addresses needed for memory find");
1068 return false;
1069 }
1070
1071 Error error;
1072 lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error);
1073 if (low_addr == LLDB_INVALID_ADDRESS || error.Fail())
1074 {
1075 result.AppendError("invalid low address");
1076 return false;
1077 }
1078 lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error);
1079 if (high_addr == LLDB_INVALID_ADDRESS || error.Fail())
1080 {
1081 result.AppendError("invalid low address");
1082 return false;
1083 }
1084
1085 if (high_addr <= low_addr)
1086 {
1087 result.AppendError("starting address must be smaller than ending address");
1088 return false;
1089 }
1090
1091 lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1092
1093 DataBufferHeap buffer;
1094
1095 if (m_memory_options.m_string.OptionWasSet())
1096 buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue()));
1097 else if (m_memory_options.m_expr.OptionWasSet())
1098 {
1099 StackFrame* frame = m_exe_ctx.GetFramePtr();
1100 ValueObjectSP result_sp;
1101 if (process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp) && result_sp.get())
1102 {
1103 uint64_t value = result_sp->GetValueAsUnsigned(0);
1104 switch (result_sp->GetClangType().GetByteSize())
1105 {
1106 case 1: {
1107 uint8_t byte = (uint8_t)value;
1108 buffer.CopyData(&byte,1);
1109 }
1110 break;
1111 case 2: {
1112 uint16_t word = (uint16_t)value;
1113 buffer.CopyData(&word,2);
1114 }
1115 break;
1116 case 4: {
1117 uint32_t lword = (uint32_t)value;
1118 buffer.CopyData(&lword,4);
1119 }
1120 break;
1121 case 8: {
1122 buffer.CopyData(&value, 8);
1123 }
1124 break;
1125 case 3:
1126 case 5:
1127 case 6:
1128 case 7:
1129 result.AppendError("unknown type. pass a string instead");
1130 return false;
1131 default:
1132 result.AppendError("do not know how to deal with larger than 8 byte result types. pass a string instead");
1133 return false;
1134 }
1135 }
1136 else
1137 {
1138 result.AppendError("expression evaluation failed. pass a string instead?");
1139 return false;
1140 }
1141 }
1142 else
1143 {
1144 result.AppendError("please pass either a block of text, or an expression to evaluate.");
1145 return false;
1146 }
1147
1148 size_t count = m_memory_options.m_count.GetCurrentValue();
1149 found_location = low_addr;
1150 bool ever_found = false;
1151 while (count)
1152 {
1153 found_location = Search(found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
1154 if (found_location == LLDB_INVALID_ADDRESS)
1155 {
1156 if (!ever_found)
1157 {
1158 result.AppendMessage("Your data was not found within the range.\n");
1159 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1160 }
1161 else
1162 result.AppendMessage("No more matches found within the range.\n");
1163 break;
1164 }
1165 result.AppendMessageWithFormat("Your data was found at location: 0x%" PRIx64 "\n", found_location);
1166
1167 DataBufferHeap dumpbuffer(32,0);
1168 process->ReadMemory(found_location+m_memory_options.m_offset.GetCurrentValue(), dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
1169 if (!error.Fail())
1170 {
1171 DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), process->GetByteOrder(), process->GetAddressByteSize());
1172 data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1, dumpbuffer.GetByteSize(), 16, found_location+m_memory_options.m_offset.GetCurrentValue(), 0, 0);
1173 result.GetOutputStream().EOL();
1174 }
1175
1176 --count;
1177 found_location++;
1178 ever_found = true;
1179 }
1180
1181 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1182 return true;
1183 }
1184
1185 lldb::addr_t
Search(lldb::addr_t low,lldb::addr_t high,uint8_t * buffer,size_t buffer_size)1186 Search (lldb::addr_t low,
1187 lldb::addr_t high,
1188 uint8_t* buffer,
1189 size_t buffer_size)
1190 {
1191 Process *process = m_exe_ctx.GetProcessPtr();
1192 DataBufferHeap heap(buffer_size, 0);
1193 lldb::addr_t fictional_ptr = low;
1194 for (auto ptr = low;
1195 low < high;
1196 fictional_ptr++)
1197 {
1198 Error error;
1199 if (ptr == low || buffer_size == 1)
1200 process->ReadMemory(ptr, heap.GetBytes(), buffer_size, error);
1201 else
1202 {
1203 memmove(heap.GetBytes(), heap.GetBytes()+1, buffer_size-1);
1204 process->ReadMemory(ptr, heap.GetBytes()+buffer_size-1, 1, error);
1205 }
1206 if (error.Fail())
1207 return LLDB_INVALID_ADDRESS;
1208 if (memcmp(heap.GetBytes(), buffer, buffer_size) == 0)
1209 return fictional_ptr;
1210 if (ptr == low)
1211 ptr += buffer_size;
1212 else
1213 ptr += 1;
1214 }
1215 return LLDB_INVALID_ADDRESS;
1216 }
1217
1218 OptionGroupOptions m_option_group;
1219 OptionGroupFindMemory m_memory_options;
1220 };
1221
1222
1223 OptionDefinition
1224 g_memory_write_option_table[] =
1225 {
1226 { LLDB_OPT_SET_1, true, "infile", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1227 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
1228 };
1229
1230 //----------------------------------------------------------------------
1231 // Write memory to the inferior process
1232 //----------------------------------------------------------------------
1233 class CommandObjectMemoryWrite : public CommandObjectParsed
1234 {
1235 public:
1236
1237 class OptionGroupWriteMemory : public OptionGroup
1238 {
1239 public:
OptionGroupWriteMemory()1240 OptionGroupWriteMemory () :
1241 OptionGroup()
1242 {
1243 }
1244
1245 virtual
~OptionGroupWriteMemory()1246 ~OptionGroupWriteMemory ()
1247 {
1248 }
1249
1250 virtual uint32_t
GetNumDefinitions()1251 GetNumDefinitions ()
1252 {
1253 return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
1254 }
1255
1256 virtual const OptionDefinition*
GetDefinitions()1257 GetDefinitions ()
1258 {
1259 return g_memory_write_option_table;
1260 }
1261
1262 virtual Error
SetOptionValue(CommandInterpreter & interpreter,uint32_t option_idx,const char * option_arg)1263 SetOptionValue (CommandInterpreter &interpreter,
1264 uint32_t option_idx,
1265 const char *option_arg)
1266 {
1267 Error error;
1268 const int short_option = g_memory_write_option_table[option_idx].short_option;
1269
1270 switch (short_option)
1271 {
1272 case 'i':
1273 m_infile.SetFile (option_arg, true);
1274 if (!m_infile.Exists())
1275 {
1276 m_infile.Clear();
1277 error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
1278 }
1279 break;
1280
1281 case 'o':
1282 {
1283 bool success;
1284 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
1285 if (!success)
1286 {
1287 error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
1288 }
1289 }
1290 break;
1291
1292 default:
1293 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
1294 break;
1295 }
1296 return error;
1297 }
1298
1299 virtual void
OptionParsingStarting(CommandInterpreter & interpreter)1300 OptionParsingStarting (CommandInterpreter &interpreter)
1301 {
1302 m_infile.Clear();
1303 m_infile_offset = 0;
1304 }
1305
1306 FileSpec m_infile;
1307 off_t m_infile_offset;
1308 };
1309
CommandObjectMemoryWrite(CommandInterpreter & interpreter)1310 CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
1311 CommandObjectParsed (interpreter,
1312 "memory write",
1313 "Write to the memory of the process being debugged.",
1314 NULL,
1315 eFlagRequiresProcess | eFlagProcessMustBeLaunched),
1316 m_option_group (interpreter),
1317 m_format_options (eFormatBytes, 1, UINT64_MAX),
1318 m_memory_options ()
1319 {
1320 CommandArgumentEntry arg1;
1321 CommandArgumentEntry arg2;
1322 CommandArgumentData addr_arg;
1323 CommandArgumentData value_arg;
1324
1325 // Define the first (and only) variant of this arg.
1326 addr_arg.arg_type = eArgTypeAddress;
1327 addr_arg.arg_repetition = eArgRepeatPlain;
1328
1329 // There is only one variant this argument could be; put it into the argument entry.
1330 arg1.push_back (addr_arg);
1331
1332 // Define the first (and only) variant of this arg.
1333 value_arg.arg_type = eArgTypeValue;
1334 value_arg.arg_repetition = eArgRepeatPlus;
1335
1336 // There is only one variant this argument could be; put it into the argument entry.
1337 arg2.push_back (value_arg);
1338
1339 // Push the data for the first argument into the m_arguments vector.
1340 m_arguments.push_back (arg1);
1341 m_arguments.push_back (arg2);
1342
1343 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
1344 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
1345 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1346 m_option_group.Finalize();
1347
1348 }
1349
1350 virtual
~CommandObjectMemoryWrite()1351 ~CommandObjectMemoryWrite ()
1352 {
1353 }
1354
1355 Options *
GetOptions()1356 GetOptions ()
1357 {
1358 return &m_option_group;
1359 }
1360
1361 bool
UIntValueIsValidForSize(uint64_t uval64,size_t total_byte_size)1362 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
1363 {
1364 if (total_byte_size > 8)
1365 return false;
1366
1367 if (total_byte_size == 8)
1368 return true;
1369
1370 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1371 return uval64 <= max;
1372 }
1373
1374 bool
SIntValueIsValidForSize(int64_t sval64,size_t total_byte_size)1375 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
1376 {
1377 if (total_byte_size > 8)
1378 return false;
1379
1380 if (total_byte_size == 8)
1381 return true;
1382
1383 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1384 const int64_t min = ~(max);
1385 return min <= sval64 && sval64 <= max;
1386 }
1387
1388 protected:
1389 virtual bool
DoExecute(Args & command,CommandReturnObject & result)1390 DoExecute (Args& command, CommandReturnObject &result)
1391 {
1392 // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1393 Process *process = m_exe_ctx.GetProcessPtr();
1394
1395 const size_t argc = command.GetArgumentCount();
1396
1397 if (m_memory_options.m_infile)
1398 {
1399 if (argc < 1)
1400 {
1401 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
1402 result.SetStatus(eReturnStatusFailed);
1403 return false;
1404 }
1405 }
1406 else if (argc < 2)
1407 {
1408 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
1409 result.SetStatus(eReturnStatusFailed);
1410 return false;
1411 }
1412
1413 StreamString buffer (Stream::eBinary,
1414 process->GetTarget().GetArchitecture().GetAddressByteSize(),
1415 process->GetTarget().GetArchitecture().GetByteOrder());
1416
1417 OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1418 size_t item_byte_size = byte_size_value.GetCurrentValue();
1419
1420 Error error;
1421 lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1422 command.GetArgumentAtIndex(0),
1423 LLDB_INVALID_ADDRESS,
1424 &error);
1425
1426 if (addr == LLDB_INVALID_ADDRESS)
1427 {
1428 result.AppendError("invalid address expression\n");
1429 result.AppendError(error.AsCString());
1430 result.SetStatus(eReturnStatusFailed);
1431 return false;
1432 }
1433
1434 if (m_memory_options.m_infile)
1435 {
1436 size_t length = SIZE_MAX;
1437 if (item_byte_size > 0)
1438 length = item_byte_size;
1439 lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
1440 if (data_sp)
1441 {
1442 length = data_sp->GetByteSize();
1443 if (length > 0)
1444 {
1445 Error error;
1446 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
1447
1448 if (bytes_written == length)
1449 {
1450 // All bytes written
1451 result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
1452 result.SetStatus(eReturnStatusSuccessFinishResult);
1453 }
1454 else if (bytes_written > 0)
1455 {
1456 // Some byte written
1457 result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
1458 result.SetStatus(eReturnStatusSuccessFinishResult);
1459 }
1460 else
1461 {
1462 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1463 result.SetStatus(eReturnStatusFailed);
1464 }
1465 }
1466 }
1467 else
1468 {
1469 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1470 result.SetStatus(eReturnStatusFailed);
1471 }
1472 return result.Succeeded();
1473 }
1474 else if (item_byte_size == 0)
1475 {
1476 if (m_format_options.GetFormat() == eFormatPointer)
1477 item_byte_size = buffer.GetAddressByteSize();
1478 else
1479 item_byte_size = 1;
1480 }
1481
1482 command.Shift(); // shift off the address argument
1483 uint64_t uval64;
1484 int64_t sval64;
1485 bool success = false;
1486 const size_t num_value_args = command.GetArgumentCount();
1487 for (size_t i=0; i<num_value_args; ++i)
1488 {
1489 const char *value_str = command.GetArgumentAtIndex(i);
1490
1491 switch (m_format_options.GetFormat())
1492 {
1493 case kNumFormats:
1494 case eFormatFloat: // TODO: add support for floats soon
1495 case eFormatCharPrintable:
1496 case eFormatBytesWithASCII:
1497 case eFormatComplex:
1498 case eFormatEnum:
1499 case eFormatUnicode16:
1500 case eFormatUnicode32:
1501 case eFormatVectorOfChar:
1502 case eFormatVectorOfSInt8:
1503 case eFormatVectorOfUInt8:
1504 case eFormatVectorOfSInt16:
1505 case eFormatVectorOfUInt16:
1506 case eFormatVectorOfSInt32:
1507 case eFormatVectorOfUInt32:
1508 case eFormatVectorOfSInt64:
1509 case eFormatVectorOfUInt64:
1510 case eFormatVectorOfFloat32:
1511 case eFormatVectorOfFloat64:
1512 case eFormatVectorOfUInt128:
1513 case eFormatOSType:
1514 case eFormatComplexInteger:
1515 case eFormatAddressInfo:
1516 case eFormatHexFloat:
1517 case eFormatInstruction:
1518 case eFormatVoid:
1519 result.AppendError("unsupported format for writing memory");
1520 result.SetStatus(eReturnStatusFailed);
1521 return false;
1522
1523 case eFormatDefault:
1524 case eFormatBytes:
1525 case eFormatHex:
1526 case eFormatHexUppercase:
1527 case eFormatPointer:
1528
1529 // Decode hex bytes
1530 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1531 if (!success)
1532 {
1533 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1534 result.SetStatus(eReturnStatusFailed);
1535 return false;
1536 }
1537 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1538 {
1539 result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
1540 result.SetStatus(eReturnStatusFailed);
1541 return false;
1542 }
1543 buffer.PutMaxHex64 (uval64, item_byte_size);
1544 break;
1545
1546 case eFormatBoolean:
1547 uval64 = Args::StringToBoolean(value_str, false, &success);
1548 if (!success)
1549 {
1550 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1551 result.SetStatus(eReturnStatusFailed);
1552 return false;
1553 }
1554 buffer.PutMaxHex64 (uval64, item_byte_size);
1555 break;
1556
1557 case eFormatBinary:
1558 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1559 if (!success)
1560 {
1561 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1562 result.SetStatus(eReturnStatusFailed);
1563 return false;
1564 }
1565 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1566 {
1567 result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
1568 result.SetStatus(eReturnStatusFailed);
1569 return false;
1570 }
1571 buffer.PutMaxHex64 (uval64, item_byte_size);
1572 break;
1573
1574 case eFormatCharArray:
1575 case eFormatChar:
1576 case eFormatCString:
1577 if (value_str[0])
1578 {
1579 size_t len = strlen (value_str);
1580 // Include the NULL for C strings...
1581 if (m_format_options.GetFormat() == eFormatCString)
1582 ++len;
1583 Error error;
1584 if (process->WriteMemory (addr, value_str, len, error) == len)
1585 {
1586 addr += len;
1587 }
1588 else
1589 {
1590 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1591 result.SetStatus(eReturnStatusFailed);
1592 return false;
1593 }
1594 }
1595 break;
1596
1597 case eFormatDecimal:
1598 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1599 if (!success)
1600 {
1601 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1602 result.SetStatus(eReturnStatusFailed);
1603 return false;
1604 }
1605 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1606 {
1607 result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %zu byte signed integer value.\n", sval64, item_byte_size);
1608 result.SetStatus(eReturnStatusFailed);
1609 return false;
1610 }
1611 buffer.PutMaxHex64 (sval64, item_byte_size);
1612 break;
1613
1614 case eFormatUnsigned:
1615 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1616 if (!success)
1617 {
1618 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1619 result.SetStatus(eReturnStatusFailed);
1620 return false;
1621 }
1622 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1623 {
1624 result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
1625 result.SetStatus(eReturnStatusFailed);
1626 return false;
1627 }
1628 buffer.PutMaxHex64 (uval64, item_byte_size);
1629 break;
1630
1631 case eFormatOctal:
1632 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1633 if (!success)
1634 {
1635 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1636 result.SetStatus(eReturnStatusFailed);
1637 return false;
1638 }
1639 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1640 {
1641 result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %zu byte unsigned integer value.\n", uval64, item_byte_size);
1642 result.SetStatus(eReturnStatusFailed);
1643 return false;
1644 }
1645 buffer.PutMaxHex64 (uval64, item_byte_size);
1646 break;
1647 }
1648 }
1649
1650 if (!buffer.GetString().empty())
1651 {
1652 Error error;
1653 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1654 return true;
1655 else
1656 {
1657 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1658 result.SetStatus(eReturnStatusFailed);
1659 return false;
1660 }
1661 }
1662 return true;
1663 }
1664
1665 OptionGroupOptions m_option_group;
1666 OptionGroupFormat m_format_options;
1667 OptionGroupWriteMemory m_memory_options;
1668 };
1669
1670
1671 //-------------------------------------------------------------------------
1672 // CommandObjectMemory
1673 //-------------------------------------------------------------------------
1674
CommandObjectMemory(CommandInterpreter & interpreter)1675 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1676 CommandObjectMultiword (interpreter,
1677 "memory",
1678 "A set of commands for operating on memory.",
1679 "memory <subcommand> [<subcommand-options>]")
1680 {
1681 LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
1682 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1683 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1684 }
1685
~CommandObjectMemory()1686 CommandObjectMemory::~CommandObjectMemory ()
1687 {
1688 }
1689