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