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/Interpreter/Args.h" 21 #include "lldb/Interpreter/CommandReturnObject.h" 22 #include "lldb/Interpreter/CommandInterpreter.h" 23 #include "lldb/Interpreter/Options.h" 24 #include "lldb/Target/Process.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //---------------------------------------------------------------------- 30 // Read memory from the inferior process 31 //---------------------------------------------------------------------- 32 class CommandObjectMemoryRead : public CommandObject 33 { 34 public: 35 36 class CommandOptions : public Options 37 { 38 public: 39 CommandOptions () : 40 Options() 41 { 42 ResetOptionValues(); 43 } 44 45 virtual 46 ~CommandOptions () 47 { 48 } 49 50 virtual Error 51 SetOptionValue (int option_idx, const char *option_arg) 52 { 53 Error error; 54 char short_option = (char) m_getopt_table[option_idx].val; 55 56 switch (short_option) 57 { 58 case 'f': 59 error = Args::StringToFormat (option_arg, m_format); 60 61 switch (m_format) 62 { 63 default: 64 break; 65 66 case eFormatBoolean: 67 if (m_byte_size == 0) 68 m_byte_size = 1; 69 if (m_num_per_line == 0) 70 m_num_per_line = 1; 71 break; 72 73 case eFormatCString: 74 if (m_num_per_line == 0) 75 m_num_per_line = 1; 76 break; 77 78 case eFormatPointer: 79 break; 80 81 case eFormatBinary: 82 case eFormatFloat: 83 case eFormatOctal: 84 case eFormatDecimal: 85 case eFormatEnum: 86 case eFormatUnicode16: 87 case eFormatUnicode32: 88 case eFormatUnsigned: 89 if (m_byte_size == 0) 90 m_byte_size = 4; 91 if (m_num_per_line == 0) 92 m_num_per_line = 1; 93 break; 94 95 case eFormatBytes: 96 case eFormatBytesWithASCII: 97 case eFormatChar: 98 case eFormatCharPrintable: 99 if (m_byte_size == 0) 100 m_byte_size = 1; 101 break; 102 case eFormatComplex: 103 if (m_byte_size == 0) 104 m_byte_size = 8; 105 break; 106 case eFormatHex: 107 if (m_byte_size == 0) 108 m_byte_size = 4; 109 break; 110 111 case eFormatVectorOfChar: 112 case eFormatVectorOfSInt8: 113 case eFormatVectorOfUInt8: 114 case eFormatVectorOfSInt16: 115 case eFormatVectorOfUInt16: 116 case eFormatVectorOfSInt32: 117 case eFormatVectorOfUInt32: 118 case eFormatVectorOfSInt64: 119 case eFormatVectorOfUInt64: 120 case eFormatVectorOfFloat32: 121 case eFormatVectorOfFloat64: 122 case eFormatVectorOfUInt128: 123 break; 124 } 125 break; 126 127 case 'l': 128 m_num_per_line = Args::StringToUInt32 (option_arg, 0); 129 if (m_num_per_line == 0) 130 error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg); 131 break; 132 133 case 'c': 134 m_count = Args::StringToUInt32 (option_arg, 0); 135 if (m_count == 0) 136 error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg); 137 break; 138 139 case 's': 140 m_byte_size = Args::StringToUInt32 (option_arg, 0); 141 if (m_byte_size == 0) 142 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); 143 break; 144 145 case 'o': 146 m_outfile_filespec.SetFile (option_arg, true); 147 break; 148 149 case 'b': 150 m_output_as_binary = true; 151 break; 152 153 case 'a': 154 m_append_to_outfile = true; 155 break; 156 157 default: 158 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); 159 break; 160 } 161 return error; 162 } 163 164 void 165 ResetOptionValues () 166 { 167 Options::ResetOptionValues(); 168 m_format = eFormatBytesWithASCII; 169 m_byte_size = 0; 170 m_count = 0; 171 m_num_per_line = 0; 172 m_outfile_filespec.Clear(); 173 m_append_to_outfile = false; 174 m_output_as_binary = false; 175 } 176 177 const lldb::OptionDefinition* 178 GetDefinitions () 179 { 180 return g_option_table; 181 } 182 183 // Options table: Required for subclasses of Options. 184 185 static lldb::OptionDefinition g_option_table[]; 186 187 // Instance variables to hold the values for command options. 188 lldb::Format m_format; 189 uint32_t m_byte_size; 190 uint32_t m_count; 191 uint32_t m_num_per_line; 192 FileSpec m_outfile_filespec; 193 bool m_append_to_outfile; 194 bool m_output_as_binary; 195 }; 196 197 CommandObjectMemoryRead (CommandInterpreter &interpreter) : 198 CommandObject (interpreter, 199 "memory read", 200 "Read from the memory of the process being debugged.", 201 NULL, 202 eFlagProcessMustBeLaunched) 203 { 204 CommandArgumentEntry arg1; 205 CommandArgumentEntry arg2; 206 CommandArgumentData start_addr_arg; 207 CommandArgumentData end_addr_arg; 208 209 // Define the first (and only) variant of this arg. 210 start_addr_arg.arg_type = eArgTypeStartAddress; 211 start_addr_arg.arg_repetition = eArgRepeatPlain; 212 213 // There is only one variant this argument could be; put it into the argument entry. 214 arg1.push_back (start_addr_arg); 215 216 // Define the first (and only) variant of this arg. 217 end_addr_arg.arg_type = eArgTypeEndAddress; 218 end_addr_arg.arg_repetition = eArgRepeatOptional; 219 220 // There is only one variant this argument could be; put it into the argument entry. 221 arg2.push_back (end_addr_arg); 222 223 // Push the data for the first argument into the m_arguments vector. 224 m_arguments.push_back (arg1); 225 m_arguments.push_back (arg2); 226 } 227 228 virtual 229 ~CommandObjectMemoryRead () 230 { 231 } 232 233 Options * 234 GetOptions () 235 { 236 return &m_options; 237 } 238 239 virtual bool 240 Execute (Args& command, 241 CommandReturnObject &result) 242 { 243 Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; 244 if (process == NULL) 245 { 246 result.AppendError("need a process to read memory"); 247 result.SetStatus(eReturnStatusFailed); 248 return false; 249 } 250 const size_t argc = command.GetArgumentCount(); 251 252 if (argc == 0 || argc > 2) 253 { 254 result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str()); 255 result.SetStatus(eReturnStatusFailed); 256 return false; 257 } 258 259 size_t item_byte_size = m_options.m_byte_size; 260 if (item_byte_size == 0) 261 { 262 if (m_options.m_format == eFormatPointer) 263 item_byte_size = process->GetAddressByteSize(); 264 else 265 item_byte_size = 1; 266 } 267 268 size_t item_count = m_options.m_count; 269 270 size_t num_per_line = m_options.m_num_per_line; 271 if (num_per_line == 0) 272 { 273 num_per_line = (16/item_byte_size); 274 if (num_per_line == 0) 275 num_per_line = 1; 276 } 277 278 size_t total_byte_size = m_options.m_count * item_byte_size; 279 if (total_byte_size == 0) 280 total_byte_size = 32; 281 282 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); 283 284 if (addr == LLDB_INVALID_ADDRESS) 285 { 286 result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0)); 287 result.SetStatus(eReturnStatusFailed); 288 return false; 289 } 290 291 if (argc == 2) 292 { 293 lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0); 294 if (end_addr == LLDB_INVALID_ADDRESS) 295 { 296 result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1)); 297 result.SetStatus(eReturnStatusFailed); 298 return false; 299 } 300 else if (end_addr <= addr) 301 { 302 result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr); 303 result.SetStatus(eReturnStatusFailed); 304 return false; 305 } 306 else if (item_count != 0) 307 { 308 result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count); 309 result.SetStatus(eReturnStatusFailed); 310 return false; 311 } 312 313 total_byte_size = end_addr - addr; 314 item_count = total_byte_size / item_byte_size; 315 } 316 else 317 { 318 if (item_count == 0) 319 item_count = 32; 320 } 321 322 DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0')); 323 Error error; 324 size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error); 325 if (bytes_read == 0) 326 { 327 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr); 328 result.AppendError(error.AsCString()); 329 result.SetStatus(eReturnStatusFailed); 330 return false; 331 } 332 333 if (bytes_read < total_byte_size) 334 result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr); 335 336 result.SetStatus(eReturnStatusSuccessFinishResult); 337 DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize()); 338 339 StreamFile outfile_stream; 340 Stream *output_stream = NULL; 341 342 if (m_options.m_outfile_filespec) 343 { 344 char path[PATH_MAX]; 345 m_options.m_outfile_filespec.GetPath (path, sizeof(path)); 346 char mode[16] = { 'w', '\0' }; 347 if (m_options.m_append_to_outfile) 348 mode[0] = 'a'; 349 350 if (outfile_stream.Open (path, mode)) 351 { 352 if (m_options.m_output_as_binary) 353 { 354 int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read); 355 if (bytes_written > 0) 356 { 357 result.GetOutputStream().Printf ("%i bytes %s to '%s'\n", 358 bytes_written, 359 m_options.m_append_to_outfile ? "appended" : "written", 360 path); 361 return true; 362 } 363 else 364 { 365 result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path); 366 result.SetStatus(eReturnStatusFailed); 367 return false; 368 } 369 } 370 else 371 { 372 // We are going to write ASCII to the file just point the 373 // output_stream to our outfile_stream... 374 output_stream = &outfile_stream; 375 } 376 } 377 else 378 { 379 result.AppendErrorWithFormat("Failed to open file '%s' with a mode of '%s'.\n", path, mode); 380 result.SetStatus(eReturnStatusFailed); 381 return false; 382 } 383 } 384 else 385 { 386 output_stream = &result.GetOutputStream(); 387 } 388 389 assert (output_stream); 390 data.Dump (output_stream, 391 0, 392 m_options.m_format, 393 item_byte_size, 394 item_count, 395 num_per_line, 396 addr, 397 0, 398 0); 399 output_stream->EOL(); 400 return true; 401 } 402 403 protected: 404 CommandOptions m_options; 405 }; 406 407 #define SET1 LLDB_OPT_SET_1 408 #define SET2 LLDB_OPT_SET_2 409 410 lldb::OptionDefinition 411 CommandObjectMemoryRead::CommandOptions::g_option_table[] = 412 { 413 { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."}, 414 { SET1 , false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes to use when displaying with the selected format."}, 415 { SET1 , false, "num-per-line", 'l', required_argument, NULL, 0, eArgTypeNumberPerLine,"The number of items per line to display."}, 416 { SET1 , false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of total items to display."}, 417 { SET1 | SET2, false, "outfile", 'o', required_argument, NULL, 0, eArgTypeFilename, "Dump memory read results into a file."}, 418 { SET1 | SET2, false, "append", 'a', no_argument, NULL, 0, eArgTypeNone, "Append memory read results to 'outfile'."}, 419 { SET2, 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."}, 420 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 421 }; 422 423 #undef SET1 424 #undef SET2 425 426 //---------------------------------------------------------------------- 427 // Write memory to the inferior process 428 //---------------------------------------------------------------------- 429 class CommandObjectMemoryWrite : public CommandObject 430 { 431 public: 432 433 class CommandOptions : public Options 434 { 435 public: 436 CommandOptions () : 437 Options() 438 { 439 ResetOptionValues(); 440 } 441 442 virtual 443 ~CommandOptions () 444 { 445 } 446 447 virtual Error 448 SetOptionValue (int option_idx, const char *option_arg) 449 { 450 Error error; 451 char short_option = (char) m_getopt_table[option_idx].val; 452 switch (short_option) 453 { 454 case 'f': 455 error = Args::StringToFormat (option_arg, m_format); 456 break; 457 458 case 's': 459 m_byte_size = Args::StringToUInt32 (option_arg, 0); 460 if (m_byte_size == 0) 461 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); 462 break; 463 464 case 'i': 465 m_infile.SetFile (option_arg, true); 466 if (!m_infile.Exists()) 467 { 468 m_infile.Clear(); 469 error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg); 470 } 471 break; 472 473 case 'o': 474 { 475 bool success; 476 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success); 477 if (!success) 478 { 479 error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg); 480 } 481 } 482 break; 483 484 default: 485 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option); 486 break; 487 } 488 return error; 489 } 490 491 void 492 ResetOptionValues () 493 { 494 Options::ResetOptionValues(); 495 m_format = eFormatBytes; 496 m_byte_size = 1; 497 m_infile.Clear(); 498 m_infile_offset = 0; 499 } 500 501 const lldb::OptionDefinition* 502 GetDefinitions () 503 { 504 return g_option_table; 505 } 506 507 // Options table: Required for subclasses of Options. 508 509 static lldb::OptionDefinition g_option_table[]; 510 511 // Instance variables to hold the values for command options. 512 lldb::Format m_format; 513 uint32_t m_byte_size; 514 FileSpec m_infile; 515 off_t m_infile_offset; 516 }; 517 518 CommandObjectMemoryWrite (CommandInterpreter &interpreter) : 519 CommandObject (interpreter, 520 "memory write", 521 "Write to the memory of the process being debugged.", 522 //"memory write [<cmd-options>] <addr> [value1 value2 ...]", 523 NULL, 524 eFlagProcessMustBeLaunched) 525 { 526 CommandArgumentEntry arg1; 527 CommandArgumentEntry arg2; 528 CommandArgumentData addr_arg; 529 CommandArgumentData value_arg; 530 531 // Define the first (and only) variant of this arg. 532 addr_arg.arg_type = eArgTypeAddress; 533 addr_arg.arg_repetition = eArgRepeatPlain; 534 535 // There is only one variant this argument could be; put it into the argument entry. 536 arg1.push_back (addr_arg); 537 538 // Define the first (and only) variant of this arg. 539 value_arg.arg_type = eArgTypeValue; 540 value_arg.arg_repetition = eArgRepeatPlus; 541 542 // There is only one variant this argument could be; put it into the argument entry. 543 arg2.push_back (value_arg); 544 545 // Push the data for the first argument into the m_arguments vector. 546 m_arguments.push_back (arg1); 547 m_arguments.push_back (arg2); 548 } 549 550 virtual 551 ~CommandObjectMemoryWrite () 552 { 553 } 554 555 Options * 556 GetOptions () 557 { 558 return &m_options; 559 } 560 561 bool 562 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) 563 { 564 if (total_byte_size > 8) 565 return false; 566 567 if (total_byte_size == 8) 568 return true; 569 570 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; 571 return uval64 <= max; 572 } 573 574 bool 575 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) 576 { 577 if (total_byte_size > 8) 578 return false; 579 580 if (total_byte_size == 8) 581 return true; 582 583 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; 584 const int64_t min = ~(max); 585 return min <= sval64 && sval64 <= max; 586 } 587 588 virtual bool 589 Execute (Args& command, 590 CommandReturnObject &result) 591 { 592 Process *process = m_interpreter.GetDebugger().GetExecutionContext().process; 593 if (process == NULL) 594 { 595 result.AppendError("need a process to read memory"); 596 result.SetStatus(eReturnStatusFailed); 597 return false; 598 } 599 600 const size_t argc = command.GetArgumentCount(); 601 602 if (m_options.m_infile) 603 { 604 if (argc < 1) 605 { 606 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); 607 result.SetStatus(eReturnStatusFailed); 608 return false; 609 } 610 } 611 else if (argc < 2) 612 { 613 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); 614 result.SetStatus(eReturnStatusFailed); 615 return false; 616 } 617 618 StreamString buffer (Stream::eBinary, 619 process->GetAddressByteSize(), 620 process->GetByteOrder()); 621 622 size_t item_byte_size = m_options.m_byte_size; 623 624 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); 625 626 if (addr == LLDB_INVALID_ADDRESS) 627 { 628 result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); 629 result.SetStatus(eReturnStatusFailed); 630 return false; 631 } 632 633 if (m_options.m_infile) 634 { 635 size_t length = SIZE_MAX; 636 if (m_options.m_byte_size > 0) 637 length = m_options.m_byte_size; 638 lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length)); 639 if (data_sp) 640 { 641 length = data_sp->GetByteSize(); 642 if (length > 0) 643 { 644 Error error; 645 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); 646 647 if (bytes_written == length) 648 { 649 // All bytes written 650 result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr); 651 result.SetStatus(eReturnStatusSuccessFinishResult); 652 } 653 else if (bytes_written > 0) 654 { 655 // Some byte written 656 result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr); 657 result.SetStatus(eReturnStatusSuccessFinishResult); 658 } 659 else 660 { 661 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 662 result.SetStatus(eReturnStatusFailed); 663 } 664 } 665 } 666 else 667 { 668 result.AppendErrorWithFormat ("Unable to read contents of file.\n"); 669 result.SetStatus(eReturnStatusFailed); 670 } 671 return result.Succeeded(); 672 } 673 else if (m_options.m_byte_size == 0) 674 { 675 if (m_options.m_format == eFormatPointer) 676 item_byte_size = buffer.GetAddressByteSize(); 677 else 678 item_byte_size = 1; 679 } 680 681 command.Shift(); // shift off the address argument 682 uint64_t uval64; 683 int64_t sval64; 684 bool success = false; 685 const uint32_t num_value_args = command.GetArgumentCount(); 686 uint32_t i; 687 for (i=0; i<num_value_args; ++i) 688 { 689 const char *value_str = command.GetArgumentAtIndex(i); 690 691 switch (m_options.m_format) 692 { 693 case eFormatFloat: // TODO: add support for floats soon 694 case eFormatCharPrintable: 695 case eFormatBytesWithASCII: 696 case eFormatComplex: 697 case eFormatEnum: 698 case eFormatUnicode16: 699 case eFormatUnicode32: 700 case eFormatVectorOfChar: 701 case eFormatVectorOfSInt8: 702 case eFormatVectorOfUInt8: 703 case eFormatVectorOfSInt16: 704 case eFormatVectorOfUInt16: 705 case eFormatVectorOfSInt32: 706 case eFormatVectorOfUInt32: 707 case eFormatVectorOfSInt64: 708 case eFormatVectorOfUInt64: 709 case eFormatVectorOfFloat32: 710 case eFormatVectorOfFloat64: 711 case eFormatVectorOfUInt128: 712 result.AppendError("unsupported format for writing memory"); 713 result.SetStatus(eReturnStatusFailed); 714 return false; 715 716 case eFormatDefault: 717 case eFormatBytes: 718 case eFormatHex: 719 case eFormatPointer: 720 721 // Decode hex bytes 722 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); 723 if (!success) 724 { 725 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); 726 result.SetStatus(eReturnStatusFailed); 727 return false; 728 } 729 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 730 { 731 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 732 result.SetStatus(eReturnStatusFailed); 733 return false; 734 } 735 buffer.PutMaxHex64 (uval64, item_byte_size); 736 break; 737 738 case eFormatBoolean: 739 uval64 = Args::StringToBoolean(value_str, false, &success); 740 if (!success) 741 { 742 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); 743 result.SetStatus(eReturnStatusFailed); 744 return false; 745 } 746 buffer.PutMaxHex64 (uval64, item_byte_size); 747 break; 748 749 case eFormatBinary: 750 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); 751 if (!success) 752 { 753 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); 754 result.SetStatus(eReturnStatusFailed); 755 return false; 756 } 757 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 758 { 759 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 760 result.SetStatus(eReturnStatusFailed); 761 return false; 762 } 763 buffer.PutMaxHex64 (uval64, item_byte_size); 764 break; 765 766 case eFormatChar: 767 case eFormatCString: 768 if (value_str[0]) 769 { 770 size_t len = strlen (value_str); 771 // Include the NULL for C strings... 772 if (m_options.m_format == eFormatCString) 773 ++len; 774 Error error; 775 if (process->WriteMemory (addr, value_str, len, error) == len) 776 { 777 addr += len; 778 } 779 else 780 { 781 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 782 result.SetStatus(eReturnStatusFailed); 783 return false; 784 } 785 } 786 break; 787 788 case eFormatDecimal: 789 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); 790 if (!success) 791 { 792 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); 793 result.SetStatus(eReturnStatusFailed); 794 return false; 795 } 796 else if (!SIntValueIsValidForSize (sval64, item_byte_size)) 797 { 798 result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size); 799 result.SetStatus(eReturnStatusFailed); 800 return false; 801 } 802 buffer.PutMaxHex64 (sval64, item_byte_size); 803 break; 804 805 case eFormatUnsigned: 806 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); 807 if (!success) 808 { 809 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); 810 result.SetStatus(eReturnStatusFailed); 811 return false; 812 } 813 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 814 { 815 result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 816 result.SetStatus(eReturnStatusFailed); 817 return false; 818 } 819 buffer.PutMaxHex64 (uval64, item_byte_size); 820 break; 821 822 case eFormatOctal: 823 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); 824 if (!success) 825 { 826 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); 827 result.SetStatus(eReturnStatusFailed); 828 return false; 829 } 830 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 831 { 832 result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 833 result.SetStatus(eReturnStatusFailed); 834 return false; 835 } 836 buffer.PutMaxHex64 (uval64, item_byte_size); 837 break; 838 } 839 } 840 841 if (!buffer.GetString().empty()) 842 { 843 Error error; 844 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) 845 return true; 846 else 847 { 848 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 849 result.SetStatus(eReturnStatusFailed); 850 return false; 851 } 852 } 853 return true; 854 } 855 856 protected: 857 CommandOptions m_options; 858 }; 859 860 #define SET1 LLDB_OPT_SET_1 861 #define SET2 LLDB_OPT_SET_2 862 863 lldb::OptionDefinition 864 CommandObjectMemoryWrite::CommandOptions::g_option_table[] = 865 { 866 { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format value types that will be decoded and written to memory."}, 867 { SET1 | SET2, false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."}, 868 { SET2, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."}, 869 { SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, 870 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 871 }; 872 873 #undef SET1 874 #undef SET2 875 876 //------------------------------------------------------------------------- 877 // CommandObjectMemory 878 //------------------------------------------------------------------------- 879 880 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : 881 CommandObjectMultiword (interpreter, 882 "memory", 883 "A set of commands for operating on memory.", 884 "memory <subcommand> [<subcommand-options>]") 885 { 886 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); 887 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); 888 } 889 890 CommandObjectMemory::~CommandObjectMemory () 891 { 892 } 893