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 "CommandObjectMemory.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/DataBufferHeap.h" 17 #include "lldb/Core/DataExtractor.h" 18 #include "lldb/Core/Debugger.h" 19 #include "lldb/Core/StreamString.h" 20 #include "lldb/Core/ValueObjectMemory.h" 21 #include "lldb/Interpreter/Args.h" 22 #include "lldb/Interpreter/CommandReturnObject.h" 23 #include "lldb/Interpreter/CommandInterpreter.h" 24 #include "lldb/Interpreter/Options.h" 25 #include "lldb/Interpreter/OptionGroupFormat.h" 26 #include "lldb/Interpreter/OptionGroupOutputFile.h" 27 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 28 #include "lldb/Symbol/ClangNamespaceDecl.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Target/StackFrame.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 static OptionDefinition 36 g_option_table[] = 37 { 38 { LLDB_OPT_SET_1| 39 LLDB_OPT_SET_2, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize ,"The size in bytes to use when displaying with the selected format."}, 40 { LLDB_OPT_SET_1| 41 LLDB_OPT_SET_3, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount ,"The number of total items to display."}, 42 { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."}, 43 { LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , 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."}, 44 { LLDB_OPT_SET_3, true , "view-as" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."}, 45 }; 46 47 48 49 class OptionGroupReadMemory : public OptionGroup 50 { 51 public: 52 53 OptionGroupReadMemory () : 54 m_byte_size (1,1), 55 m_count (8,8), 56 m_num_per_line (1,1), 57 m_output_as_binary (false), 58 m_view_as_type() 59 { 60 } 61 62 virtual 63 ~OptionGroupReadMemory () 64 { 65 } 66 67 68 virtual uint32_t 69 GetNumDefinitions () 70 { 71 return sizeof (g_option_table) / sizeof (OptionDefinition); 72 } 73 74 virtual const OptionDefinition* 75 GetDefinitions () 76 { 77 return g_option_table; 78 } 79 80 virtual Error 81 SetOptionValue (CommandInterpreter &interpreter, 82 uint32_t option_idx, 83 const char *option_arg) 84 { 85 Error error; 86 char short_option = (char) g_option_table[option_idx].short_option; 87 88 switch (short_option) 89 { 90 case 'l': 91 error = m_num_per_line.SetValueFromCString (option_arg); 92 if (m_num_per_line.GetCurrentValue() == 0) 93 error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg); 94 break; 95 96 case 'c': 97 error = m_count.SetValueFromCString (option_arg); 98 if (m_count.GetCurrentValue() == 0) 99 error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg); 100 break; 101 102 case 's': 103 error = m_byte_size.SetValueFromCString (option_arg); 104 if (m_byte_size.GetCurrentValue() == 0) 105 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); 106 break; 107 108 case 'b': 109 m_output_as_binary = true; 110 break; 111 112 case 't': 113 error = m_view_as_type.SetValueFromCString (option_arg); 114 break; 115 116 default: 117 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); 118 break; 119 } 120 return error; 121 } 122 123 virtual void 124 OptionParsingStarting (CommandInterpreter &interpreter) 125 { 126 m_byte_size.Clear(); 127 m_count.Clear(); 128 m_num_per_line.Clear(); 129 m_output_as_binary = false; 130 m_view_as_type.Clear(); 131 } 132 133 Error 134 FinalizeSettings (Target *target, const OptionGroupFormat& format_options) 135 { 136 Error error; 137 bool byte_size_option_set = m_byte_size.OptionWasSet(); 138 const bool num_per_line_option_set = m_num_per_line.OptionWasSet(); 139 const bool count_option_set = m_count.OptionWasSet(); 140 141 uint32_t format_byte_size = format_options.GetByteSize(); 142 if (byte_size_option_set) 143 { 144 if (format_byte_size > 0) 145 { 146 error.SetErrorString("can't specify the byte size in both the '--size <num>' option and the '--format [<byte-size>]<format-char>' options."); 147 return error; 148 } 149 } 150 else 151 { 152 if (format_byte_size != 0) 153 { 154 byte_size_option_set = true; 155 m_byte_size = format_byte_size; 156 } 157 } 158 159 switch (format_options.GetFormat()) 160 { 161 default: 162 break; 163 164 case eFormatBoolean: 165 if (!byte_size_option_set) 166 m_byte_size = 1; 167 if (!num_per_line_option_set) 168 m_num_per_line = 1; 169 if (!count_option_set) 170 m_count = 8; 171 break; 172 173 case eFormatCString: 174 break; 175 176 case eFormatPointer: 177 m_byte_size = target->GetArchitecture().GetAddressByteSize(); 178 if (!num_per_line_option_set) 179 m_num_per_line = 4; 180 if (!count_option_set) 181 m_count = 8; 182 break; 183 184 case eFormatBinary: 185 case eFormatFloat: 186 case eFormatOctal: 187 case eFormatDecimal: 188 case eFormatEnum: 189 case eFormatUnicode16: 190 case eFormatUnicode32: 191 case eFormatUnsigned: 192 if (!byte_size_option_set) 193 m_byte_size = 4; 194 if (!num_per_line_option_set) 195 m_num_per_line = 1; 196 if (!count_option_set) 197 m_count = 8; 198 break; 199 200 case eFormatBytes: 201 case eFormatBytesWithASCII: 202 if (m_byte_size.OptionWasSet()) 203 { 204 if (m_byte_size > 1) 205 error.SetErrorString ("use --count option to specify an end address to display a number of bytes"); 206 } 207 else 208 m_byte_size = 1; 209 if (!num_per_line_option_set) 210 m_num_per_line = 16; 211 if (!count_option_set) 212 m_count = 32; 213 break; 214 case eFormatCharArray: 215 case eFormatChar: 216 case eFormatCharPrintable: 217 if (!byte_size_option_set) 218 m_byte_size = 1; 219 if (!num_per_line_option_set) 220 m_num_per_line = 32; 221 if (!count_option_set) 222 m_count = 64; 223 break; 224 case eFormatComplex: 225 if (!byte_size_option_set) 226 m_byte_size = 8; 227 if (!num_per_line_option_set) 228 m_num_per_line = 1; 229 if (!count_option_set) 230 m_count = 8; 231 break; 232 case eFormatHex: 233 if (!byte_size_option_set) 234 m_byte_size = 4; 235 if (!num_per_line_option_set) 236 { 237 switch (m_byte_size) 238 { 239 case 1: 240 case 2: 241 m_num_per_line = 8; 242 break; 243 case 4: 244 m_num_per_line = 4; 245 break; 246 case 8: 247 m_num_per_line = 2; 248 break; 249 default: 250 m_num_per_line = 1; 251 break; 252 } 253 } 254 if (!count_option_set) 255 m_count = 8; 256 break; 257 258 case eFormatVectorOfChar: 259 case eFormatVectorOfSInt8: 260 case eFormatVectorOfUInt8: 261 case eFormatVectorOfSInt16: 262 case eFormatVectorOfUInt16: 263 case eFormatVectorOfSInt32: 264 case eFormatVectorOfUInt32: 265 case eFormatVectorOfSInt64: 266 case eFormatVectorOfUInt64: 267 case eFormatVectorOfFloat32: 268 case eFormatVectorOfFloat64: 269 case eFormatVectorOfUInt128: 270 if (!byte_size_option_set) 271 m_byte_size = 128; 272 if (!num_per_line_option_set) 273 m_num_per_line = 1; 274 if (!count_option_set) 275 m_count = 4; 276 break; 277 } 278 return error; 279 } 280 281 OptionValueUInt64 m_byte_size; 282 OptionValueUInt64 m_count; 283 OptionValueUInt64 m_num_per_line; 284 bool m_output_as_binary; 285 OptionValueString m_view_as_type; 286 }; 287 288 289 290 //---------------------------------------------------------------------- 291 // Read memory from the inferior process 292 //---------------------------------------------------------------------- 293 class CommandObjectMemoryRead : public CommandObject 294 { 295 public: 296 297 CommandObjectMemoryRead (CommandInterpreter &interpreter) : 298 CommandObject (interpreter, 299 "memory read", 300 "Read from the memory of the process being debugged.", 301 NULL, 302 eFlagProcessMustBePaused), 303 m_option_group (interpreter), 304 m_format_options (eFormatBytesWithASCII, 0, true), 305 m_memory_options (), 306 m_outfile_options (), 307 m_varobj_options() 308 { 309 CommandArgumentEntry arg1; 310 CommandArgumentEntry arg2; 311 CommandArgumentData start_addr_arg; 312 CommandArgumentData end_addr_arg; 313 314 // Define the first (and only) variant of this arg. 315 start_addr_arg.arg_type = eArgTypeStartAddress; 316 start_addr_arg.arg_repetition = eArgRepeatPlain; 317 318 // There is only one variant this argument could be; put it into the argument entry. 319 arg1.push_back (start_addr_arg); 320 321 // Define the first (and only) variant of this arg. 322 end_addr_arg.arg_type = eArgTypeEndAddress; 323 end_addr_arg.arg_repetition = eArgRepeatOptional; 324 325 // There is only one variant this argument could be; put it into the argument entry. 326 arg2.push_back (end_addr_arg); 327 328 // Push the data for the first argument into the m_arguments vector. 329 m_arguments.push_back (arg1); 330 m_arguments.push_back (arg2); 331 332 m_option_group.Append (&m_format_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_3); 333 m_option_group.Append (&m_memory_options); 334 m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); 335 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3); 336 m_option_group.Finalize(); 337 } 338 339 virtual 340 ~CommandObjectMemoryRead () 341 { 342 } 343 344 Options * 345 GetOptions () 346 { 347 return &m_option_group; 348 } 349 350 virtual bool 351 Execute (Args& command, 352 CommandReturnObject &result) 353 { 354 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 355 Target *target = exe_ctx.GetTargetPtr(); 356 if (target == NULL) 357 { 358 result.AppendError("need at least a target to read memory"); 359 result.SetStatus(eReturnStatusFailed); 360 return false; 361 } 362 const size_t argc = command.GetArgumentCount(); 363 364 365 if (argc == 0 || argc > 2) 366 { 367 result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str()); 368 result.SetStatus(eReturnStatusFailed); 369 return false; 370 } 371 372 ClangASTType clang_ast_type; 373 Error error; 374 375 Format format = m_format_options.GetFormat(); 376 const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue(); 377 if (view_as_type_cstr && view_as_type_cstr[0]) 378 { 379 // We are viewing memory as a type 380 SymbolContext sc; 381 const bool append = true; 382 TypeList type_list; 383 uint32_t reference_count = 0; 384 uint32_t pointer_count = 0; 385 size_t idx; 386 static const char *g_keywords[] = { "const", "volatile", "restrict", "struct", "class", "union"}; 387 static size_t g_num_keywords = sizeof(g_keywords)/sizeof(const char *); 388 std::string type_str(view_as_type_cstr); 389 390 // Remove all instances of g_keywords that are followed by spaces 391 for (size_t i = 0; i < g_num_keywords; ++i) 392 { 393 const char *keyword = g_keywords[i]; 394 int keyword_len = ::strlen (keyword); 395 while ((idx = type_str.find (keyword)) != std::string::npos) 396 { 397 if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t') 398 type_str.erase(idx, keyword_len+1); 399 } 400 } 401 bool done = type_str.empty(); 402 // 403 idx = type_str.find_first_not_of (" \t"); 404 if (idx > 0 && idx != std::string::npos) 405 type_str.erase (0, idx); 406 while (!done) 407 { 408 // Strip trailing spaces 409 if (type_str.empty()) 410 done = true; 411 else 412 { 413 switch (type_str[type_str.size()-1]) 414 { 415 case '*': 416 ++pointer_count; 417 // fall through... 418 case ' ': 419 case '\t': 420 type_str.erase(type_str.size()-1); 421 break; 422 423 case '&': 424 if (reference_count == 0) 425 { 426 reference_count = 1; 427 type_str.erase(type_str.size()-1); 428 } 429 else 430 { 431 result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr); 432 result.SetStatus(eReturnStatusFailed); 433 return false; 434 } 435 break; 436 437 default: 438 done = true; 439 break; 440 } 441 } 442 } 443 444 ConstString lookup_type_name(type_str.c_str()); 445 StackFrame *frame = exe_ctx.GetFramePtr(); 446 if (frame) 447 { 448 sc = frame->GetSymbolContext (eSymbolContextModule); 449 if (sc.module_sp) 450 { 451 sc.module_sp->FindTypes (sc, 452 lookup_type_name, 453 NULL, 454 append, 455 1, 456 type_list); 457 } 458 } 459 if (type_list.GetSize() == 0) 460 { 461 target->GetImages().FindTypes (sc, 462 lookup_type_name, 463 append, 464 1, 465 type_list); 466 } 467 468 if (type_list.GetSize() == 0) 469 { 470 result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n", 471 lookup_type_name.GetCString(), 472 view_as_type_cstr); 473 result.SetStatus(eReturnStatusFailed); 474 return false; 475 } 476 477 TypeSP type_sp (type_list.GetTypeAtIndex(0)); 478 clang_ast_type.SetClangType (type_sp->GetClangAST(), type_sp->GetClangFullType()); 479 480 while (pointer_count > 0) 481 { 482 clang_type_t pointer_type = ClangASTContext::CreatePointerType (clang_ast_type.GetASTContext(), clang_ast_type.GetOpaqueQualType()); 483 if (pointer_type) 484 clang_ast_type.SetClangType (clang_ast_type.GetASTContext(), pointer_type); 485 else 486 { 487 result.AppendError ("unable make a pointer type\n"); 488 result.SetStatus(eReturnStatusFailed); 489 return false; 490 } 491 --pointer_count; 492 } 493 494 m_memory_options.m_byte_size = (clang_ast_type.GetClangTypeBitWidth () + 7) / 8; 495 496 if (m_memory_options.m_byte_size == 0) 497 { 498 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n", 499 view_as_type_cstr); 500 result.SetStatus(eReturnStatusFailed); 501 return false; 502 } 503 504 if (!m_memory_options.m_count.OptionWasSet()) 505 m_memory_options.m_count = 1; 506 } 507 else 508 { 509 error = m_memory_options.FinalizeSettings (target, m_format_options); 510 } 511 512 // Look for invalid combinations of settings 513 if (error.Fail()) 514 { 515 result.AppendErrorWithFormat("%s", error.AsCString()); 516 result.SetStatus(eReturnStatusFailed); 517 return false; 518 } 519 520 size_t item_count = m_memory_options.m_count.GetCurrentValue(); 521 const size_t item_byte_size = m_memory_options.m_byte_size; 522 const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue(); 523 524 size_t total_byte_size = item_count * item_byte_size; 525 if (total_byte_size == 0) 526 total_byte_size = 32; 527 528 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); 529 530 if (addr == LLDB_INVALID_ADDRESS) 531 { 532 result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0)); 533 result.SetStatus(eReturnStatusFailed); 534 return false; 535 } 536 537 if (argc == 2) 538 { 539 lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0); 540 if (end_addr == LLDB_INVALID_ADDRESS) 541 { 542 result.AppendErrorWithFormat("invalid end address string '%s'.\n", command.GetArgumentAtIndex(1)); 543 result.SetStatus(eReturnStatusFailed); 544 return false; 545 } 546 else if (end_addr <= addr) 547 { 548 result.AppendErrorWithFormat("end address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr); 549 result.SetStatus(eReturnStatusFailed); 550 return false; 551 } 552 else if (m_memory_options.m_count.OptionWasSet()) 553 { 554 result.AppendErrorWithFormat("specify either the end address (0x%llx) or the count (--count %lu), not both.\n", end_addr, item_count); 555 result.SetStatus(eReturnStatusFailed); 556 return false; 557 } 558 559 total_byte_size = end_addr - addr; 560 item_count = total_byte_size / item_byte_size; 561 } 562 563 DataBufferSP data_sp; 564 size_t bytes_read = 0; 565 if (!clang_ast_type.GetOpaqueQualType()) 566 { 567 data_sp.reset (new DataBufferHeap (total_byte_size, '\0')); 568 Address address(NULL, addr); 569 bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error); 570 if (bytes_read == 0) 571 { 572 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr); 573 result.AppendError(error.AsCString()); 574 result.SetStatus(eReturnStatusFailed); 575 return false; 576 } 577 578 if (bytes_read < total_byte_size) 579 result.AppendWarningWithFormat("Not all bytes (%lu/%lu) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr); 580 } 581 582 StreamFile outfile_stream; 583 Stream *output_stream = NULL; 584 const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue(); 585 if (outfile_spec) 586 { 587 char path[PATH_MAX]; 588 outfile_spec.GetPath (path, sizeof(path)); 589 590 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 591 const bool append = m_outfile_options.GetAppend().GetCurrentValue(); 592 if (append) 593 open_options |= File::eOpenOptionAppend; 594 595 if (outfile_stream.GetFile ().Open (path, open_options).Success()) 596 { 597 if (m_memory_options.m_output_as_binary) 598 { 599 int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read); 600 if (bytes_written > 0) 601 { 602 result.GetOutputStream().Printf ("%i bytes %s to '%s'\n", 603 bytes_written, 604 append ? "appended" : "written", 605 path); 606 return true; 607 } 608 else 609 { 610 result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path); 611 result.SetStatus(eReturnStatusFailed); 612 return false; 613 } 614 } 615 else 616 { 617 // We are going to write ASCII to the file just point the 618 // output_stream to our outfile_stream... 619 output_stream = &outfile_stream; 620 } 621 } 622 else 623 { 624 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write"); 625 result.SetStatus(eReturnStatusFailed); 626 return false; 627 } 628 } 629 else 630 { 631 output_stream = &result.GetOutputStream(); 632 } 633 634 635 if (clang_ast_type.GetOpaqueQualType()) 636 { 637 for (uint32_t i = 0; i<item_count; ++i) 638 { 639 addr_t item_addr = addr + (i * item_byte_size); 640 Address address (NULL, item_addr); 641 StreamString name_strm; 642 name_strm.Printf ("0x%llx", item_addr); 643 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), 644 name_strm.GetString().c_str(), 645 address, 646 clang_ast_type)); 647 if (valobj_sp) 648 { 649 if (format != eFormatDefault) 650 valobj_sp->SetFormat (format); 651 652 bool scope_already_checked = true; 653 654 ValueObject::DumpValueObject (*output_stream, 655 valobj_sp.get(), 656 NULL, 657 m_varobj_options.ptr_depth, 658 0, 659 m_varobj_options.max_depth, 660 m_varobj_options.show_types, 661 m_varobj_options.show_location, 662 m_varobj_options.use_objc, 663 m_varobj_options.use_dynamic, 664 m_varobj_options.be_raw ? false : m_varobj_options.use_synth, 665 scope_already_checked, 666 m_varobj_options.flat_output, 667 m_varobj_options.be_raw ? UINT32_MAX : m_varobj_options.no_summary_depth, 668 m_varobj_options.be_raw ? true : m_varobj_options.ignore_cap); 669 } 670 else 671 { 672 result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n", 673 view_as_type_cstr, 674 name_strm.GetString().c_str()); 675 result.SetStatus(eReturnStatusFailed); 676 return false; 677 } 678 } 679 return true; 680 } 681 682 result.SetStatus(eReturnStatusSuccessFinishResult); 683 DataExtractor data (data_sp, 684 target->GetArchitecture().GetByteOrder(), 685 target->GetArchitecture().GetAddressByteSize()); 686 687 688 assert (output_stream); 689 data.Dump (output_stream, 690 0, 691 m_format_options.GetFormat(), 692 item_byte_size, 693 item_count, 694 num_per_line, 695 addr, 696 0, 697 0); 698 output_stream->EOL(); 699 return true; 700 } 701 702 protected: 703 OptionGroupOptions m_option_group; 704 OptionGroupFormat m_format_options; 705 OptionGroupReadMemory m_memory_options; 706 OptionGroupOutputFile m_outfile_options; 707 OptionGroupValueObjectDisplay m_varobj_options; 708 709 }; 710 711 //---------------------------------------------------------------------- 712 // Write memory to the inferior process 713 //---------------------------------------------------------------------- 714 class CommandObjectMemoryWrite : public CommandObject 715 { 716 public: 717 718 class CommandOptions : public Options 719 { 720 public: 721 CommandOptions (CommandInterpreter &interpreter) : 722 Options(interpreter) 723 { 724 OptionParsingStarting(); 725 } 726 727 virtual 728 ~CommandOptions () 729 { 730 } 731 732 virtual Error 733 SetOptionValue (uint32_t option_idx, const char *option_arg) 734 { 735 Error error; 736 char short_option = (char) m_getopt_table[option_idx].val; 737 switch (short_option) 738 { 739 case 'f': 740 error = Args::StringToFormat (option_arg, m_format, &m_byte_size); 741 break; 742 743 case 's': 744 m_byte_size = Args::StringToUInt32 (option_arg, 0); 745 if (m_byte_size == 0) 746 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); 747 break; 748 749 case 'i': 750 m_infile.SetFile (option_arg, true); 751 if (!m_infile.Exists()) 752 { 753 m_infile.Clear(); 754 error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg); 755 } 756 break; 757 758 case 'o': 759 { 760 bool success; 761 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success); 762 if (!success) 763 { 764 error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg); 765 } 766 } 767 break; 768 769 default: 770 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option); 771 break; 772 } 773 return error; 774 } 775 776 void 777 OptionParsingStarting () 778 { 779 m_format = eFormatBytes; 780 m_byte_size = 1; 781 m_infile.Clear(); 782 m_infile_offset = 0; 783 } 784 785 const OptionDefinition* 786 GetDefinitions () 787 { 788 return g_option_table; 789 } 790 791 // Options table: Required for subclasses of Options. 792 793 static OptionDefinition g_option_table[]; 794 795 // Instance variables to hold the values for command options. 796 lldb::Format m_format; 797 uint32_t m_byte_size; 798 FileSpec m_infile; 799 off_t m_infile_offset; 800 }; 801 802 CommandObjectMemoryWrite (CommandInterpreter &interpreter) : 803 CommandObject (interpreter, 804 "memory write", 805 "Write to the memory of the process being debugged.", 806 //"memory write [<cmd-options>] <addr> [value1 value2 ...]", 807 NULL, 808 eFlagProcessMustBeLaunched), 809 m_options (interpreter) 810 { 811 CommandArgumentEntry arg1; 812 CommandArgumentEntry arg2; 813 CommandArgumentData addr_arg; 814 CommandArgumentData value_arg; 815 816 // Define the first (and only) variant of this arg. 817 addr_arg.arg_type = eArgTypeAddress; 818 addr_arg.arg_repetition = eArgRepeatPlain; 819 820 // There is only one variant this argument could be; put it into the argument entry. 821 arg1.push_back (addr_arg); 822 823 // Define the first (and only) variant of this arg. 824 value_arg.arg_type = eArgTypeValue; 825 value_arg.arg_repetition = eArgRepeatPlus; 826 827 // There is only one variant this argument could be; put it into the argument entry. 828 arg2.push_back (value_arg); 829 830 // Push the data for the first argument into the m_arguments vector. 831 m_arguments.push_back (arg1); 832 m_arguments.push_back (arg2); 833 } 834 835 virtual 836 ~CommandObjectMemoryWrite () 837 { 838 } 839 840 Options * 841 GetOptions () 842 { 843 return &m_options; 844 } 845 846 bool 847 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) 848 { 849 if (total_byte_size > 8) 850 return false; 851 852 if (total_byte_size == 8) 853 return true; 854 855 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; 856 return uval64 <= max; 857 } 858 859 bool 860 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) 861 { 862 if (total_byte_size > 8) 863 return false; 864 865 if (total_byte_size == 8) 866 return true; 867 868 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; 869 const int64_t min = ~(max); 870 return min <= sval64 && sval64 <= max; 871 } 872 873 virtual bool 874 Execute (Args& command, 875 CommandReturnObject &result) 876 { 877 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr(); 878 if (process == NULL) 879 { 880 result.AppendError("need a process to read memory"); 881 result.SetStatus(eReturnStatusFailed); 882 return false; 883 } 884 885 const size_t argc = command.GetArgumentCount(); 886 887 if (m_options.m_infile) 888 { 889 if (argc < 1) 890 { 891 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); 892 result.SetStatus(eReturnStatusFailed); 893 return false; 894 } 895 } 896 else if (argc < 2) 897 { 898 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); 899 result.SetStatus(eReturnStatusFailed); 900 return false; 901 } 902 903 StreamString buffer (Stream::eBinary, 904 process->GetTarget().GetArchitecture().GetAddressByteSize(), 905 process->GetTarget().GetArchitecture().GetByteOrder()); 906 907 size_t item_byte_size = m_options.m_byte_size; 908 909 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); 910 911 if (addr == LLDB_INVALID_ADDRESS) 912 { 913 result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); 914 result.SetStatus(eReturnStatusFailed); 915 return false; 916 } 917 918 if (m_options.m_infile) 919 { 920 size_t length = SIZE_MAX; 921 if (m_options.m_byte_size > 0) 922 length = m_options.m_byte_size; 923 lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length)); 924 if (data_sp) 925 { 926 length = data_sp->GetByteSize(); 927 if (length > 0) 928 { 929 Error error; 930 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); 931 932 if (bytes_written == length) 933 { 934 // All bytes written 935 result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr); 936 result.SetStatus(eReturnStatusSuccessFinishResult); 937 } 938 else if (bytes_written > 0) 939 { 940 // Some byte written 941 result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr); 942 result.SetStatus(eReturnStatusSuccessFinishResult); 943 } 944 else 945 { 946 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 947 result.SetStatus(eReturnStatusFailed); 948 } 949 } 950 } 951 else 952 { 953 result.AppendErrorWithFormat ("Unable to read contents of file.\n"); 954 result.SetStatus(eReturnStatusFailed); 955 } 956 return result.Succeeded(); 957 } 958 else if (m_options.m_byte_size == 0) 959 { 960 if (m_options.m_format == eFormatPointer) 961 item_byte_size = buffer.GetAddressByteSize(); 962 else 963 item_byte_size = 1; 964 } 965 966 command.Shift(); // shift off the address argument 967 uint64_t uval64; 968 int64_t sval64; 969 bool success = false; 970 const uint32_t num_value_args = command.GetArgumentCount(); 971 uint32_t i; 972 for (i=0; i<num_value_args; ++i) 973 { 974 const char *value_str = command.GetArgumentAtIndex(i); 975 976 switch (m_options.m_format) 977 { 978 case kNumFormats: 979 case eFormatFloat: // TODO: add support for floats soon 980 case eFormatCharPrintable: 981 case eFormatBytesWithASCII: 982 case eFormatComplex: 983 case eFormatEnum: 984 case eFormatUnicode16: 985 case eFormatUnicode32: 986 case eFormatVectorOfChar: 987 case eFormatVectorOfSInt8: 988 case eFormatVectorOfUInt8: 989 case eFormatVectorOfSInt16: 990 case eFormatVectorOfUInt16: 991 case eFormatVectorOfSInt32: 992 case eFormatVectorOfUInt32: 993 case eFormatVectorOfSInt64: 994 case eFormatVectorOfUInt64: 995 case eFormatVectorOfFloat32: 996 case eFormatVectorOfFloat64: 997 case eFormatVectorOfUInt128: 998 case eFormatOSType: 999 case eFormatComplexInteger: 1000 result.AppendError("unsupported format for writing memory"); 1001 result.SetStatus(eReturnStatusFailed); 1002 return false; 1003 1004 case eFormatDefault: 1005 case eFormatBytes: 1006 case eFormatHex: 1007 case eFormatPointer: 1008 1009 // Decode hex bytes 1010 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); 1011 if (!success) 1012 { 1013 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); 1014 result.SetStatus(eReturnStatusFailed); 1015 return false; 1016 } 1017 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1018 { 1019 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1020 result.SetStatus(eReturnStatusFailed); 1021 return false; 1022 } 1023 buffer.PutMaxHex64 (uval64, item_byte_size); 1024 break; 1025 1026 case eFormatBoolean: 1027 uval64 = Args::StringToBoolean(value_str, false, &success); 1028 if (!success) 1029 { 1030 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); 1031 result.SetStatus(eReturnStatusFailed); 1032 return false; 1033 } 1034 buffer.PutMaxHex64 (uval64, item_byte_size); 1035 break; 1036 1037 case eFormatBinary: 1038 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); 1039 if (!success) 1040 { 1041 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); 1042 result.SetStatus(eReturnStatusFailed); 1043 return false; 1044 } 1045 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1046 { 1047 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1048 result.SetStatus(eReturnStatusFailed); 1049 return false; 1050 } 1051 buffer.PutMaxHex64 (uval64, item_byte_size); 1052 break; 1053 1054 case eFormatCharArray: 1055 case eFormatChar: 1056 case eFormatCString: 1057 if (value_str[0]) 1058 { 1059 size_t len = strlen (value_str); 1060 // Include the NULL for C strings... 1061 if (m_options.m_format == eFormatCString) 1062 ++len; 1063 Error error; 1064 if (process->WriteMemory (addr, value_str, len, error) == len) 1065 { 1066 addr += len; 1067 } 1068 else 1069 { 1070 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1071 result.SetStatus(eReturnStatusFailed); 1072 return false; 1073 } 1074 } 1075 break; 1076 1077 case eFormatDecimal: 1078 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); 1079 if (!success) 1080 { 1081 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); 1082 result.SetStatus(eReturnStatusFailed); 1083 return false; 1084 } 1085 else if (!SIntValueIsValidForSize (sval64, item_byte_size)) 1086 { 1087 result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size); 1088 result.SetStatus(eReturnStatusFailed); 1089 return false; 1090 } 1091 buffer.PutMaxHex64 (sval64, item_byte_size); 1092 break; 1093 1094 case eFormatUnsigned: 1095 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); 1096 if (!success) 1097 { 1098 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); 1099 result.SetStatus(eReturnStatusFailed); 1100 return false; 1101 } 1102 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1103 { 1104 result.AppendErrorWithFormat ("Value %llu is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1105 result.SetStatus(eReturnStatusFailed); 1106 return false; 1107 } 1108 buffer.PutMaxHex64 (uval64, item_byte_size); 1109 break; 1110 1111 case eFormatOctal: 1112 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); 1113 if (!success) 1114 { 1115 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); 1116 result.SetStatus(eReturnStatusFailed); 1117 return false; 1118 } 1119 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1120 { 1121 result.AppendErrorWithFormat ("Value %llo is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1122 result.SetStatus(eReturnStatusFailed); 1123 return false; 1124 } 1125 buffer.PutMaxHex64 (uval64, item_byte_size); 1126 break; 1127 } 1128 } 1129 1130 if (!buffer.GetString().empty()) 1131 { 1132 Error error; 1133 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) 1134 return true; 1135 else 1136 { 1137 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1138 result.SetStatus(eReturnStatusFailed); 1139 return false; 1140 } 1141 } 1142 return true; 1143 } 1144 1145 protected: 1146 CommandOptions m_options; 1147 }; 1148 1149 #define SET1 LLDB_OPT_SET_1 1150 #define SET2 LLDB_OPT_SET_2 1151 1152 OptionDefinition 1153 CommandObjectMemoryWrite::CommandOptions::g_option_table[] = 1154 { 1155 { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format value types that will be decoded and written to memory."}, 1156 { SET1 | SET2, false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."}, 1157 { SET2, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."}, 1158 { SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, 1159 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 1160 }; 1161 1162 #undef SET1 1163 #undef SET2 1164 1165 //------------------------------------------------------------------------- 1166 // CommandObjectMemory 1167 //------------------------------------------------------------------------- 1168 1169 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : 1170 CommandObjectMultiword (interpreter, 1171 "memory", 1172 "A set of commands for operating on memory.", 1173 "memory <subcommand> [<subcommand-options>]") 1174 { 1175 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); 1176 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); 1177 } 1178 1179 CommandObjectMemory::~CommandObjectMemory () 1180 { 1181 } 1182