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