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