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