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 } 710 else 711 { 712 result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n", 713 view_as_type_cstr, 714 name_strm.GetString().c_str()); 715 result.SetStatus(eReturnStatusFailed); 716 return false; 717 } 718 } 719 return true; 720 } 721 722 result.SetStatus(eReturnStatusSuccessFinishResult); 723 DataExtractor data (data_sp, 724 target->GetArchitecture().GetByteOrder(), 725 target->GetArchitecture().GetAddressByteSize()); 726 727 728 assert (output_stream); 729 uint32_t bytes_dumped = data.Dump (output_stream, 730 0, 731 m_format_options.GetFormat(), 732 item_byte_size, 733 item_count, 734 num_per_line, 735 addr, 736 0, 737 0, 738 exe_scope); 739 m_next_addr = addr + bytes_dumped; 740 output_stream->EOL(); 741 return true; 742 } 743 744 protected: 745 OptionGroupOptions m_option_group; 746 OptionGroupFormat m_format_options; 747 OptionGroupReadMemory m_memory_options; 748 OptionGroupOutputFile m_outfile_options; 749 OptionGroupValueObjectDisplay m_varobj_options; 750 lldb::addr_t m_next_addr; 751 lldb::addr_t m_prev_byte_size; 752 OptionGroupFormat m_prev_format_options; 753 OptionGroupReadMemory m_prev_memory_options; 754 OptionGroupOutputFile m_prev_outfile_options; 755 OptionGroupValueObjectDisplay m_prev_varobj_options; 756 }; 757 758 759 OptionDefinition 760 g_memory_write_option_table[] = 761 { 762 { LLDB_OPT_SET_1, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."}, 763 { LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, 764 }; 765 766 767 //---------------------------------------------------------------------- 768 // Write memory to the inferior process 769 //---------------------------------------------------------------------- 770 class CommandObjectMemoryWrite : public CommandObject 771 { 772 public: 773 774 class OptionGroupWriteMemory : public OptionGroup 775 { 776 public: 777 OptionGroupWriteMemory () : 778 OptionGroup() 779 { 780 } 781 782 virtual 783 ~OptionGroupWriteMemory () 784 { 785 } 786 787 virtual uint32_t 788 GetNumDefinitions () 789 { 790 return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition); 791 } 792 793 virtual const OptionDefinition* 794 GetDefinitions () 795 { 796 return g_memory_write_option_table; 797 } 798 799 virtual Error 800 SetOptionValue (CommandInterpreter &interpreter, 801 uint32_t option_idx, 802 const char *option_arg) 803 { 804 Error error; 805 char short_option = (char) g_memory_write_option_table[option_idx].short_option; 806 807 switch (short_option) 808 { 809 case 'i': 810 m_infile.SetFile (option_arg, true); 811 if (!m_infile.Exists()) 812 { 813 m_infile.Clear(); 814 error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg); 815 } 816 break; 817 818 case 'o': 819 { 820 bool success; 821 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success); 822 if (!success) 823 { 824 error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg); 825 } 826 } 827 break; 828 829 default: 830 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 831 break; 832 } 833 return error; 834 } 835 836 virtual void 837 OptionParsingStarting (CommandInterpreter &interpreter) 838 { 839 m_infile.Clear(); 840 m_infile_offset = 0; 841 } 842 843 FileSpec m_infile; 844 off_t m_infile_offset; 845 }; 846 847 CommandObjectMemoryWrite (CommandInterpreter &interpreter) : 848 CommandObject (interpreter, 849 "memory write", 850 "Write to the memory of the process being debugged.", 851 //"memory write [<cmd-options>] <addr> [value1 value2 ...]", 852 NULL, 853 eFlagProcessMustBeLaunched), 854 m_option_group (interpreter), 855 m_format_options (eFormatBytes, 1, UINT64_MAX), 856 m_memory_options () 857 { 858 CommandArgumentEntry arg1; 859 CommandArgumentEntry arg2; 860 CommandArgumentData addr_arg; 861 CommandArgumentData value_arg; 862 863 // Define the first (and only) variant of this arg. 864 addr_arg.arg_type = eArgTypeAddress; 865 addr_arg.arg_repetition = eArgRepeatPlain; 866 867 // There is only one variant this argument could be; put it into the argument entry. 868 arg1.push_back (addr_arg); 869 870 // Define the first (and only) variant of this arg. 871 value_arg.arg_type = eArgTypeValue; 872 value_arg.arg_repetition = eArgRepeatPlus; 873 874 // There is only one variant this argument could be; put it into the argument entry. 875 arg2.push_back (value_arg); 876 877 // Push the data for the first argument into the m_arguments vector. 878 m_arguments.push_back (arg1); 879 m_arguments.push_back (arg2); 880 881 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1); 882 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2); 883 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2); 884 m_option_group.Finalize(); 885 886 } 887 888 virtual 889 ~CommandObjectMemoryWrite () 890 { 891 } 892 893 Options * 894 GetOptions () 895 { 896 return &m_option_group; 897 } 898 899 bool 900 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) 901 { 902 if (total_byte_size > 8) 903 return false; 904 905 if (total_byte_size == 8) 906 return true; 907 908 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; 909 return uval64 <= max; 910 } 911 912 bool 913 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) 914 { 915 if (total_byte_size > 8) 916 return false; 917 918 if (total_byte_size == 8) 919 return true; 920 921 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; 922 const int64_t min = ~(max); 923 return min <= sval64 && sval64 <= max; 924 } 925 926 virtual bool 927 Execute (Args& command, 928 CommandReturnObject &result) 929 { 930 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr(); 931 if (process == NULL) 932 { 933 result.AppendError("need a process to read memory"); 934 result.SetStatus(eReturnStatusFailed); 935 return false; 936 } 937 938 const size_t argc = command.GetArgumentCount(); 939 940 if (m_memory_options.m_infile) 941 { 942 if (argc < 1) 943 { 944 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); 945 result.SetStatus(eReturnStatusFailed); 946 return false; 947 } 948 } 949 else if (argc < 2) 950 { 951 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); 952 result.SetStatus(eReturnStatusFailed); 953 return false; 954 } 955 956 StreamString buffer (Stream::eBinary, 957 process->GetTarget().GetArchitecture().GetAddressByteSize(), 958 process->GetTarget().GetArchitecture().GetByteOrder()); 959 960 OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue(); 961 size_t item_byte_size = byte_size_value.GetCurrentValue(); 962 963 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); 964 965 if (addr == LLDB_INVALID_ADDRESS) 966 { 967 result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); 968 result.SetStatus(eReturnStatusFailed); 969 return false; 970 } 971 972 if (m_memory_options.m_infile) 973 { 974 size_t length = SIZE_MAX; 975 if (item_byte_size > 0) 976 length = item_byte_size; 977 lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length)); 978 if (data_sp) 979 { 980 length = data_sp->GetByteSize(); 981 if (length > 0) 982 { 983 Error error; 984 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); 985 986 if (bytes_written == length) 987 { 988 // All bytes written 989 result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr); 990 result.SetStatus(eReturnStatusSuccessFinishResult); 991 } 992 else if (bytes_written > 0) 993 { 994 // Some byte written 995 result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr); 996 result.SetStatus(eReturnStatusSuccessFinishResult); 997 } 998 else 999 { 1000 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1001 result.SetStatus(eReturnStatusFailed); 1002 } 1003 } 1004 } 1005 else 1006 { 1007 result.AppendErrorWithFormat ("Unable to read contents of file.\n"); 1008 result.SetStatus(eReturnStatusFailed); 1009 } 1010 return result.Succeeded(); 1011 } 1012 else if (item_byte_size == 0) 1013 { 1014 if (m_format_options.GetFormat() == eFormatPointer) 1015 item_byte_size = buffer.GetAddressByteSize(); 1016 else 1017 item_byte_size = 1; 1018 } 1019 1020 command.Shift(); // shift off the address argument 1021 uint64_t uval64; 1022 int64_t sval64; 1023 bool success = false; 1024 const uint32_t num_value_args = command.GetArgumentCount(); 1025 uint32_t i; 1026 for (i=0; i<num_value_args; ++i) 1027 { 1028 const char *value_str = command.GetArgumentAtIndex(i); 1029 1030 switch (m_format_options.GetFormat()) 1031 { 1032 case kNumFormats: 1033 case eFormatFloat: // TODO: add support for floats soon 1034 case eFormatCharPrintable: 1035 case eFormatBytesWithASCII: 1036 case eFormatComplex: 1037 case eFormatEnum: 1038 case eFormatUnicode16: 1039 case eFormatUnicode32: 1040 case eFormatVectorOfChar: 1041 case eFormatVectorOfSInt8: 1042 case eFormatVectorOfUInt8: 1043 case eFormatVectorOfSInt16: 1044 case eFormatVectorOfUInt16: 1045 case eFormatVectorOfSInt32: 1046 case eFormatVectorOfUInt32: 1047 case eFormatVectorOfSInt64: 1048 case eFormatVectorOfUInt64: 1049 case eFormatVectorOfFloat32: 1050 case eFormatVectorOfFloat64: 1051 case eFormatVectorOfUInt128: 1052 case eFormatOSType: 1053 case eFormatComplexInteger: 1054 case eFormatAddressInfo: 1055 case eFormatHexFloat: 1056 case eFormatInstruction: 1057 result.AppendError("unsupported format for writing memory"); 1058 result.SetStatus(eReturnStatusFailed); 1059 return false; 1060 1061 case eFormatDefault: 1062 case eFormatBytes: 1063 case eFormatHex: 1064 case eFormatPointer: 1065 1066 // Decode hex bytes 1067 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); 1068 if (!success) 1069 { 1070 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); 1071 result.SetStatus(eReturnStatusFailed); 1072 return false; 1073 } 1074 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1075 { 1076 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1077 result.SetStatus(eReturnStatusFailed); 1078 return false; 1079 } 1080 buffer.PutMaxHex64 (uval64, item_byte_size); 1081 break; 1082 1083 case eFormatBoolean: 1084 uval64 = Args::StringToBoolean(value_str, false, &success); 1085 if (!success) 1086 { 1087 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); 1088 result.SetStatus(eReturnStatusFailed); 1089 return false; 1090 } 1091 buffer.PutMaxHex64 (uval64, item_byte_size); 1092 break; 1093 1094 case eFormatBinary: 1095 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); 1096 if (!success) 1097 { 1098 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); 1099 result.SetStatus(eReturnStatusFailed); 1100 return false; 1101 } 1102 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1103 { 1104 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1105 result.SetStatus(eReturnStatusFailed); 1106 return false; 1107 } 1108 buffer.PutMaxHex64 (uval64, item_byte_size); 1109 break; 1110 1111 case eFormatCharArray: 1112 case eFormatChar: 1113 case eFormatCString: 1114 if (value_str[0]) 1115 { 1116 size_t len = strlen (value_str); 1117 // Include the NULL for C strings... 1118 if (m_format_options.GetFormat() == eFormatCString) 1119 ++len; 1120 Error error; 1121 if (process->WriteMemory (addr, value_str, len, error) == len) 1122 { 1123 addr += len; 1124 } 1125 else 1126 { 1127 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1128 result.SetStatus(eReturnStatusFailed); 1129 return false; 1130 } 1131 } 1132 break; 1133 1134 case eFormatDecimal: 1135 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); 1136 if (!success) 1137 { 1138 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); 1139 result.SetStatus(eReturnStatusFailed); 1140 return false; 1141 } 1142 else if (!SIntValueIsValidForSize (sval64, item_byte_size)) 1143 { 1144 result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size); 1145 result.SetStatus(eReturnStatusFailed); 1146 return false; 1147 } 1148 buffer.PutMaxHex64 (sval64, item_byte_size); 1149 break; 1150 1151 case eFormatUnsigned: 1152 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); 1153 if (!success) 1154 { 1155 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); 1156 result.SetStatus(eReturnStatusFailed); 1157 return false; 1158 } 1159 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1160 { 1161 result.AppendErrorWithFormat ("Value %llu is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1162 result.SetStatus(eReturnStatusFailed); 1163 return false; 1164 } 1165 buffer.PutMaxHex64 (uval64, item_byte_size); 1166 break; 1167 1168 case eFormatOctal: 1169 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); 1170 if (!success) 1171 { 1172 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); 1173 result.SetStatus(eReturnStatusFailed); 1174 return false; 1175 } 1176 else if (!UIntValueIsValidForSize (uval64, item_byte_size)) 1177 { 1178 result.AppendErrorWithFormat ("Value %llo is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size); 1179 result.SetStatus(eReturnStatusFailed); 1180 return false; 1181 } 1182 buffer.PutMaxHex64 (uval64, item_byte_size); 1183 break; 1184 } 1185 } 1186 1187 if (!buffer.GetString().empty()) 1188 { 1189 Error error; 1190 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size()) 1191 return true; 1192 else 1193 { 1194 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); 1195 result.SetStatus(eReturnStatusFailed); 1196 return false; 1197 } 1198 } 1199 return true; 1200 } 1201 1202 protected: 1203 1204 OptionGroupOptions m_option_group; 1205 OptionGroupFormat m_format_options; 1206 OptionGroupWriteMemory m_memory_options; 1207 }; 1208 1209 1210 //------------------------------------------------------------------------- 1211 // CommandObjectMemory 1212 //------------------------------------------------------------------------- 1213 1214 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : 1215 CommandObjectMultiword (interpreter, 1216 "memory", 1217 "A set of commands for operating on memory.", 1218 "memory <subcommand> [<subcommand-options>]") 1219 { 1220 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); 1221 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); 1222 } 1223 1224 CommandObjectMemory::~CommandObjectMemory () 1225 { 1226 } 1227