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