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