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 use_dynamic = false; 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 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 eFormatFloat: // TODO: add support for floats soon 992 case eFormatCharPrintable: 993 case eFormatBytesWithASCII: 994 case eFormatComplex: 995 case eFormatEnum: 996 case eFormatUnicode16: 997 case eFormatUnicode32: 998 case eFormatVectorOfChar: 999 case eFormatVectorOfSInt8: 1000 case eFormatVectorOfUInt8: 1001 case eFormatVectorOfSInt16: 1002 case eFormatVectorOfUInt16: 1003 case eFormatVectorOfSInt32: 1004 case eFormatVectorOfUInt32: 1005 case eFormatVectorOfSInt64: 1006 case eFormatVectorOfUInt64: 1007 case eFormatVectorOfFloat32: 1008 case eFormatVectorOfFloat64: 1009 case eFormatVectorOfUInt128: 1010 case eFormatOSType: 1011 case eFormatComplexInteger: 1012 result.AppendError("unsupported format for writing memory"); 1013 result.SetStatus(eReturnStatusFailed); 1014 return false; 1015 1016 case eFormatDefault: 1017 case eFormatBytes: 1018 case eFormatHex: 1019 case eFormatPointer: 1020 1021 // Decode hex bytes 1022 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); 1023 if (!success) 1024 { 1025 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); 1026 result.SetStatus(eReturnStatusFailed); 1027 return false; 1028 } 1029 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1030 { 1031 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 1032 result.SetStatus(eReturnStatusFailed); 1033 return false; 1034 } 1035 buffer.PutMaxHex64 (uval64, item_byte_size); 1036 break; 1037 1038 case eFormatBoolean: 1039 uval64 = Args::StringToBoolean(value_str, false, &success); 1040 if (!success) 1041 { 1042 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); 1043 result.SetStatus(eReturnStatusFailed); 1044 return false; 1045 } 1046 buffer.PutMaxHex64 (uval64, item_byte_size); 1047 break; 1048 1049 case eFormatBinary: 1050 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); 1051 if (!success) 1052 { 1053 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); 1054 result.SetStatus(eReturnStatusFailed); 1055 return false; 1056 } 1057 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1058 { 1059 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 1060 result.SetStatus(eReturnStatusFailed); 1061 return false; 1062 } 1063 buffer.PutMaxHex64 (uval64, item_byte_size); 1064 break; 1065 1066 case eFormatChar: 1067 case eFormatCString: 1068 if (value_str[0]) 1069 { 1070 size_t len = strlen (value_str); 1071 // Include the NULL for C strings... 1072 if (m_options.m_format == eFormatCString) 1073 ++len; 1074 Error error; 1075 if (process->WriteMemory (addr, value_str, len, error) == len) 1076 { 1077 addr += len; 1078 } 1079 else 1080 { 1081 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1082 result.SetStatus(eReturnStatusFailed); 1083 return false; 1084 } 1085 } 1086 break; 1087 1088 case eFormatDecimal: 1089 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); 1090 if (!success) 1091 { 1092 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); 1093 result.SetStatus(eReturnStatusFailed); 1094 return false; 1095 } 1096 else if (!SIntValueIsValidForSize (sval64, item_byte_size)) 1097 { 1098 result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size); 1099 result.SetStatus(eReturnStatusFailed); 1100 return false; 1101 } 1102 buffer.PutMaxHex64 (sval64, item_byte_size); 1103 break; 1104 1105 case eFormatUnsigned: 1106 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); 1107 if (!success) 1108 { 1109 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); 1110 result.SetStatus(eReturnStatusFailed); 1111 return false; 1112 } 1113 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1114 { 1115 result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 1116 result.SetStatus(eReturnStatusFailed); 1117 return false; 1118 } 1119 buffer.PutMaxHex64 (uval64, item_byte_size); 1120 break; 1121 1122 case eFormatOctal: 1123 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); 1124 if (!success) 1125 { 1126 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); 1127 result.SetStatus(eReturnStatusFailed); 1128 return false; 1129 } 1130 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1131 { 1132 result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); 1133 result.SetStatus(eReturnStatusFailed); 1134 return false; 1135 } 1136 buffer.PutMaxHex64 (uval64, item_byte_size); 1137 break; 1138 } 1139 } 1140 1141 if (!buffer.GetString().empty()) 1142 { 1143 Error error; 1144 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) 1145 return true; 1146 else 1147 { 1148 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1149 result.SetStatus(eReturnStatusFailed); 1150 return false; 1151 } 1152 } 1153 return true; 1154 } 1155 1156 protected: 1157 CommandOptions m_options; 1158 }; 1159 1160 #define SET1 LLDB_OPT_SET_1 1161 #define SET2 LLDB_OPT_SET_2 1162 1163 OptionDefinition 1164 CommandObjectMemoryWrite::CommandOptions::g_option_table[] = 1165 { 1166 { SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format value types that will be decoded and written to memory."}, 1167 { SET1 | SET2, false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."}, 1168 { SET2, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."}, 1169 { SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, 1170 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 1171 }; 1172 1173 #undef SET1 1174 #undef SET2 1175 1176 //------------------------------------------------------------------------- 1177 // CommandObjectMemory 1178 //------------------------------------------------------------------------- 1179 1180 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : 1181 CommandObjectMultiword (interpreter, 1182 "memory", 1183 "A set of commands for operating on memory.", 1184 "memory <subcommand> [<subcommand-options>]") 1185 { 1186 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); 1187 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); 1188 } 1189 1190 CommandObjectMemory::~CommandObjectMemory () 1191 { 1192 } 1193