1849 lines · cpp
1//===-- CommandObjectMemory.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CommandObjectMemory.h"10#include "CommandObjectMemoryTag.h"11#include "lldb/Core/DumpDataExtractor.h"12#include "lldb/Core/Section.h"13#include "lldb/Expression/ExpressionVariable.h"14#include "lldb/Host/OptionParser.h"15#include "lldb/Interpreter/CommandOptionArgumentTable.h"16#include "lldb/Interpreter/CommandReturnObject.h"17#include "lldb/Interpreter/OptionArgParser.h"18#include "lldb/Interpreter/OptionGroupFormat.h"19#include "lldb/Interpreter/OptionGroupMemoryTag.h"20#include "lldb/Interpreter/OptionGroupOutputFile.h"21#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"22#include "lldb/Interpreter/OptionValueLanguage.h"23#include "lldb/Interpreter/OptionValueString.h"24#include "lldb/Interpreter/Options.h"25#include "lldb/Symbol/SymbolFile.h"26#include "lldb/Symbol/TypeList.h"27#include "lldb/Target/ABI.h"28#include "lldb/Target/Language.h"29#include "lldb/Target/MemoryHistory.h"30#include "lldb/Target/MemoryRegionInfo.h"31#include "lldb/Target/Process.h"32#include "lldb/Target/StackFrame.h"33#include "lldb/Target/Target.h"34#include "lldb/Target/Thread.h"35#include "lldb/Utility/Args.h"36#include "lldb/Utility/DataBufferHeap.h"37#include "lldb/Utility/StreamString.h"38#include "lldb/ValueObject/ValueObjectMemory.h"39#include "llvm/Support/MathExtras.h"40#include <cinttypes>41#include <memory>42#include <optional>43 44using namespace lldb;45using namespace lldb_private;46 47#define LLDB_OPTIONS_memory_read48#include "CommandOptions.inc"49 50class OptionGroupReadMemory : public OptionGroup {51public:52 OptionGroupReadMemory()53 : m_num_per_line(1, 1), m_offset(0, 0),54 m_language_for_type(eLanguageTypeUnknown) {}55 56 ~OptionGroupReadMemory() override = default;57 58 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {59 return llvm::ArrayRef(g_memory_read_options);60 }61 62 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,63 ExecutionContext *execution_context) override {64 Status error;65 const int short_option = g_memory_read_options[option_idx].short_option;66 67 switch (short_option) {68 case 'l':69 error = m_num_per_line.SetValueFromString(option_value);70 if (m_num_per_line.GetCurrentValue() == 0)71 error = Status::FromErrorStringWithFormat(72 "invalid value for --num-per-line option '%s'",73 option_value.str().c_str());74 break;75 76 case 'b':77 m_output_as_binary = true;78 break;79 80 case 't':81 error = m_view_as_type.SetValueFromString(option_value);82 break;83 84 case 'r':85 m_force = true;86 break;87 88 case 'x':89 error = m_language_for_type.SetValueFromString(option_value);90 break;91 92 case 'E':93 error = m_offset.SetValueFromString(option_value);94 break;95 96 default:97 llvm_unreachable("Unimplemented option");98 }99 return error;100 }101 102 void OptionParsingStarting(ExecutionContext *execution_context) override {103 m_num_per_line.Clear();104 m_output_as_binary = false;105 m_view_as_type.Clear();106 m_force = false;107 m_offset.Clear();108 m_language_for_type.Clear();109 }110 111 Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {112 Status error;113 OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();114 OptionValueUInt64 &count_value = format_options.GetCountValue();115 const bool byte_size_option_set = byte_size_value.OptionWasSet();116 const bool num_per_line_option_set = m_num_per_line.OptionWasSet();117 const bool count_option_set = format_options.GetCountValue().OptionWasSet();118 119 switch (format_options.GetFormat()) {120 default:121 break;122 123 case eFormatBoolean:124 if (!byte_size_option_set)125 byte_size_value = 1;126 if (!num_per_line_option_set)127 m_num_per_line = 1;128 if (!count_option_set)129 format_options.GetCountValue() = 8;130 break;131 132 case eFormatCString:133 break;134 135 case eFormatInstruction:136 if (count_option_set)137 byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();138 m_num_per_line = 1;139 break;140 141 case eFormatAddressInfo:142 if (!byte_size_option_set)143 byte_size_value = target->GetArchitecture().GetAddressByteSize();144 m_num_per_line = 1;145 if (!count_option_set)146 format_options.GetCountValue() = 8;147 break;148 149 case eFormatPointer:150 byte_size_value = target->GetArchitecture().GetAddressByteSize();151 if (!num_per_line_option_set)152 m_num_per_line = 4;153 if (!count_option_set)154 format_options.GetCountValue() = 8;155 break;156 157 case eFormatBinary:158 case eFormatFloat:159 case eFormatFloat128:160 case eFormatOctal:161 case eFormatDecimal:162 case eFormatEnum:163 case eFormatUnicode8:164 case eFormatUnicode16:165 case eFormatUnicode32:166 case eFormatUnsigned:167 case eFormatHexFloat:168 if (!byte_size_option_set)169 byte_size_value = 4;170 if (!num_per_line_option_set)171 m_num_per_line = 1;172 if (!count_option_set)173 format_options.GetCountValue() = 8;174 break;175 176 case eFormatBytes:177 case eFormatBytesWithASCII:178 if (byte_size_option_set) {179 if (byte_size_value > 1)180 error = Status::FromErrorStringWithFormat(181 "display format (bytes/bytes with ASCII) conflicts with the "182 "specified byte size %" PRIu64 "\n"183 "\tconsider using a different display format or don't specify "184 "the byte size.",185 byte_size_value.GetCurrentValue());186 } else187 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 194 case eFormatCharArray:195 case eFormatChar:196 case eFormatCharPrintable:197 if (!byte_size_option_set)198 byte_size_value = 1;199 if (!num_per_line_option_set)200 m_num_per_line = 32;201 if (!count_option_set)202 format_options.GetCountValue() = 64;203 break;204 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 214 case eFormatComplexInteger:215 if (!byte_size_option_set)216 byte_size_value = 8;217 if (!num_per_line_option_set)218 m_num_per_line = 1;219 if (!count_option_set)220 format_options.GetCountValue() = 8;221 break;222 223 case eFormatHex:224 if (!byte_size_option_set)225 byte_size_value = 4;226 if (!num_per_line_option_set) {227 switch (byte_size_value) {228 case 1:229 case 2:230 m_num_per_line = 8;231 break;232 case 4:233 m_num_per_line = 4;234 break;235 case 8:236 m_num_per_line = 2;237 break;238 default:239 m_num_per_line = 1;240 break;241 }242 }243 if (!count_option_set)244 count_value = 8;245 break;246 247 case eFormatVectorOfChar:248 case eFormatVectorOfSInt8:249 case eFormatVectorOfUInt8:250 case eFormatVectorOfSInt16:251 case eFormatVectorOfUInt16:252 case eFormatVectorOfSInt32:253 case eFormatVectorOfUInt32:254 case eFormatVectorOfSInt64:255 case eFormatVectorOfUInt64:256 case eFormatVectorOfFloat16:257 case eFormatVectorOfFloat32:258 case eFormatVectorOfFloat64:259 case eFormatVectorOfUInt128:260 if (!byte_size_option_set)261 byte_size_value = 128;262 if (!num_per_line_option_set)263 m_num_per_line = 1;264 if (!count_option_set)265 count_value = 4;266 break;267 }268 return error;269 }270 271 bool AnyOptionWasSet() const {272 return m_num_per_line.OptionWasSet() || m_output_as_binary ||273 m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||274 m_language_for_type.OptionWasSet();275 }276 277 OptionValueUInt64 m_num_per_line;278 bool m_output_as_binary = false;279 OptionValueString m_view_as_type;280 bool m_force = false;281 OptionValueUInt64 m_offset;282 OptionValueLanguage m_language_for_type;283};284 285// Read memory from the inferior process286class CommandObjectMemoryRead : public CommandObjectParsed {287public:288 CommandObjectMemoryRead(CommandInterpreter &interpreter)289 : CommandObjectParsed(290 interpreter, "memory read",291 "Read from the memory of the current target process.", nullptr,292 eCommandRequiresTarget | eCommandProcessMustBePaused),293 m_format_options(eFormatBytesWithASCII, 1, 8),294 m_memory_tag_options(/*note_binary=*/true),295 m_prev_format_options(eFormatBytesWithASCII, 1, 8) {296 CommandArgumentEntry arg1;297 CommandArgumentEntry arg2;298 CommandArgumentData start_addr_arg;299 CommandArgumentData end_addr_arg;300 301 // Define the first (and only) variant of this arg.302 start_addr_arg.arg_type = eArgTypeAddressOrExpression;303 start_addr_arg.arg_repetition = eArgRepeatPlain;304 305 // There is only one variant this argument could be; put it into the306 // argument entry.307 arg1.push_back(start_addr_arg);308 309 // Define the first (and only) variant of this arg.310 end_addr_arg.arg_type = eArgTypeAddressOrExpression;311 end_addr_arg.arg_repetition = eArgRepeatOptional;312 313 // There is only one variant this argument could be; put it into the314 // argument entry.315 arg2.push_back(end_addr_arg);316 317 // Push the data for the first argument into the m_arguments vector.318 m_arguments.push_back(arg1);319 m_arguments.push_back(arg2);320 321 // Add the "--format" and "--count" options to group 1 and 3322 m_option_group.Append(&m_format_options,323 OptionGroupFormat::OPTION_GROUP_FORMAT |324 OptionGroupFormat::OPTION_GROUP_COUNT,325 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);326 m_option_group.Append(&m_format_options,327 OptionGroupFormat::OPTION_GROUP_GDB_FMT,328 LLDB_OPT_SET_1 | LLDB_OPT_SET_3);329 // Add the "--size" option to group 1 and 2330 m_option_group.Append(&m_format_options,331 OptionGroupFormat::OPTION_GROUP_SIZE,332 LLDB_OPT_SET_1 | LLDB_OPT_SET_2);333 m_option_group.Append(&m_memory_options);334 m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,335 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.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,338 LLDB_OPT_SET_ALL);339 m_option_group.Finalize();340 }341 342 ~CommandObjectMemoryRead() override = default;343 344 Options *GetOptions() override { return &m_option_group; }345 346 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,347 uint32_t index) override {348 return m_cmd_name;349 }350 351protected:352 void DoExecute(Args &command, CommandReturnObject &result) override {353 // No need to check "target" for validity as eCommandRequiresTarget ensures354 // it is valid355 Target *target = m_exe_ctx.GetTargetPtr();356 357 const size_t argc = command.GetArgumentCount();358 359 if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {360 result.AppendErrorWithFormat("%s takes a start address expression with "361 "an optional end address expression.\n",362 m_cmd_name.c_str());363 result.AppendWarning("Expressions should be quoted if they contain "364 "spaces or other special characters.");365 return;366 }367 368 ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();369 370 CompilerType compiler_type;371 Status error;372 373 const char *view_as_type_cstr =374 m_memory_options.m_view_as_type.GetCurrentValue();375 if (view_as_type_cstr && view_as_type_cstr[0]) {376 // We are viewing memory as a type377 378 uint32_t reference_count = 0;379 uint32_t pointer_count = 0;380 size_t idx;381 382#define ALL_KEYWORDS \383 KEYWORD("const") \384 KEYWORD("volatile") \385 KEYWORD("restrict") \386 KEYWORD("struct") \387 KEYWORD("class") \388 KEYWORD("union")389 390#define KEYWORD(s) s,391 static const char *g_keywords[] = {ALL_KEYWORDS};392#undef KEYWORD393 394#define KEYWORD(s) (sizeof(s) - 1),395 static const int g_keyword_lengths[] = {ALL_KEYWORDS};396#undef KEYWORD397 398#undef ALL_KEYWORDS399 400 static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);401 std::string type_str(view_as_type_cstr);402 403 // Remove all instances of g_keywords that are followed by spaces404 for (size_t i = 0; i < g_num_keywords; ++i) {405 const char *keyword = g_keywords[i];406 int keyword_len = g_keyword_lengths[i];407 408 idx = 0;409 while ((idx = type_str.find(keyword, idx)) != std::string::npos) {410 if (type_str[idx + keyword_len] == ' ' ||411 type_str[idx + keyword_len] == '\t') {412 type_str.erase(idx, keyword_len + 1);413 idx = 0;414 } else {415 idx += keyword_len;416 }417 }418 }419 bool done = type_str.empty();420 //421 idx = type_str.find_first_not_of(" \t");422 if (idx > 0 && idx != std::string::npos)423 type_str.erase(0, idx);424 while (!done) {425 // Strip trailing spaces426 if (type_str.empty())427 done = true;428 else {429 switch (type_str[type_str.size() - 1]) {430 case '*':431 ++pointer_count;432 [[fallthrough]];433 case ' ':434 case '\t':435 type_str.erase(type_str.size() - 1);436 break;437 438 case '&':439 if (reference_count == 0) {440 reference_count = 1;441 type_str.erase(type_str.size() - 1);442 } else {443 result.AppendErrorWithFormat("invalid type string: '%s'\n",444 view_as_type_cstr);445 return;446 }447 break;448 449 default:450 done = true;451 break;452 }453 }454 }455 456 ConstString lookup_type_name(type_str.c_str());457 StackFrame *frame = m_exe_ctx.GetFramePtr();458 ModuleSP search_first;459 if (frame)460 search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;461 TypeQuery query(lookup_type_name.GetStringRef(),462 TypeQueryOptions::e_find_one);463 TypeResults results;464 target->GetImages().FindTypes(search_first.get(), query, results);465 TypeSP type_sp = results.GetFirstType();466 467 if (!type_sp && lookup_type_name.GetCString()) {468 LanguageType language_for_type =469 m_memory_options.m_language_for_type.GetCurrentValue();470 std::set<LanguageType> languages_to_check;471 if (language_for_type != eLanguageTypeUnknown) {472 languages_to_check.insert(language_for_type);473 } else {474 languages_to_check = Language::GetSupportedLanguages();475 }476 477 std::set<CompilerType> user_defined_types;478 for (auto lang : languages_to_check) {479 if (auto *persistent_vars =480 target->GetPersistentExpressionStateForLanguage(lang)) {481 if (std::optional<CompilerType> type =482 persistent_vars->GetCompilerTypeFromPersistentDecl(483 lookup_type_name)) {484 user_defined_types.emplace(*type);485 }486 }487 }488 489 if (user_defined_types.size() > 1) {490 result.AppendErrorWithFormat(491 "Mutiple types found matching raw type '%s', please disambiguate "492 "by specifying the language with -x",493 lookup_type_name.GetCString());494 return;495 }496 497 if (user_defined_types.size() == 1) {498 compiler_type = *user_defined_types.begin();499 }500 }501 502 if (!compiler_type.IsValid()) {503 if (type_sp) {504 compiler_type = type_sp->GetFullCompilerType();505 } else {506 result.AppendErrorWithFormat("unable to find any types that match "507 "the raw type '%s' for full type '%s'\n",508 lookup_type_name.GetCString(),509 view_as_type_cstr);510 return;511 }512 }513 514 while (pointer_count > 0) {515 CompilerType pointer_type = compiler_type.GetPointerType();516 if (pointer_type.IsValid())517 compiler_type = pointer_type;518 else {519 result.AppendError("unable make a pointer type\n");520 return;521 }522 --pointer_count;523 }524 525 auto size_or_err = compiler_type.GetByteSize(exe_scope);526 if (!size_or_err) {527 result.AppendErrorWithFormat(528 "unable to get the byte size of the type '%s'\n%s",529 view_as_type_cstr, llvm::toString(size_or_err.takeError()).c_str());530 return;531 }532 m_format_options.GetByteSizeValue() = *size_or_err;533 534 if (!m_format_options.GetCountValue().OptionWasSet())535 m_format_options.GetCountValue() = 1;536 } else {537 error = m_memory_options.FinalizeSettings(target, m_format_options);538 }539 540 // Look for invalid combinations of settings541 if (error.Fail()) {542 result.AppendError(error.AsCString());543 return;544 }545 546 lldb::addr_t addr;547 size_t total_byte_size = 0;548 if (argc == 0) {549 // Use the last address and byte size and all options as they were if no550 // options have been set551 addr = m_next_addr;552 total_byte_size = m_prev_byte_size;553 compiler_type = m_prev_compiler_type;554 if (!m_format_options.AnyOptionWasSet() &&555 !m_memory_options.AnyOptionWasSet() &&556 !m_outfile_options.AnyOptionWasSet() &&557 !m_varobj_options.AnyOptionWasSet() &&558 !m_memory_tag_options.AnyOptionWasSet()) {559 m_format_options = m_prev_format_options;560 m_memory_options = m_prev_memory_options;561 m_outfile_options = m_prev_outfile_options;562 m_varobj_options = m_prev_varobj_options;563 m_memory_tag_options = m_prev_memory_tag_options;564 }565 }566 567 size_t item_count = m_format_options.GetCountValue().GetCurrentValue();568 569 // TODO For non-8-bit byte addressable architectures this needs to be570 // revisited to fully support all lldb's range of formatting options.571 // Furthermore code memory reads (for those architectures) will not be572 // correctly formatted even w/o formatting options.573 size_t item_byte_size =574 target->GetArchitecture().GetDataByteSize() > 1575 ? target->GetArchitecture().GetDataByteSize()576 : m_format_options.GetByteSizeValue().GetCurrentValue();577 578 const size_t num_per_line =579 m_memory_options.m_num_per_line.GetCurrentValue();580 581 if (total_byte_size == 0) {582 total_byte_size = item_count * item_byte_size;583 if (total_byte_size == 0)584 total_byte_size = 32;585 }586 587 if (argc > 0)588 addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(),589 LLDB_INVALID_ADDRESS, &error);590 591 if (addr == LLDB_INVALID_ADDRESS) {592 result.AppendError("invalid start address expression.");593 result.AppendError(error.AsCString());594 return;595 }596 597 if (argc == 2) {598 lldb::addr_t end_addr = OptionArgParser::ToAddress(599 &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, nullptr);600 601 if (end_addr == LLDB_INVALID_ADDRESS) {602 result.AppendError("invalid end address expression.");603 result.AppendError(error.AsCString());604 return;605 } else if (end_addr <= addr) {606 result.AppendErrorWithFormat(607 "end address (0x%" PRIx64608 ") must be greater than the start address (0x%" PRIx64 ").\n",609 end_addr, addr);610 return;611 } else if (m_format_options.GetCountValue().OptionWasSet()) {612 result.AppendErrorWithFormat(613 "specify either the end address (0x%" PRIx64614 ") or the count (--count %" PRIu64 "), not both.\n",615 end_addr, (uint64_t)item_count);616 return;617 }618 619 total_byte_size = end_addr - addr;620 item_count = total_byte_size / item_byte_size;621 }622 623 uint32_t max_unforced_size = target->GetMaximumMemReadSize();624 625 if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {626 result.AppendErrorWithFormat(627 "Normally, \'memory read\' will not read over %" PRIu32628 " bytes of data.\n",629 max_unforced_size);630 result.AppendErrorWithFormat(631 "Please use --force to override this restriction just once.\n");632 result.AppendErrorWithFormat("or set target.max-memory-read-size if you "633 "will often need a larger limit.\n");634 return;635 }636 637 WritableDataBufferSP data_sp;638 size_t bytes_read = 0;639 if (compiler_type.GetOpaqueQualType()) {640 // Make sure we don't display our type as ASCII bytes like the default641 // memory read642 if (!m_format_options.GetFormatValue().OptionWasSet())643 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);644 645 auto size_or_err = compiler_type.GetByteSize(exe_scope);646 if (!size_or_err) {647 result.AppendError(llvm::toString(size_or_err.takeError()));648 return;649 }650 auto size = *size_or_err;651 bytes_read = size * m_format_options.GetCountValue().GetCurrentValue();652 653 if (argc > 0)654 addr = addr + (size * m_memory_options.m_offset.GetCurrentValue());655 } else if (m_format_options.GetFormatValue().GetCurrentValue() !=656 eFormatCString) {657 data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');658 if (data_sp->GetBytes() == nullptr) {659 result.AppendErrorWithFormat(660 "can't allocate 0x%" PRIx32661 " bytes for the memory read buffer, specify a smaller size to read",662 (uint32_t)total_byte_size);663 return;664 }665 666 Address address(addr, nullptr);667 bytes_read = target->ReadMemory(address, data_sp->GetBytes(),668 data_sp->GetByteSize(), error, true);669 if (bytes_read == 0) {670 const char *error_cstr = error.AsCString();671 if (error_cstr && error_cstr[0]) {672 result.AppendError(error_cstr);673 } else {674 result.AppendErrorWithFormat(675 "failed to read memory from 0x%" PRIx64 ".\n", addr);676 }677 return;678 }679 680 if (bytes_read < total_byte_size)681 result.AppendWarningWithFormat(682 "Not all bytes (%" PRIu64 "/%" PRIu64683 ") were able to be read from 0x%" PRIx64 ".\n",684 (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);685 } else {686 // we treat c-strings as a special case because they do not have a fixed687 // size688 if (m_format_options.GetByteSizeValue().OptionWasSet() &&689 !m_format_options.HasGDBFormat())690 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();691 else692 item_byte_size = target->GetMaximumSizeOfStringSummary();693 if (!m_format_options.GetCountValue().OptionWasSet())694 item_count = 1;695 data_sp = std::make_shared<DataBufferHeap>(696 (item_byte_size + 1) * item_count,697 '\0'); // account for NULLs as necessary698 if (data_sp->GetBytes() == nullptr) {699 result.AppendErrorWithFormat(700 "can't allocate 0x%" PRIx64701 " bytes for the memory read buffer, specify a smaller size to read",702 (uint64_t)((item_byte_size + 1) * item_count));703 return;704 }705 uint8_t *data_ptr = data_sp->GetBytes();706 auto data_addr = addr;707 auto count = item_count;708 item_count = 0;709 bool break_on_no_NULL = false;710 while (item_count < count) {711 std::string buffer;712 buffer.resize(item_byte_size + 1, 0);713 Status error;714 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],715 item_byte_size + 1, error);716 if (error.Fail()) {717 result.AppendErrorWithFormat(718 "failed to read memory from 0x%" PRIx64 ".\n", addr);719 return;720 }721 722 if (item_byte_size == read) {723 result.AppendWarningWithFormat(724 "unable to find a NULL terminated string at 0x%" PRIx64725 ". Consider increasing the maximum read length.\n",726 data_addr);727 --read;728 break_on_no_NULL = true;729 } else730 ++read; // account for final NULL byte731 732 memcpy(data_ptr, &buffer[0], read);733 data_ptr += read;734 data_addr += read;735 bytes_read += read;736 item_count++; // if we break early we know we only read item_count737 // strings738 739 if (break_on_no_NULL)740 break;741 }742 data_sp =743 std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);744 }745 746 m_next_addr = addr + bytes_read;747 m_prev_byte_size = bytes_read;748 m_prev_format_options = m_format_options;749 m_prev_memory_options = m_memory_options;750 m_prev_outfile_options = m_outfile_options;751 m_prev_varobj_options = m_varobj_options;752 m_prev_memory_tag_options = m_memory_tag_options;753 m_prev_compiler_type = compiler_type;754 755 std::unique_ptr<Stream> output_stream_storage;756 Stream *output_stream_p = nullptr;757 const FileSpec &outfile_spec =758 m_outfile_options.GetFile().GetCurrentValue();759 760 std::string path = outfile_spec.GetPath();761 if (outfile_spec) {762 763 File::OpenOptions open_options =764 File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;765 const bool append = m_outfile_options.GetAppend().GetCurrentValue();766 open_options |=767 append ? File::eOpenOptionAppend : File::eOpenOptionTruncate;768 769 auto outfile = FileSystem::Instance().Open(outfile_spec, open_options);770 771 if (outfile) {772 auto outfile_stream_up =773 std::make_unique<StreamFile>(std::move(outfile.get()));774 if (m_memory_options.m_output_as_binary) {775 const size_t bytes_written =776 outfile_stream_up->Write(data_sp->GetBytes(), bytes_read);777 if (bytes_written > 0) {778 result.GetOutputStream().Printf(779 "%zi bytes %s to '%s'\n", bytes_written,780 append ? "appended" : "written", path.c_str());781 return;782 } else {783 result.AppendErrorWithFormat("Failed to write %" PRIu64784 " bytes to '%s'.\n",785 (uint64_t)bytes_read, path.c_str());786 return;787 }788 } else {789 // We are going to write ASCII to the file just point the790 // output_stream to our outfile_stream...791 output_stream_storage = std::move(outfile_stream_up);792 output_stream_p = output_stream_storage.get();793 }794 } else {795 result.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",796 path.c_str(), append ? "append" : "write");797 798 result.AppendError(llvm::toString(outfile.takeError()));799 return;800 }801 } else {802 output_stream_p = &result.GetOutputStream();803 }804 805 if (compiler_type.GetOpaqueQualType()) {806 for (uint32_t i = 0; i < item_count; ++i) {807 addr_t item_addr = addr + (i * item_byte_size);808 Address address(item_addr);809 StreamString name_strm;810 name_strm.Printf("0x%" PRIx64, item_addr);811 ValueObjectSP valobj_sp(ValueObjectMemory::Create(812 exe_scope, name_strm.GetString(), address, compiler_type));813 if (valobj_sp) {814 Format format = m_format_options.GetFormat();815 if (format != eFormatDefault)816 valobj_sp->SetFormat(format);817 818 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(819 eLanguageRuntimeDescriptionDisplayVerbosityFull, format));820 821 if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) {822 result.AppendError(toString(std::move(error)));823 return;824 }825 } else {826 result.AppendErrorWithFormat(827 "failed to create a value object for: (%s) %s\n",828 view_as_type_cstr, name_strm.GetData());829 return;830 }831 }832 return;833 }834 835 result.SetStatus(eReturnStatusSuccessFinishResult);836 DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),837 target->GetArchitecture().GetAddressByteSize(),838 target->GetArchitecture().GetDataByteSize());839 840 Format format = m_format_options.GetFormat();841 if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&842 (item_byte_size != 1)) {843 // if a count was not passed, or it is 1844 if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {845 // this turns requests such as846 // memory read -fc -s10 -c1 *charPtrPtr847 // which make no sense (what is a char of size 10?) into a request for848 // fetching 10 chars of size 1 from the same memory location849 format = eFormatCharArray;850 item_count = item_byte_size;851 item_byte_size = 1;852 } else {853 // here we passed a count, and it was not 1 so we have a byte_size and854 // a count we could well multiply those, but instead let's just fail855 result.AppendErrorWithFormat(856 "reading memory as characters of size %" PRIu64 " is not supported",857 (uint64_t)item_byte_size);858 return;859 }860 }861 862 assert(output_stream_p);863 size_t bytes_dumped = DumpDataExtractor(864 data, output_stream_p, 0, format, item_byte_size, item_count,865 num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,866 exe_scope, m_memory_tag_options.GetShowTags().GetCurrentValue());867 m_next_addr = addr + bytes_dumped;868 output_stream_p->EOL();869 }870 871 OptionGroupOptions m_option_group;872 OptionGroupFormat m_format_options;873 OptionGroupReadMemory m_memory_options;874 OptionGroupOutputFile m_outfile_options;875 OptionGroupValueObjectDisplay m_varobj_options;876 OptionGroupMemoryTag m_memory_tag_options;877 lldb::addr_t m_next_addr = LLDB_INVALID_ADDRESS;878 lldb::addr_t m_prev_byte_size = 0;879 OptionGroupFormat m_prev_format_options;880 OptionGroupReadMemory m_prev_memory_options;881 OptionGroupOutputFile m_prev_outfile_options;882 OptionGroupValueObjectDisplay m_prev_varobj_options;883 OptionGroupMemoryTag m_prev_memory_tag_options;884 CompilerType m_prev_compiler_type;885};886 887#define LLDB_OPTIONS_memory_find888#include "CommandOptions.inc"889 890static llvm::Error CopyExpressionResult(ValueObject &result,891 DataBufferHeap &buffer,892 ExecutionContextScope *scope) {893 uint64_t value = result.GetValueAsUnsigned(0);894 auto size_or_err = result.GetCompilerType().GetByteSize(scope);895 if (!size_or_err)896 return size_or_err.takeError();897 898 switch (*size_or_err) {899 case 1: {900 uint8_t byte = (uint8_t)value;901 buffer.CopyData(&byte, 1);902 } break;903 case 2: {904 uint16_t word = (uint16_t)value;905 buffer.CopyData(&word, 2);906 } break;907 case 4: {908 uint32_t lword = (uint32_t)value;909 buffer.CopyData(&lword, 4);910 } break;911 case 8: {912 buffer.CopyData(&value, 8);913 } break;914 default:915 return llvm::createStringError(916 "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are "917 "supported. For other pattern sizes the --string (-s) option may be "918 "used.");919 }920 921 return llvm::Error::success();922}923 924static llvm::Expected<ValueObjectSP>925EvaluateExpression(llvm::StringRef expression, StackFrame &frame,926 Process &process) {927 ValueObjectSP result_sp;928 auto status =929 process.GetTarget().EvaluateExpression(expression, &frame, result_sp);930 if (!result_sp)931 return llvm::createStringError(932 "No result returned from expression. Exit status: %d", status);933 934 if (status != eExpressionCompleted)935 return result_sp->GetError().ToError();936 937 result_sp = result_sp->GetQualifiedRepresentationIfAvailable(938 result_sp->GetDynamicValueType(), /*synthValue=*/true);939 if (!result_sp)940 return llvm::createStringError("failed to get dynamic result type");941 942 return result_sp;943}944 945// Find the specified data in memory946class CommandObjectMemoryFind : public CommandObjectParsed {947public:948 class OptionGroupFindMemory : public OptionGroup {949 public:950 OptionGroupFindMemory() : m_count(1), m_offset(0) {}951 952 ~OptionGroupFindMemory() override = default;953 954 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {955 return llvm::ArrayRef(g_memory_find_options);956 }957 958 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,959 ExecutionContext *execution_context) override {960 Status error;961 const int short_option = g_memory_find_options[option_idx].short_option;962 963 switch (short_option) {964 case 'e':965 m_expr.SetValueFromString(option_value);966 break;967 968 case 's':969 m_string.SetValueFromString(option_value);970 break;971 972 case 'c':973 if (m_count.SetValueFromString(option_value).Fail())974 error = Status::FromErrorString("unrecognized value for count");975 break;976 977 case 'o':978 if (m_offset.SetValueFromString(option_value).Fail())979 error = Status::FromErrorString("unrecognized value for dump-offset");980 break;981 982 default:983 llvm_unreachable("Unimplemented option");984 }985 return error;986 }987 988 void OptionParsingStarting(ExecutionContext *execution_context) override {989 m_expr.Clear();990 m_string.Clear();991 m_count.Clear();992 }993 994 OptionValueString m_expr;995 OptionValueString m_string;996 OptionValueUInt64 m_count;997 OptionValueUInt64 m_offset;998 };999 1000 CommandObjectMemoryFind(CommandInterpreter &interpreter)1001 : CommandObjectParsed(1002 interpreter, "memory find",1003 "Find a value in the memory of the current target process.",1004 nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched) {1005 CommandArgumentEntry arg1;1006 CommandArgumentEntry arg2;1007 CommandArgumentData addr_arg;1008 CommandArgumentData value_arg;1009 1010 // Define the first (and only) variant of this arg.1011 addr_arg.arg_type = eArgTypeAddressOrExpression;1012 addr_arg.arg_repetition = eArgRepeatPlain;1013 1014 // There is only one variant this argument could be; put it into the1015 // argument entry.1016 arg1.push_back(addr_arg);1017 1018 // Define the first (and only) variant of this arg.1019 value_arg.arg_type = eArgTypeAddressOrExpression;1020 value_arg.arg_repetition = eArgRepeatPlain;1021 1022 // There is only one variant this argument could be; put it into the1023 // argument entry.1024 arg2.push_back(value_arg);1025 1026 // Push the data for the first argument into the m_arguments vector.1027 m_arguments.push_back(arg1);1028 m_arguments.push_back(arg2);1029 1030 m_option_group.Append(&m_memory_options);1031 m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,1032 LLDB_OPT_SET_ALL);1033 m_option_group.Finalize();1034 }1035 1036 ~CommandObjectMemoryFind() override = default;1037 1038 Options *GetOptions() override { return &m_option_group; }1039 1040protected:1041 void DoExecute(Args &command, CommandReturnObject &result) override {1042 // No need to check "process" for validity as eCommandRequiresProcess1043 // ensures it is valid1044 Process *process = m_exe_ctx.GetProcessPtr();1045 1046 const size_t argc = command.GetArgumentCount();1047 1048 if (argc != 2) {1049 result.AppendError("two addresses needed for memory find");1050 return;1051 }1052 1053 Status error;1054 lldb::addr_t low_addr = OptionArgParser::ToAddress(1055 &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);1056 if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {1057 result.AppendError("invalid low address");1058 return;1059 }1060 lldb::addr_t high_addr = OptionArgParser::ToAddress(1061 &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, &error);1062 if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {1063 result.AppendError("invalid high address");1064 return;1065 }1066 1067 if (high_addr <= low_addr) {1068 result.AppendError(1069 "starting address must be smaller than ending address");1070 return;1071 }1072 1073 lldb::addr_t found_location = LLDB_INVALID_ADDRESS;1074 1075 DataBufferHeap buffer;1076 1077 if (m_memory_options.m_string.OptionWasSet()) {1078 llvm::StringRef str =1079 m_memory_options.m_string.GetValueAs<llvm::StringRef>().value_or("");1080 if (str.empty()) {1081 result.AppendError("search string must have non-zero length.");1082 return;1083 }1084 buffer.CopyData(str);1085 } else if (m_memory_options.m_expr.OptionWasSet()) {1086 auto result_or_err = EvaluateExpression(1087 m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(""),1088 m_exe_ctx.GetFrameRef(), *process);1089 if (!result_or_err) {1090 result.AppendError("Expression evaluation failed: ");1091 result.AppendError(llvm::toString(result_or_err.takeError()));1092 return;1093 }1094 1095 ValueObjectSP result_sp = *result_or_err;1096 1097 if (auto err = CopyExpressionResult(*result_sp, buffer,1098 m_exe_ctx.GetFramePtr())) {1099 result.AppendError(llvm::toString(std::move(err)));1100 return;1101 }1102 } else {1103 result.AppendError(1104 "please pass either a block of text, or an expression to evaluate.");1105 return;1106 }1107 1108 size_t count = m_memory_options.m_count.GetCurrentValue();1109 found_location = low_addr;1110 bool ever_found = false;1111 while (count) {1112 found_location = process->FindInMemory(1113 found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());1114 if (found_location == LLDB_INVALID_ADDRESS) {1115 if (!ever_found) {1116 result.AppendMessage("data not found within the range.\n");1117 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);1118 } else1119 result.AppendMessage("no more matches within the range.\n");1120 break;1121 }1122 result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",1123 found_location);1124 1125 DataBufferHeap dumpbuffer(32, 0);1126 process->ReadMemory(1127 found_location + m_memory_options.m_offset.GetCurrentValue(),1128 dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);1129 if (!error.Fail()) {1130 DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),1131 process->GetByteOrder(),1132 process->GetAddressByteSize());1133 DumpDataExtractor(1134 data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,1135 dumpbuffer.GetByteSize(), 16,1136 found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0,1137 m_exe_ctx.GetBestExecutionContextScope(),1138 m_memory_tag_options.GetShowTags().GetCurrentValue());1139 result.GetOutputStream().EOL();1140 }1141 1142 --count;1143 found_location++;1144 ever_found = true;1145 }1146 1147 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);1148 }1149 1150 OptionGroupOptions m_option_group;1151 OptionGroupFindMemory m_memory_options;1152 OptionGroupMemoryTag m_memory_tag_options;1153};1154 1155#define LLDB_OPTIONS_memory_write1156#include "CommandOptions.inc"1157 1158// Write memory to the inferior process1159class CommandObjectMemoryWrite : public CommandObjectParsed {1160public:1161 class OptionGroupWriteMemory : public OptionGroup {1162 public:1163 OptionGroupWriteMemory() = default;1164 1165 ~OptionGroupWriteMemory() override = default;1166 1167 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1168 return llvm::ArrayRef(g_memory_write_options);1169 }1170 1171 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,1172 ExecutionContext *execution_context) override {1173 Status error;1174 const int short_option = g_memory_write_options[option_idx].short_option;1175 1176 switch (short_option) {1177 case 'i':1178 m_infile.SetFile(option_value, FileSpec::Style::native);1179 FileSystem::Instance().Resolve(m_infile);1180 if (!FileSystem::Instance().Exists(m_infile)) {1181 m_infile.Clear();1182 error = Status::FromErrorStringWithFormat(1183 "input file does not exist: '%s'", option_value.str().c_str());1184 }1185 break;1186 1187 case 'o': {1188 if (option_value.getAsInteger(0, m_infile_offset)) {1189 m_infile_offset = 0;1190 error = Status::FromErrorStringWithFormat(1191 "invalid offset string '%s'", option_value.str().c_str());1192 }1193 } break;1194 1195 default:1196 llvm_unreachable("Unimplemented option");1197 }1198 return error;1199 }1200 1201 void OptionParsingStarting(ExecutionContext *execution_context) override {1202 m_infile.Clear();1203 m_infile_offset = 0;1204 }1205 1206 FileSpec m_infile;1207 off_t m_infile_offset;1208 };1209 1210 CommandObjectMemoryWrite(CommandInterpreter &interpreter)1211 : CommandObjectParsed(1212 interpreter, "memory write",1213 "Write to the memory of the current target process.", nullptr,1214 eCommandRequiresProcess | eCommandProcessMustBeLaunched),1215 m_format_options(1216 eFormatBytes, 1, UINT64_MAX,1217 {std::make_tuple(1218 eArgTypeFormat,1219 "The format to use for each of the value to be written."),1220 std::make_tuple(eArgTypeByteSize,1221 "The size in bytes to write from input file or "1222 "each value.")}) {1223 CommandArgumentEntry arg1;1224 CommandArgumentEntry arg2;1225 CommandArgumentData addr_arg;1226 CommandArgumentData value_arg;1227 1228 // Define the first (and only) variant of this arg.1229 addr_arg.arg_type = eArgTypeAddress;1230 addr_arg.arg_repetition = eArgRepeatPlain;1231 1232 // There is only one variant this argument could be; put it into the1233 // argument entry.1234 arg1.push_back(addr_arg);1235 1236 // Define the first (and only) variant of this arg.1237 value_arg.arg_type = eArgTypeValue;1238 value_arg.arg_repetition = eArgRepeatPlus;1239 value_arg.arg_opt_set_association = LLDB_OPT_SET_1;1240 1241 // There is only one variant this argument could be; put it into the1242 // argument entry.1243 arg2.push_back(value_arg);1244 1245 // Push the data for the first argument into the m_arguments vector.1246 m_arguments.push_back(arg1);1247 m_arguments.push_back(arg2);1248 1249 m_option_group.Append(&m_format_options,1250 OptionGroupFormat::OPTION_GROUP_FORMAT,1251 LLDB_OPT_SET_1);1252 m_option_group.Append(&m_format_options,1253 OptionGroupFormat::OPTION_GROUP_SIZE,1254 LLDB_OPT_SET_1 | LLDB_OPT_SET_2);1255 m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);1256 m_option_group.Finalize();1257 }1258 1259 ~CommandObjectMemoryWrite() override = default;1260 1261 Options *GetOptions() override { return &m_option_group; }1262 1263protected:1264 void DoExecute(Args &command, CommandReturnObject &result) override {1265 // No need to check "process" for validity as eCommandRequiresProcess1266 // ensures it is valid1267 Process *process = m_exe_ctx.GetProcessPtr();1268 1269 const size_t argc = command.GetArgumentCount();1270 1271 if (m_memory_options.m_infile) {1272 if (argc < 1) {1273 result.AppendErrorWithFormat(1274 "%s takes a destination address when writing file contents.\n",1275 m_cmd_name.c_str());1276 return;1277 }1278 if (argc > 1) {1279 result.AppendErrorWithFormat(1280 "%s takes only a destination address when writing file contents.\n",1281 m_cmd_name.c_str());1282 return;1283 }1284 } else if (argc < 2) {1285 result.AppendErrorWithFormat(1286 "%s takes a destination address and at least one value.\n",1287 m_cmd_name.c_str());1288 return;1289 }1290 1291 StreamString buffer(1292 Stream::eBinary,1293 process->GetTarget().GetArchitecture().GetAddressByteSize(),1294 process->GetTarget().GetArchitecture().GetByteOrder());1295 1296 OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();1297 size_t item_byte_size = byte_size_value.GetCurrentValue();1298 1299 Status error;1300 lldb::addr_t addr = OptionArgParser::ToAddress(1301 &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);1302 1303 if (addr == LLDB_INVALID_ADDRESS) {1304 result.AppendError("invalid address expression\n");1305 result.AppendError(error.AsCString());1306 return;1307 }1308 1309 if (m_memory_options.m_infile) {1310 size_t length = SIZE_MAX;1311 if (item_byte_size > 1)1312 length = item_byte_size;1313 auto data_sp = FileSystem::Instance().CreateDataBuffer(1314 m_memory_options.m_infile.GetPath(), length,1315 m_memory_options.m_infile_offset);1316 if (data_sp) {1317 length = data_sp->GetByteSize();1318 if (length > 0) {1319 Status error;1320 size_t bytes_written =1321 process->WriteMemory(addr, data_sp->GetBytes(), length, error);1322 1323 if (bytes_written == length) {1324 // All bytes written1325 result.GetOutputStream().Printf(1326 "%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",1327 (uint64_t)bytes_written, addr);1328 result.SetStatus(eReturnStatusSuccessFinishResult);1329 } else if (bytes_written > 0) {1330 // Some byte written1331 result.GetOutputStream().Printf(1332 "%" PRIu64 " bytes of %" PRIu641333 " requested were written to 0x%" PRIx64 "\n",1334 (uint64_t)bytes_written, (uint64_t)length, addr);1335 result.SetStatus(eReturnStatusSuccessFinishResult);1336 } else {1337 result.AppendErrorWithFormat("Memory write to 0x%" PRIx641338 " failed: %s.\n",1339 addr, error.AsCString());1340 }1341 }1342 } else {1343 result.AppendErrorWithFormat("Unable to read contents of file.\n");1344 }1345 return;1346 } else if (item_byte_size == 0) {1347 if (m_format_options.GetFormat() == eFormatPointer)1348 item_byte_size = buffer.GetAddressByteSize();1349 else1350 item_byte_size = 1;1351 }1352 1353 command.Shift(); // shift off the address argument1354 uint64_t uval64;1355 int64_t sval64;1356 bool success = false;1357 for (auto &entry : command) {1358 switch (m_format_options.GetFormat()) {1359 case kNumFormats:1360 case eFormatFloat: // TODO: add support for floats soon1361 case eFormatFloat128:1362 case eFormatCharPrintable:1363 case eFormatBytesWithASCII:1364 case eFormatComplex:1365 case eFormatEnum:1366 case eFormatUnicode8:1367 case eFormatUnicode16:1368 case eFormatUnicode32:1369 case eFormatVectorOfChar:1370 case eFormatVectorOfSInt8:1371 case eFormatVectorOfUInt8:1372 case eFormatVectorOfSInt16:1373 case eFormatVectorOfUInt16:1374 case eFormatVectorOfSInt32:1375 case eFormatVectorOfUInt32:1376 case eFormatVectorOfSInt64:1377 case eFormatVectorOfUInt64:1378 case eFormatVectorOfFloat16:1379 case eFormatVectorOfFloat32:1380 case eFormatVectorOfFloat64:1381 case eFormatVectorOfUInt128:1382 case eFormatOSType:1383 case eFormatComplexInteger:1384 case eFormatAddressInfo:1385 case eFormatHexFloat:1386 case eFormatInstruction:1387 case eFormatVoid:1388 result.AppendError("unsupported format for writing memory");1389 return;1390 1391 case eFormatDefault:1392 case eFormatBytes:1393 case eFormatHex:1394 case eFormatHexUppercase:1395 case eFormatPointer: {1396 // Decode hex bytes1397 // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we1398 // have to special case that:1399 bool success = false;1400 if (entry.ref().starts_with("0x"))1401 success = !entry.ref().getAsInteger(0, uval64);1402 if (!success)1403 success = !entry.ref().getAsInteger(16, uval64);1404 if (!success) {1405 result.AppendErrorWithFormat(1406 "'%s' is not a valid hex string value.\n", entry.c_str());1407 return;1408 } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1409 result.AppendErrorWithFormat("Value 0x%" PRIx641410 " is too large to fit in a %" PRIu641411 " byte unsigned integer value.\n",1412 uval64, (uint64_t)item_byte_size);1413 return;1414 }1415 buffer.PutMaxHex64(uval64, item_byte_size);1416 break;1417 }1418 case eFormatBoolean:1419 uval64 = OptionArgParser::ToBoolean(entry.ref(), false, &success);1420 if (!success) {1421 result.AppendErrorWithFormat(1422 "'%s' is not a valid boolean string value.\n", entry.c_str());1423 return;1424 }1425 buffer.PutMaxHex64(uval64, item_byte_size);1426 break;1427 1428 case eFormatBinary:1429 if (entry.ref().getAsInteger(2, uval64)) {1430 result.AppendErrorWithFormat(1431 "'%s' is not a valid binary string value.\n", entry.c_str());1432 return;1433 } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1434 result.AppendErrorWithFormat("Value 0x%" PRIx641435 " is too large to fit in a %" PRIu641436 " byte unsigned integer value.\n",1437 uval64, (uint64_t)item_byte_size);1438 return;1439 }1440 buffer.PutMaxHex64(uval64, item_byte_size);1441 break;1442 1443 case eFormatCharArray:1444 case eFormatChar:1445 case eFormatCString: {1446 if (entry.ref().empty())1447 break;1448 1449 size_t len = entry.ref().size();1450 // Include the NULL for C strings...1451 if (m_format_options.GetFormat() == eFormatCString)1452 ++len;1453 Status error;1454 if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {1455 addr += len;1456 } else {1457 result.AppendErrorWithFormat("Memory write to 0x%" PRIx641458 " failed: %s.\n",1459 addr, error.AsCString());1460 return;1461 }1462 break;1463 }1464 case eFormatDecimal:1465 if (entry.ref().getAsInteger(0, sval64)) {1466 result.AppendErrorWithFormat(1467 "'%s' is not a valid signed decimal value.\n", entry.c_str());1468 return;1469 } else if (!llvm::isIntN(item_byte_size * 8, sval64)) {1470 result.AppendErrorWithFormat(1471 "Value %" PRIi64 " is too large or small to fit in a %" PRIu641472 " byte signed integer value.\n",1473 sval64, (uint64_t)item_byte_size);1474 return;1475 }1476 buffer.PutMaxHex64(sval64, item_byte_size);1477 break;1478 1479 case eFormatUnsigned:1480 1481 if (entry.ref().getAsInteger(0, uval64)) {1482 result.AppendErrorWithFormat(1483 "'%s' is not a valid unsigned decimal string value.\n",1484 entry.c_str());1485 return;1486 } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1487 result.AppendErrorWithFormat("Value %" PRIu641488 " is too large to fit in a %" PRIu641489 " byte unsigned integer value.\n",1490 uval64, (uint64_t)item_byte_size);1491 return;1492 }1493 buffer.PutMaxHex64(uval64, item_byte_size);1494 break;1495 1496 case eFormatOctal:1497 if (entry.ref().getAsInteger(8, uval64)) {1498 result.AppendErrorWithFormat(1499 "'%s' is not a valid octal string value.\n", entry.c_str());1500 return;1501 } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1502 result.AppendErrorWithFormat("Value %" PRIo641503 " is too large to fit in a %" PRIu641504 " byte unsigned integer value.\n",1505 uval64, (uint64_t)item_byte_size);1506 return;1507 }1508 buffer.PutMaxHex64(uval64, item_byte_size);1509 break;1510 }1511 }1512 1513 if (!buffer.GetString().empty()) {1514 Status error;1515 const char *buffer_data = buffer.GetString().data();1516 const size_t buffer_size = buffer.GetString().size();1517 const size_t write_size =1518 process->WriteMemory(addr, buffer_data, buffer_size, error);1519 1520 if (write_size != buffer_size) {1521 result.AppendErrorWithFormat("Memory write to 0x%" PRIx641522 " failed: %s.\n",1523 addr, error.AsCString());1524 return;1525 }1526 }1527 }1528 1529 OptionGroupOptions m_option_group;1530 OptionGroupFormat m_format_options;1531 OptionGroupWriteMemory m_memory_options;1532};1533 1534// Get malloc/free history of a memory address.1535class CommandObjectMemoryHistory : public CommandObjectParsed {1536public:1537 CommandObjectMemoryHistory(CommandInterpreter &interpreter)1538 : CommandObjectParsed(interpreter, "memory history",1539 "Print recorded stack traces for "1540 "allocation/deallocation events "1541 "associated with an address.",1542 nullptr,1543 eCommandRequiresTarget | eCommandRequiresProcess |1544 eCommandProcessMustBePaused |1545 eCommandProcessMustBeLaunched) {1546 CommandArgumentEntry arg1;1547 CommandArgumentData addr_arg;1548 1549 // Define the first (and only) variant of this arg.1550 addr_arg.arg_type = eArgTypeAddress;1551 addr_arg.arg_repetition = eArgRepeatPlain;1552 1553 // There is only one variant this argument could be; put it into the1554 // argument entry.1555 arg1.push_back(addr_arg);1556 1557 // Push the data for the first argument into the m_arguments vector.1558 m_arguments.push_back(arg1);1559 }1560 1561 ~CommandObjectMemoryHistory() override = default;1562 1563 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,1564 uint32_t index) override {1565 return m_cmd_name;1566 }1567 1568protected:1569 void DoExecute(Args &command, CommandReturnObject &result) override {1570 const size_t argc = command.GetArgumentCount();1571 1572 if (argc == 0 || argc > 1) {1573 result.AppendErrorWithFormat("%s takes an address expression",1574 m_cmd_name.c_str());1575 return;1576 }1577 1578 Status error;1579 lldb::addr_t addr = OptionArgParser::ToAddress(1580 &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);1581 1582 if (addr == LLDB_INVALID_ADDRESS) {1583 result.AppendError("invalid address expression");1584 result.AppendError(error.AsCString());1585 return;1586 }1587 1588 Stream *output_stream = &result.GetOutputStream();1589 1590 const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();1591 const MemoryHistorySP &memory_history =1592 MemoryHistory::FindPlugin(process_sp);1593 1594 if (!memory_history) {1595 result.AppendError("no available memory history provider");1596 return;1597 }1598 1599 HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);1600 1601 const bool stop_format = false;1602 for (auto thread : thread_list) {1603 thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format,1604 /*should_filter*/ false);1605 }1606 1607 result.SetStatus(eReturnStatusSuccessFinishResult);1608 }1609};1610 1611// CommandObjectMemoryRegion1612#pragma mark CommandObjectMemoryRegion1613 1614#define LLDB_OPTIONS_memory_region1615#include "CommandOptions.inc"1616 1617class CommandObjectMemoryRegion : public CommandObjectParsed {1618public:1619 class OptionGroupMemoryRegion : public OptionGroup {1620 public:1621 OptionGroupMemoryRegion() : m_all(false, false) {}1622 1623 ~OptionGroupMemoryRegion() override = default;1624 1625 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1626 return llvm::ArrayRef(g_memory_region_options);1627 }1628 1629 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,1630 ExecutionContext *execution_context) override {1631 Status status;1632 const int short_option = g_memory_region_options[option_idx].short_option;1633 1634 switch (short_option) {1635 case 'a':1636 m_all.SetCurrentValue(true);1637 m_all.SetOptionWasSet();1638 break;1639 default:1640 llvm_unreachable("Unimplemented option");1641 }1642 1643 return status;1644 }1645 1646 void OptionParsingStarting(ExecutionContext *execution_context) override {1647 m_all.Clear();1648 }1649 1650 OptionValueBoolean m_all;1651 };1652 1653 CommandObjectMemoryRegion(CommandInterpreter &interpreter)1654 : CommandObjectParsed(interpreter, "memory region",1655 "Get information on the memory region containing "1656 "an address in the current target process.",1657 "memory region <address-expression> (or --all)",1658 eCommandRequiresProcess | eCommandTryTargetAPILock |1659 eCommandProcessMustBeLaunched) {1660 // Address in option set 1.1661 m_arguments.push_back(CommandArgumentEntry{CommandArgumentData(1662 eArgTypeAddressOrExpression, eArgRepeatPlain, LLDB_OPT_SET_1)});1663 // "--all" will go in option set 2.1664 m_option_group.Append(&m_memory_region_options);1665 m_option_group.Finalize();1666 }1667 1668 ~CommandObjectMemoryRegion() override = default;1669 1670 Options *GetOptions() override { return &m_option_group; }1671 1672protected:1673 void DumpRegion(CommandReturnObject &result, Target &target,1674 const MemoryRegionInfo &range_info, lldb::addr_t load_addr) {1675 lldb_private::Address addr;1676 ConstString section_name;1677 if (target.ResolveLoadAddress(load_addr, addr)) {1678 SectionSP section_sp(addr.GetSection());1679 if (section_sp) {1680 // Got the top most section, not the deepest section1681 while (section_sp->GetParent())1682 section_sp = section_sp->GetParent();1683 section_name = section_sp->GetName();1684 }1685 }1686 1687 ConstString name = range_info.GetName();1688 result.AppendMessageWithFormatv(1689 "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",1690 range_info.GetRange().GetRangeBase(),1691 range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),1692 range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",1693 name, section_name ? " " : "", section_name);1694 MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged();1695 if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)1696 result.AppendMessage("memory tagging: enabled");1697 MemoryRegionInfo::OptionalBool is_shadow_stack = range_info.IsShadowStack();1698 if (is_shadow_stack == MemoryRegionInfo::OptionalBool::eYes)1699 result.AppendMessage("shadow stack: yes");1700 1701 const std::optional<std::vector<addr_t>> &dirty_page_list =1702 range_info.GetDirtyPageList();1703 if (dirty_page_list) {1704 const size_t page_count = dirty_page_list->size();1705 result.AppendMessageWithFormat(1706 "Modified memory (dirty) page list provided, %zu entries.\n",1707 page_count);1708 if (page_count > 0) {1709 bool print_comma = false;1710 result.AppendMessageWithFormat("Dirty pages: ");1711 for (size_t i = 0; i < page_count; i++) {1712 if (print_comma)1713 result.AppendMessageWithFormat(", ");1714 else1715 print_comma = true;1716 result.AppendMessageWithFormat("0x%" PRIx64, (*dirty_page_list)[i]);1717 }1718 result.AppendMessageWithFormat(".\n");1719 }1720 }1721 }1722 1723 void DoExecute(Args &command, CommandReturnObject &result) override {1724 ProcessSP process_sp = m_exe_ctx.GetProcessSP();1725 if (!process_sp) {1726 m_prev_end_addr = LLDB_INVALID_ADDRESS;1727 result.AppendError("invalid process");1728 return;1729 }1730 1731 Status error;1732 lldb::addr_t load_addr = m_prev_end_addr;1733 m_prev_end_addr = LLDB_INVALID_ADDRESS;1734 1735 const size_t argc = command.GetArgumentCount();1736 const lldb::ABISP &abi = process_sp->GetABI();1737 1738 if (argc == 1) {1739 if (m_memory_region_options.m_all) {1740 result.AppendError(1741 "The \"--all\" option cannot be used when an address "1742 "argument is given");1743 return;1744 }1745 1746 auto load_addr_str = command[0].ref();1747 load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,1748 LLDB_INVALID_ADDRESS, &error);1749 if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {1750 result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n",1751 command[0].c_str(), error.AsCString());1752 return;1753 }1754 } else if (argc > 1 ||1755 // When we're repeating the command, the previous end address is1756 // used for load_addr. If that was 0xF...F then we must have1757 // reached the end of memory.1758 (argc == 0 && !m_memory_region_options.m_all &&1759 load_addr == LLDB_INVALID_ADDRESS) ||1760 // If the target has non-address bits (tags, limited virtual1761 // address size, etc.), the end of mappable memory will be lower1762 // than that. So if we find any non-address bit set, we must be1763 // at the end of the mappable range.1764 (abi && (abi->FixAnyAddress(load_addr) != load_addr))) {1765 result.AppendErrorWithFormat(1766 "'%s' takes one argument or \"--all\" option:\nUsage: %s\n",1767 m_cmd_name.c_str(), m_cmd_syntax.c_str());1768 return;1769 }1770 1771 // It is important that we track the address used to request the region as1772 // this will give the correct section name in the case that regions overlap.1773 // On Windows we get multiple regions that start at the same place but are1774 // different sizes and refer to different sections.1775 std::vector<std::pair<lldb_private::MemoryRegionInfo, lldb::addr_t>>1776 region_list;1777 if (m_memory_region_options.m_all) {1778 // We don't use GetMemoryRegions here because it doesn't include unmapped1779 // areas like repeating the command would. So instead, emulate doing that.1780 lldb::addr_t addr = 0;1781 while (error.Success() && addr != LLDB_INVALID_ADDRESS &&1782 // When there are non-address bits the last range will not extend1783 // to LLDB_INVALID_ADDRESS but to the max virtual address.1784 // This prevents us looping forever if that is the case.1785 (!abi || (abi->FixAnyAddress(addr) == addr))) {1786 lldb_private::MemoryRegionInfo region_info;1787 error = process_sp->GetMemoryRegionInfo(addr, region_info);1788 1789 if (error.Success()) {1790 region_list.push_back({region_info, addr});1791 addr = region_info.GetRange().GetRangeEnd();1792 }1793 }1794 } else {1795 lldb_private::MemoryRegionInfo region_info;1796 error = process_sp->GetMemoryRegionInfo(load_addr, region_info);1797 if (error.Success())1798 region_list.push_back({region_info, load_addr});1799 }1800 1801 if (error.Success()) {1802 for (std::pair<MemoryRegionInfo, addr_t> &range : region_list) {1803 DumpRegion(result, process_sp->GetTarget(), range.first, range.second);1804 m_prev_end_addr = range.first.GetRange().GetRangeEnd();1805 }1806 1807 result.SetStatus(eReturnStatusSuccessFinishResult);1808 return;1809 }1810 1811 result.AppendErrorWithFormat("%s\n", error.AsCString());1812 }1813 1814 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,1815 uint32_t index) override {1816 // If we repeat this command, repeat it without any arguments so we can1817 // show the next memory range1818 return m_cmd_name;1819 }1820 1821 lldb::addr_t m_prev_end_addr = LLDB_INVALID_ADDRESS;1822 1823 OptionGroupOptions m_option_group;1824 OptionGroupMemoryRegion m_memory_region_options;1825};1826 1827// CommandObjectMemory1828 1829CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)1830 : CommandObjectMultiword(1831 interpreter, "memory",1832 "Commands for operating on memory in the current target process.",1833 "memory <subcommand> [<subcommand-options>]") {1834 LoadSubCommand("find",1835 CommandObjectSP(new CommandObjectMemoryFind(interpreter)));1836 LoadSubCommand("read",1837 CommandObjectSP(new CommandObjectMemoryRead(interpreter)));1838 LoadSubCommand("write",1839 CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));1840 LoadSubCommand("history",1841 CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));1842 LoadSubCommand("region",1843 CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));1844 LoadSubCommand("tag",1845 CommandObjectSP(new CommandObjectMemoryTag(interpreter)));1846}1847 1848CommandObjectMemory::~CommandObjectMemory() = default;1849