Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp
39587 views
//===-- CommandObjectMemory.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "CommandObjectMemory.h"9#include "CommandObjectMemoryTag.h"10#include "lldb/Core/DumpDataExtractor.h"11#include "lldb/Core/Section.h"12#include "lldb/Core/ValueObjectMemory.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 "llvm/Support/MathExtras.h"39#include <cinttypes>40#include <memory>41#include <optional>4243using namespace lldb;44using namespace lldb_private;4546#define LLDB_OPTIONS_memory_read47#include "CommandOptions.inc"4849class OptionGroupReadMemory : public OptionGroup {50public:51OptionGroupReadMemory()52: m_num_per_line(1, 1), m_offset(0, 0),53m_language_for_type(eLanguageTypeUnknown) {}5455~OptionGroupReadMemory() override = default;5657llvm::ArrayRef<OptionDefinition> GetDefinitions() override {58return llvm::ArrayRef(g_memory_read_options);59}6061Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,62ExecutionContext *execution_context) override {63Status error;64const int short_option = g_memory_read_options[option_idx].short_option;6566switch (short_option) {67case 'l':68error = m_num_per_line.SetValueFromString(option_value);69if (m_num_per_line.GetCurrentValue() == 0)70error.SetErrorStringWithFormat(71"invalid value for --num-per-line option '%s'",72option_value.str().c_str());73break;7475case 'b':76m_output_as_binary = true;77break;7879case 't':80error = m_view_as_type.SetValueFromString(option_value);81break;8283case 'r':84m_force = true;85break;8687case 'x':88error = m_language_for_type.SetValueFromString(option_value);89break;9091case 'E':92error = m_offset.SetValueFromString(option_value);93break;9495default:96llvm_unreachable("Unimplemented option");97}98return error;99}100101void OptionParsingStarting(ExecutionContext *execution_context) override {102m_num_per_line.Clear();103m_output_as_binary = false;104m_view_as_type.Clear();105m_force = false;106m_offset.Clear();107m_language_for_type.Clear();108}109110Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {111Status error;112OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();113OptionValueUInt64 &count_value = format_options.GetCountValue();114const bool byte_size_option_set = byte_size_value.OptionWasSet();115const bool num_per_line_option_set = m_num_per_line.OptionWasSet();116const bool count_option_set = format_options.GetCountValue().OptionWasSet();117118switch (format_options.GetFormat()) {119default:120break;121122case eFormatBoolean:123if (!byte_size_option_set)124byte_size_value = 1;125if (!num_per_line_option_set)126m_num_per_line = 1;127if (!count_option_set)128format_options.GetCountValue() = 8;129break;130131case eFormatCString:132break;133134case eFormatInstruction:135if (count_option_set)136byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();137m_num_per_line = 1;138break;139140case eFormatAddressInfo:141if (!byte_size_option_set)142byte_size_value = target->GetArchitecture().GetAddressByteSize();143m_num_per_line = 1;144if (!count_option_set)145format_options.GetCountValue() = 8;146break;147148case eFormatPointer:149byte_size_value = target->GetArchitecture().GetAddressByteSize();150if (!num_per_line_option_set)151m_num_per_line = 4;152if (!count_option_set)153format_options.GetCountValue() = 8;154break;155156case eFormatBinary:157case eFormatFloat:158case eFormatOctal:159case eFormatDecimal:160case eFormatEnum:161case eFormatUnicode8:162case eFormatUnicode16:163case eFormatUnicode32:164case eFormatUnsigned:165case eFormatHexFloat:166if (!byte_size_option_set)167byte_size_value = 4;168if (!num_per_line_option_set)169m_num_per_line = 1;170if (!count_option_set)171format_options.GetCountValue() = 8;172break;173174case eFormatBytes:175case eFormatBytesWithASCII:176if (byte_size_option_set) {177if (byte_size_value > 1)178error.SetErrorStringWithFormat(179"display format (bytes/bytes with ASCII) conflicts with the "180"specified byte size %" PRIu64 "\n"181"\tconsider using a different display format or don't specify "182"the byte size.",183byte_size_value.GetCurrentValue());184} else185byte_size_value = 1;186if (!num_per_line_option_set)187m_num_per_line = 16;188if (!count_option_set)189format_options.GetCountValue() = 32;190break;191192case eFormatCharArray:193case eFormatChar:194case eFormatCharPrintable:195if (!byte_size_option_set)196byte_size_value = 1;197if (!num_per_line_option_set)198m_num_per_line = 32;199if (!count_option_set)200format_options.GetCountValue() = 64;201break;202203case eFormatComplex:204if (!byte_size_option_set)205byte_size_value = 8;206if (!num_per_line_option_set)207m_num_per_line = 1;208if (!count_option_set)209format_options.GetCountValue() = 8;210break;211212case eFormatComplexInteger:213if (!byte_size_option_set)214byte_size_value = 8;215if (!num_per_line_option_set)216m_num_per_line = 1;217if (!count_option_set)218format_options.GetCountValue() = 8;219break;220221case eFormatHex:222if (!byte_size_option_set)223byte_size_value = 4;224if (!num_per_line_option_set) {225switch (byte_size_value) {226case 1:227case 2:228m_num_per_line = 8;229break;230case 4:231m_num_per_line = 4;232break;233case 8:234m_num_per_line = 2;235break;236default:237m_num_per_line = 1;238break;239}240}241if (!count_option_set)242count_value = 8;243break;244245case eFormatVectorOfChar:246case eFormatVectorOfSInt8:247case eFormatVectorOfUInt8:248case eFormatVectorOfSInt16:249case eFormatVectorOfUInt16:250case eFormatVectorOfSInt32:251case eFormatVectorOfUInt32:252case eFormatVectorOfSInt64:253case eFormatVectorOfUInt64:254case eFormatVectorOfFloat16:255case eFormatVectorOfFloat32:256case eFormatVectorOfFloat64:257case eFormatVectorOfUInt128:258if (!byte_size_option_set)259byte_size_value = 128;260if (!num_per_line_option_set)261m_num_per_line = 1;262if (!count_option_set)263count_value = 4;264break;265}266return error;267}268269bool AnyOptionWasSet() const {270return m_num_per_line.OptionWasSet() || m_output_as_binary ||271m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||272m_language_for_type.OptionWasSet();273}274275OptionValueUInt64 m_num_per_line;276bool m_output_as_binary = false;277OptionValueString m_view_as_type;278bool m_force = false;279OptionValueUInt64 m_offset;280OptionValueLanguage m_language_for_type;281};282283// Read memory from the inferior process284class CommandObjectMemoryRead : public CommandObjectParsed {285public:286CommandObjectMemoryRead(CommandInterpreter &interpreter)287: CommandObjectParsed(288interpreter, "memory read",289"Read from the memory of the current target process.", nullptr,290eCommandRequiresTarget | eCommandProcessMustBePaused),291m_format_options(eFormatBytesWithASCII, 1, 8),292m_memory_tag_options(/*note_binary=*/true),293m_prev_format_options(eFormatBytesWithASCII, 1, 8) {294CommandArgumentEntry arg1;295CommandArgumentEntry arg2;296CommandArgumentData start_addr_arg;297CommandArgumentData end_addr_arg;298299// Define the first (and only) variant of this arg.300start_addr_arg.arg_type = eArgTypeAddressOrExpression;301start_addr_arg.arg_repetition = eArgRepeatPlain;302303// There is only one variant this argument could be; put it into the304// argument entry.305arg1.push_back(start_addr_arg);306307// Define the first (and only) variant of this arg.308end_addr_arg.arg_type = eArgTypeAddressOrExpression;309end_addr_arg.arg_repetition = eArgRepeatOptional;310311// There is only one variant this argument could be; put it into the312// argument entry.313arg2.push_back(end_addr_arg);314315// Push the data for the first argument into the m_arguments vector.316m_arguments.push_back(arg1);317m_arguments.push_back(arg2);318319// Add the "--format" and "--count" options to group 1 and 3320m_option_group.Append(&m_format_options,321OptionGroupFormat::OPTION_GROUP_FORMAT |322OptionGroupFormat::OPTION_GROUP_COUNT,323LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);324m_option_group.Append(&m_format_options,325OptionGroupFormat::OPTION_GROUP_GDB_FMT,326LLDB_OPT_SET_1 | LLDB_OPT_SET_3);327// Add the "--size" option to group 1 and 2328m_option_group.Append(&m_format_options,329OptionGroupFormat::OPTION_GROUP_SIZE,330LLDB_OPT_SET_1 | LLDB_OPT_SET_2);331m_option_group.Append(&m_memory_options);332m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,333LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);334m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);335m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,336LLDB_OPT_SET_ALL);337m_option_group.Finalize();338}339340~CommandObjectMemoryRead() override = default;341342Options *GetOptions() override { return &m_option_group; }343344std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,345uint32_t index) override {346return m_cmd_name;347}348349protected:350void DoExecute(Args &command, CommandReturnObject &result) override {351// No need to check "target" for validity as eCommandRequiresTarget ensures352// it is valid353Target *target = m_exe_ctx.GetTargetPtr();354355const size_t argc = command.GetArgumentCount();356357if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {358result.AppendErrorWithFormat("%s takes a start address expression with "359"an optional end address expression.\n",360m_cmd_name.c_str());361result.AppendWarning("Expressions should be quoted if they contain "362"spaces or other special characters.");363return;364}365366CompilerType compiler_type;367Status error;368369const char *view_as_type_cstr =370m_memory_options.m_view_as_type.GetCurrentValue();371if (view_as_type_cstr && view_as_type_cstr[0]) {372// We are viewing memory as a type373374uint32_t reference_count = 0;375uint32_t pointer_count = 0;376size_t idx;377378#define ALL_KEYWORDS \379KEYWORD("const") \380KEYWORD("volatile") \381KEYWORD("restrict") \382KEYWORD("struct") \383KEYWORD("class") \384KEYWORD("union")385386#define KEYWORD(s) s,387static const char *g_keywords[] = {ALL_KEYWORDS};388#undef KEYWORD389390#define KEYWORD(s) (sizeof(s) - 1),391static const int g_keyword_lengths[] = {ALL_KEYWORDS};392#undef KEYWORD393394#undef ALL_KEYWORDS395396static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);397std::string type_str(view_as_type_cstr);398399// Remove all instances of g_keywords that are followed by spaces400for (size_t i = 0; i < g_num_keywords; ++i) {401const char *keyword = g_keywords[i];402int keyword_len = g_keyword_lengths[i];403404idx = 0;405while ((idx = type_str.find(keyword, idx)) != std::string::npos) {406if (type_str[idx + keyword_len] == ' ' ||407type_str[idx + keyword_len] == '\t') {408type_str.erase(idx, keyword_len + 1);409idx = 0;410} else {411idx += keyword_len;412}413}414}415bool done = type_str.empty();416//417idx = type_str.find_first_not_of(" \t");418if (idx > 0 && idx != std::string::npos)419type_str.erase(0, idx);420while (!done) {421// Strip trailing spaces422if (type_str.empty())423done = true;424else {425switch (type_str[type_str.size() - 1]) {426case '*':427++pointer_count;428[[fallthrough]];429case ' ':430case '\t':431type_str.erase(type_str.size() - 1);432break;433434case '&':435if (reference_count == 0) {436reference_count = 1;437type_str.erase(type_str.size() - 1);438} else {439result.AppendErrorWithFormat("invalid type string: '%s'\n",440view_as_type_cstr);441return;442}443break;444445default:446done = true;447break;448}449}450}451452ConstString lookup_type_name(type_str.c_str());453StackFrame *frame = m_exe_ctx.GetFramePtr();454ModuleSP search_first;455if (frame)456search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;457TypeQuery query(lookup_type_name.GetStringRef(),458TypeQueryOptions::e_find_one);459TypeResults results;460target->GetImages().FindTypes(search_first.get(), query, results);461TypeSP type_sp = results.GetFirstType();462463if (!type_sp && lookup_type_name.GetCString()) {464LanguageType language_for_type =465m_memory_options.m_language_for_type.GetCurrentValue();466std::set<LanguageType> languages_to_check;467if (language_for_type != eLanguageTypeUnknown) {468languages_to_check.insert(language_for_type);469} else {470languages_to_check = Language::GetSupportedLanguages();471}472473std::set<CompilerType> user_defined_types;474for (auto lang : languages_to_check) {475if (auto *persistent_vars =476target->GetPersistentExpressionStateForLanguage(lang)) {477if (std::optional<CompilerType> type =478persistent_vars->GetCompilerTypeFromPersistentDecl(479lookup_type_name)) {480user_defined_types.emplace(*type);481}482}483}484485if (user_defined_types.size() > 1) {486result.AppendErrorWithFormat(487"Mutiple types found matching raw type '%s', please disambiguate "488"by specifying the language with -x",489lookup_type_name.GetCString());490return;491}492493if (user_defined_types.size() == 1) {494compiler_type = *user_defined_types.begin();495}496}497498if (!compiler_type.IsValid()) {499if (type_sp) {500compiler_type = type_sp->GetFullCompilerType();501} else {502result.AppendErrorWithFormat("unable to find any types that match "503"the raw type '%s' for full type '%s'\n",504lookup_type_name.GetCString(),505view_as_type_cstr);506return;507}508}509510while (pointer_count > 0) {511CompilerType pointer_type = compiler_type.GetPointerType();512if (pointer_type.IsValid())513compiler_type = pointer_type;514else {515result.AppendError("unable make a pointer type\n");516return;517}518--pointer_count;519}520521std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);522if (!size) {523result.AppendErrorWithFormat(524"unable to get the byte size of the type '%s'\n",525view_as_type_cstr);526return;527}528m_format_options.GetByteSizeValue() = *size;529530if (!m_format_options.GetCountValue().OptionWasSet())531m_format_options.GetCountValue() = 1;532} else {533error = m_memory_options.FinalizeSettings(target, m_format_options);534}535536// Look for invalid combinations of settings537if (error.Fail()) {538result.AppendError(error.AsCString());539return;540}541542lldb::addr_t addr;543size_t total_byte_size = 0;544if (argc == 0) {545// Use the last address and byte size and all options as they were if no546// options have been set547addr = m_next_addr;548total_byte_size = m_prev_byte_size;549compiler_type = m_prev_compiler_type;550if (!m_format_options.AnyOptionWasSet() &&551!m_memory_options.AnyOptionWasSet() &&552!m_outfile_options.AnyOptionWasSet() &&553!m_varobj_options.AnyOptionWasSet() &&554!m_memory_tag_options.AnyOptionWasSet()) {555m_format_options = m_prev_format_options;556m_memory_options = m_prev_memory_options;557m_outfile_options = m_prev_outfile_options;558m_varobj_options = m_prev_varobj_options;559m_memory_tag_options = m_prev_memory_tag_options;560}561}562563size_t item_count = m_format_options.GetCountValue().GetCurrentValue();564565// TODO For non-8-bit byte addressable architectures this needs to be566// revisited to fully support all lldb's range of formatting options.567// Furthermore code memory reads (for those architectures) will not be568// correctly formatted even w/o formatting options.569size_t item_byte_size =570target->GetArchitecture().GetDataByteSize() > 1571? target->GetArchitecture().GetDataByteSize()572: m_format_options.GetByteSizeValue().GetCurrentValue();573574const size_t num_per_line =575m_memory_options.m_num_per_line.GetCurrentValue();576577if (total_byte_size == 0) {578total_byte_size = item_count * item_byte_size;579if (total_byte_size == 0)580total_byte_size = 32;581}582583if (argc > 0)584addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(),585LLDB_INVALID_ADDRESS, &error);586587if (addr == LLDB_INVALID_ADDRESS) {588result.AppendError("invalid start address expression.");589result.AppendError(error.AsCString());590return;591}592593if (argc == 2) {594lldb::addr_t end_addr = OptionArgParser::ToAddress(595&m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, nullptr);596597if (end_addr == LLDB_INVALID_ADDRESS) {598result.AppendError("invalid end address expression.");599result.AppendError(error.AsCString());600return;601} else if (end_addr <= addr) {602result.AppendErrorWithFormat(603"end address (0x%" PRIx64604") must be greater than the start address (0x%" PRIx64 ").\n",605end_addr, addr);606return;607} else if (m_format_options.GetCountValue().OptionWasSet()) {608result.AppendErrorWithFormat(609"specify either the end address (0x%" PRIx64610") or the count (--count %" PRIu64 "), not both.\n",611end_addr, (uint64_t)item_count);612return;613}614615total_byte_size = end_addr - addr;616item_count = total_byte_size / item_byte_size;617}618619uint32_t max_unforced_size = target->GetMaximumMemReadSize();620621if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {622result.AppendErrorWithFormat(623"Normally, \'memory read\' will not read over %" PRIu32624" bytes of data.\n",625max_unforced_size);626result.AppendErrorWithFormat(627"Please use --force to override this restriction just once.\n");628result.AppendErrorWithFormat("or set target.max-memory-read-size if you "629"will often need a larger limit.\n");630return;631}632633WritableDataBufferSP data_sp;634size_t bytes_read = 0;635if (compiler_type.GetOpaqueQualType()) {636// Make sure we don't display our type as ASCII bytes like the default637// memory read638if (!m_format_options.GetFormatValue().OptionWasSet())639m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);640641std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);642if (!size) {643result.AppendError("can't get size of type");644return;645}646bytes_read = *size * m_format_options.GetCountValue().GetCurrentValue();647648if (argc > 0)649addr = addr + (*size * m_memory_options.m_offset.GetCurrentValue());650} else if (m_format_options.GetFormatValue().GetCurrentValue() !=651eFormatCString) {652data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');653if (data_sp->GetBytes() == nullptr) {654result.AppendErrorWithFormat(655"can't allocate 0x%" PRIx32656" bytes for the memory read buffer, specify a smaller size to read",657(uint32_t)total_byte_size);658return;659}660661Address address(addr, nullptr);662bytes_read = target->ReadMemory(address, data_sp->GetBytes(),663data_sp->GetByteSize(), error, true);664if (bytes_read == 0) {665const char *error_cstr = error.AsCString();666if (error_cstr && error_cstr[0]) {667result.AppendError(error_cstr);668} else {669result.AppendErrorWithFormat(670"failed to read memory from 0x%" PRIx64 ".\n", addr);671}672return;673}674675if (bytes_read < total_byte_size)676result.AppendWarningWithFormat(677"Not all bytes (%" PRIu64 "/%" PRIu64678") were able to be read from 0x%" PRIx64 ".\n",679(uint64_t)bytes_read, (uint64_t)total_byte_size, addr);680} else {681// we treat c-strings as a special case because they do not have a fixed682// size683if (m_format_options.GetByteSizeValue().OptionWasSet() &&684!m_format_options.HasGDBFormat())685item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();686else687item_byte_size = target->GetMaximumSizeOfStringSummary();688if (!m_format_options.GetCountValue().OptionWasSet())689item_count = 1;690data_sp = std::make_shared<DataBufferHeap>(691(item_byte_size + 1) * item_count,692'\0'); // account for NULLs as necessary693if (data_sp->GetBytes() == nullptr) {694result.AppendErrorWithFormat(695"can't allocate 0x%" PRIx64696" bytes for the memory read buffer, specify a smaller size to read",697(uint64_t)((item_byte_size + 1) * item_count));698return;699}700uint8_t *data_ptr = data_sp->GetBytes();701auto data_addr = addr;702auto count = item_count;703item_count = 0;704bool break_on_no_NULL = false;705while (item_count < count) {706std::string buffer;707buffer.resize(item_byte_size + 1, 0);708Status error;709size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],710item_byte_size + 1, error);711if (error.Fail()) {712result.AppendErrorWithFormat(713"failed to read memory from 0x%" PRIx64 ".\n", addr);714return;715}716717if (item_byte_size == read) {718result.AppendWarningWithFormat(719"unable to find a NULL terminated string at 0x%" PRIx64720". Consider increasing the maximum read length.\n",721data_addr);722--read;723break_on_no_NULL = true;724} else725++read; // account for final NULL byte726727memcpy(data_ptr, &buffer[0], read);728data_ptr += read;729data_addr += read;730bytes_read += read;731item_count++; // if we break early we know we only read item_count732// strings733734if (break_on_no_NULL)735break;736}737data_sp =738std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);739}740741m_next_addr = addr + bytes_read;742m_prev_byte_size = bytes_read;743m_prev_format_options = m_format_options;744m_prev_memory_options = m_memory_options;745m_prev_outfile_options = m_outfile_options;746m_prev_varobj_options = m_varobj_options;747m_prev_memory_tag_options = m_memory_tag_options;748m_prev_compiler_type = compiler_type;749750std::unique_ptr<Stream> output_stream_storage;751Stream *output_stream_p = nullptr;752const FileSpec &outfile_spec =753m_outfile_options.GetFile().GetCurrentValue();754755std::string path = outfile_spec.GetPath();756if (outfile_spec) {757758File::OpenOptions open_options =759File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;760const bool append = m_outfile_options.GetAppend().GetCurrentValue();761open_options |=762append ? File::eOpenOptionAppend : File::eOpenOptionTruncate;763764auto outfile = FileSystem::Instance().Open(outfile_spec, open_options);765766if (outfile) {767auto outfile_stream_up =768std::make_unique<StreamFile>(std::move(outfile.get()));769if (m_memory_options.m_output_as_binary) {770const size_t bytes_written =771outfile_stream_up->Write(data_sp->GetBytes(), bytes_read);772if (bytes_written > 0) {773result.GetOutputStream().Printf(774"%zi bytes %s to '%s'\n", bytes_written,775append ? "appended" : "written", path.c_str());776return;777} else {778result.AppendErrorWithFormat("Failed to write %" PRIu64779" bytes to '%s'.\n",780(uint64_t)bytes_read, path.c_str());781return;782}783} else {784// We are going to write ASCII to the file just point the785// output_stream to our outfile_stream...786output_stream_storage = std::move(outfile_stream_up);787output_stream_p = output_stream_storage.get();788}789} else {790result.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",791path.c_str(), append ? "append" : "write");792793result.AppendError(llvm::toString(outfile.takeError()));794return;795}796} else {797output_stream_p = &result.GetOutputStream();798}799800ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();801if (compiler_type.GetOpaqueQualType()) {802for (uint32_t i = 0; i < item_count; ++i) {803addr_t item_addr = addr + (i * item_byte_size);804Address address(item_addr);805StreamString name_strm;806name_strm.Printf("0x%" PRIx64, item_addr);807ValueObjectSP valobj_sp(ValueObjectMemory::Create(808exe_scope, name_strm.GetString(), address, compiler_type));809if (valobj_sp) {810Format format = m_format_options.GetFormat();811if (format != eFormatDefault)812valobj_sp->SetFormat(format);813814DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(815eLanguageRuntimeDescriptionDisplayVerbosityFull, format));816817if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) {818result.AppendError(toString(std::move(error)));819return;820}821} else {822result.AppendErrorWithFormat(823"failed to create a value object for: (%s) %s\n",824view_as_type_cstr, name_strm.GetData());825return;826}827}828return;829}830831result.SetStatus(eReturnStatusSuccessFinishResult);832DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),833target->GetArchitecture().GetAddressByteSize(),834target->GetArchitecture().GetDataByteSize());835836Format format = m_format_options.GetFormat();837if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&838(item_byte_size != 1)) {839// if a count was not passed, or it is 1840if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {841// this turns requests such as842// memory read -fc -s10 -c1 *charPtrPtr843// which make no sense (what is a char of size 10?) into a request for844// fetching 10 chars of size 1 from the same memory location845format = eFormatCharArray;846item_count = item_byte_size;847item_byte_size = 1;848} else {849// here we passed a count, and it was not 1 so we have a byte_size and850// a count we could well multiply those, but instead let's just fail851result.AppendErrorWithFormat(852"reading memory as characters of size %" PRIu64 " is not supported",853(uint64_t)item_byte_size);854return;855}856}857858assert(output_stream_p);859size_t bytes_dumped = DumpDataExtractor(860data, output_stream_p, 0, format, item_byte_size, item_count,861num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,862exe_scope, m_memory_tag_options.GetShowTags().GetCurrentValue());863m_next_addr = addr + bytes_dumped;864output_stream_p->EOL();865}866867OptionGroupOptions m_option_group;868OptionGroupFormat m_format_options;869OptionGroupReadMemory m_memory_options;870OptionGroupOutputFile m_outfile_options;871OptionGroupValueObjectDisplay m_varobj_options;872OptionGroupMemoryTag m_memory_tag_options;873lldb::addr_t m_next_addr = LLDB_INVALID_ADDRESS;874lldb::addr_t m_prev_byte_size = 0;875OptionGroupFormat m_prev_format_options;876OptionGroupReadMemory m_prev_memory_options;877OptionGroupOutputFile m_prev_outfile_options;878OptionGroupValueObjectDisplay m_prev_varobj_options;879OptionGroupMemoryTag m_prev_memory_tag_options;880CompilerType m_prev_compiler_type;881};882883#define LLDB_OPTIONS_memory_find884#include "CommandOptions.inc"885886// Find the specified data in memory887class CommandObjectMemoryFind : public CommandObjectParsed {888public:889class OptionGroupFindMemory : public OptionGroup {890public:891OptionGroupFindMemory() : m_count(1), m_offset(0) {}892893~OptionGroupFindMemory() override = default;894895llvm::ArrayRef<OptionDefinition> GetDefinitions() override {896return llvm::ArrayRef(g_memory_find_options);897}898899Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,900ExecutionContext *execution_context) override {901Status error;902const int short_option = g_memory_find_options[option_idx].short_option;903904switch (short_option) {905case 'e':906m_expr.SetValueFromString(option_value);907break;908909case 's':910m_string.SetValueFromString(option_value);911break;912913case 'c':914if (m_count.SetValueFromString(option_value).Fail())915error.SetErrorString("unrecognized value for count");916break;917918case 'o':919if (m_offset.SetValueFromString(option_value).Fail())920error.SetErrorString("unrecognized value for dump-offset");921break;922923default:924llvm_unreachable("Unimplemented option");925}926return error;927}928929void OptionParsingStarting(ExecutionContext *execution_context) override {930m_expr.Clear();931m_string.Clear();932m_count.Clear();933}934935OptionValueString m_expr;936OptionValueString m_string;937OptionValueUInt64 m_count;938OptionValueUInt64 m_offset;939};940941CommandObjectMemoryFind(CommandInterpreter &interpreter)942: CommandObjectParsed(943interpreter, "memory find",944"Find a value in the memory of the current target process.",945nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched) {946CommandArgumentEntry arg1;947CommandArgumentEntry arg2;948CommandArgumentData addr_arg;949CommandArgumentData value_arg;950951// Define the first (and only) variant of this arg.952addr_arg.arg_type = eArgTypeAddressOrExpression;953addr_arg.arg_repetition = eArgRepeatPlain;954955// There is only one variant this argument could be; put it into the956// argument entry.957arg1.push_back(addr_arg);958959// Define the first (and only) variant of this arg.960value_arg.arg_type = eArgTypeAddressOrExpression;961value_arg.arg_repetition = eArgRepeatPlain;962963// There is only one variant this argument could be; put it into the964// argument entry.965arg2.push_back(value_arg);966967// Push the data for the first argument into the m_arguments vector.968m_arguments.push_back(arg1);969m_arguments.push_back(arg2);970971m_option_group.Append(&m_memory_options);972m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,973LLDB_OPT_SET_ALL);974m_option_group.Finalize();975}976977~CommandObjectMemoryFind() override = default;978979Options *GetOptions() override { return &m_option_group; }980981protected:982void DoExecute(Args &command, CommandReturnObject &result) override {983// No need to check "process" for validity as eCommandRequiresProcess984// ensures it is valid985Process *process = m_exe_ctx.GetProcessPtr();986987const size_t argc = command.GetArgumentCount();988989if (argc != 2) {990result.AppendError("two addresses needed for memory find");991return;992}993994Status error;995lldb::addr_t low_addr = OptionArgParser::ToAddress(996&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);997if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {998result.AppendError("invalid low address");999return;1000}1001lldb::addr_t high_addr = OptionArgParser::ToAddress(1002&m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, &error);1003if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {1004result.AppendError("invalid high address");1005return;1006}10071008if (high_addr <= low_addr) {1009result.AppendError(1010"starting address must be smaller than ending address");1011return;1012}10131014lldb::addr_t found_location = LLDB_INVALID_ADDRESS;10151016DataBufferHeap buffer;10171018if (m_memory_options.m_string.OptionWasSet()) {1019llvm::StringRef str =1020m_memory_options.m_string.GetValueAs<llvm::StringRef>().value_or("");1021if (str.empty()) {1022result.AppendError("search string must have non-zero length.");1023return;1024}1025buffer.CopyData(str);1026} else if (m_memory_options.m_expr.OptionWasSet()) {1027StackFrame *frame = m_exe_ctx.GetFramePtr();1028ValueObjectSP result_sp;1029if ((eExpressionCompleted ==1030process->GetTarget().EvaluateExpression(1031m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(1032""),1033frame, result_sp)) &&1034result_sp) {1035uint64_t value = result_sp->GetValueAsUnsigned(0);1036std::optional<uint64_t> size =1037result_sp->GetCompilerType().GetByteSize(nullptr);1038if (!size)1039return;1040switch (*size) {1041case 1: {1042uint8_t byte = (uint8_t)value;1043buffer.CopyData(&byte, 1);1044} break;1045case 2: {1046uint16_t word = (uint16_t)value;1047buffer.CopyData(&word, 2);1048} break;1049case 4: {1050uint32_t lword = (uint32_t)value;1051buffer.CopyData(&lword, 4);1052} break;1053case 8: {1054buffer.CopyData(&value, 8);1055} break;1056case 3:1057case 5:1058case 6:1059case 7:1060result.AppendError("unknown type. pass a string instead");1061return;1062default:1063result.AppendError(1064"result size larger than 8 bytes. pass a string instead");1065return;1066}1067} else {1068result.AppendError(1069"expression evaluation failed. pass a string instead");1070return;1071}1072} else {1073result.AppendError(1074"please pass either a block of text, or an expression to evaluate.");1075return;1076}10771078size_t count = m_memory_options.m_count.GetCurrentValue();1079found_location = low_addr;1080bool ever_found = false;1081while (count) {1082found_location = process->FindInMemory(1083found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());1084if (found_location == LLDB_INVALID_ADDRESS) {1085if (!ever_found) {1086result.AppendMessage("data not found within the range.\n");1087result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);1088} else1089result.AppendMessage("no more matches within the range.\n");1090break;1091}1092result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",1093found_location);10941095DataBufferHeap dumpbuffer(32, 0);1096process->ReadMemory(1097found_location + m_memory_options.m_offset.GetCurrentValue(),1098dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);1099if (!error.Fail()) {1100DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),1101process->GetByteOrder(),1102process->GetAddressByteSize());1103DumpDataExtractor(1104data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,1105dumpbuffer.GetByteSize(), 16,1106found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0,1107m_exe_ctx.GetBestExecutionContextScope(),1108m_memory_tag_options.GetShowTags().GetCurrentValue());1109result.GetOutputStream().EOL();1110}11111112--count;1113found_location++;1114ever_found = true;1115}11161117result.SetStatus(lldb::eReturnStatusSuccessFinishResult);1118}11191120OptionGroupOptions m_option_group;1121OptionGroupFindMemory m_memory_options;1122OptionGroupMemoryTag m_memory_tag_options;1123};11241125#define LLDB_OPTIONS_memory_write1126#include "CommandOptions.inc"11271128// Write memory to the inferior process1129class CommandObjectMemoryWrite : public CommandObjectParsed {1130public:1131class OptionGroupWriteMemory : public OptionGroup {1132public:1133OptionGroupWriteMemory() = default;11341135~OptionGroupWriteMemory() override = default;11361137llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1138return llvm::ArrayRef(g_memory_write_options);1139}11401141Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,1142ExecutionContext *execution_context) override {1143Status error;1144const int short_option = g_memory_write_options[option_idx].short_option;11451146switch (short_option) {1147case 'i':1148m_infile.SetFile(option_value, FileSpec::Style::native);1149FileSystem::Instance().Resolve(m_infile);1150if (!FileSystem::Instance().Exists(m_infile)) {1151m_infile.Clear();1152error.SetErrorStringWithFormat("input file does not exist: '%s'",1153option_value.str().c_str());1154}1155break;11561157case 'o': {1158if (option_value.getAsInteger(0, m_infile_offset)) {1159m_infile_offset = 0;1160error.SetErrorStringWithFormat("invalid offset string '%s'",1161option_value.str().c_str());1162}1163} break;11641165default:1166llvm_unreachable("Unimplemented option");1167}1168return error;1169}11701171void OptionParsingStarting(ExecutionContext *execution_context) override {1172m_infile.Clear();1173m_infile_offset = 0;1174}11751176FileSpec m_infile;1177off_t m_infile_offset;1178};11791180CommandObjectMemoryWrite(CommandInterpreter &interpreter)1181: CommandObjectParsed(1182interpreter, "memory write",1183"Write to the memory of the current target process.", nullptr,1184eCommandRequiresProcess | eCommandProcessMustBeLaunched),1185m_format_options(1186eFormatBytes, 1, UINT64_MAX,1187{std::make_tuple(1188eArgTypeFormat,1189"The format to use for each of the value to be written."),1190std::make_tuple(eArgTypeByteSize,1191"The size in bytes to write from input file or "1192"each value.")}) {1193CommandArgumentEntry arg1;1194CommandArgumentEntry arg2;1195CommandArgumentData addr_arg;1196CommandArgumentData value_arg;11971198// Define the first (and only) variant of this arg.1199addr_arg.arg_type = eArgTypeAddress;1200addr_arg.arg_repetition = eArgRepeatPlain;12011202// There is only one variant this argument could be; put it into the1203// argument entry.1204arg1.push_back(addr_arg);12051206// Define the first (and only) variant of this arg.1207value_arg.arg_type = eArgTypeValue;1208value_arg.arg_repetition = eArgRepeatPlus;1209value_arg.arg_opt_set_association = LLDB_OPT_SET_1;12101211// There is only one variant this argument could be; put it into the1212// argument entry.1213arg2.push_back(value_arg);12141215// Push the data for the first argument into the m_arguments vector.1216m_arguments.push_back(arg1);1217m_arguments.push_back(arg2);12181219m_option_group.Append(&m_format_options,1220OptionGroupFormat::OPTION_GROUP_FORMAT,1221LLDB_OPT_SET_1);1222m_option_group.Append(&m_format_options,1223OptionGroupFormat::OPTION_GROUP_SIZE,1224LLDB_OPT_SET_1 | LLDB_OPT_SET_2);1225m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);1226m_option_group.Finalize();1227}12281229~CommandObjectMemoryWrite() override = default;12301231Options *GetOptions() override { return &m_option_group; }12321233protected:1234void DoExecute(Args &command, CommandReturnObject &result) override {1235// No need to check "process" for validity as eCommandRequiresProcess1236// ensures it is valid1237Process *process = m_exe_ctx.GetProcessPtr();12381239const size_t argc = command.GetArgumentCount();12401241if (m_memory_options.m_infile) {1242if (argc < 1) {1243result.AppendErrorWithFormat(1244"%s takes a destination address when writing file contents.\n",1245m_cmd_name.c_str());1246return;1247}1248if (argc > 1) {1249result.AppendErrorWithFormat(1250"%s takes only a destination address when writing file contents.\n",1251m_cmd_name.c_str());1252return;1253}1254} else if (argc < 2) {1255result.AppendErrorWithFormat(1256"%s takes a destination address and at least one value.\n",1257m_cmd_name.c_str());1258return;1259}12601261StreamString buffer(1262Stream::eBinary,1263process->GetTarget().GetArchitecture().GetAddressByteSize(),1264process->GetTarget().GetArchitecture().GetByteOrder());12651266OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();1267size_t item_byte_size = byte_size_value.GetCurrentValue();12681269Status error;1270lldb::addr_t addr = OptionArgParser::ToAddress(1271&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);12721273if (addr == LLDB_INVALID_ADDRESS) {1274result.AppendError("invalid address expression\n");1275result.AppendError(error.AsCString());1276return;1277}12781279if (m_memory_options.m_infile) {1280size_t length = SIZE_MAX;1281if (item_byte_size > 1)1282length = item_byte_size;1283auto data_sp = FileSystem::Instance().CreateDataBuffer(1284m_memory_options.m_infile.GetPath(), length,1285m_memory_options.m_infile_offset);1286if (data_sp) {1287length = data_sp->GetByteSize();1288if (length > 0) {1289Status error;1290size_t bytes_written =1291process->WriteMemory(addr, data_sp->GetBytes(), length, error);12921293if (bytes_written == length) {1294// All bytes written1295result.GetOutputStream().Printf(1296"%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",1297(uint64_t)bytes_written, addr);1298result.SetStatus(eReturnStatusSuccessFinishResult);1299} else if (bytes_written > 0) {1300// Some byte written1301result.GetOutputStream().Printf(1302"%" PRIu64 " bytes of %" PRIu641303" requested were written to 0x%" PRIx64 "\n",1304(uint64_t)bytes_written, (uint64_t)length, addr);1305result.SetStatus(eReturnStatusSuccessFinishResult);1306} else {1307result.AppendErrorWithFormat("Memory write to 0x%" PRIx641308" failed: %s.\n",1309addr, error.AsCString());1310}1311}1312} else {1313result.AppendErrorWithFormat("Unable to read contents of file.\n");1314}1315return;1316} else if (item_byte_size == 0) {1317if (m_format_options.GetFormat() == eFormatPointer)1318item_byte_size = buffer.GetAddressByteSize();1319else1320item_byte_size = 1;1321}13221323command.Shift(); // shift off the address argument1324uint64_t uval64;1325int64_t sval64;1326bool success = false;1327for (auto &entry : command) {1328switch (m_format_options.GetFormat()) {1329case kNumFormats:1330case eFormatFloat: // TODO: add support for floats soon1331case eFormatCharPrintable:1332case eFormatBytesWithASCII:1333case eFormatComplex:1334case eFormatEnum:1335case eFormatUnicode8:1336case eFormatUnicode16:1337case eFormatUnicode32:1338case eFormatVectorOfChar:1339case eFormatVectorOfSInt8:1340case eFormatVectorOfUInt8:1341case eFormatVectorOfSInt16:1342case eFormatVectorOfUInt16:1343case eFormatVectorOfSInt32:1344case eFormatVectorOfUInt32:1345case eFormatVectorOfSInt64:1346case eFormatVectorOfUInt64:1347case eFormatVectorOfFloat16:1348case eFormatVectorOfFloat32:1349case eFormatVectorOfFloat64:1350case eFormatVectorOfUInt128:1351case eFormatOSType:1352case eFormatComplexInteger:1353case eFormatAddressInfo:1354case eFormatHexFloat:1355case eFormatInstruction:1356case eFormatVoid:1357result.AppendError("unsupported format for writing memory");1358return;13591360case eFormatDefault:1361case eFormatBytes:1362case eFormatHex:1363case eFormatHexUppercase:1364case eFormatPointer: {1365// Decode hex bytes1366// Be careful, getAsInteger with a radix of 16 rejects "0xab" so we1367// have to special case that:1368bool success = false;1369if (entry.ref().starts_with("0x"))1370success = !entry.ref().getAsInteger(0, uval64);1371if (!success)1372success = !entry.ref().getAsInteger(16, uval64);1373if (!success) {1374result.AppendErrorWithFormat(1375"'%s' is not a valid hex string value.\n", entry.c_str());1376return;1377} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1378result.AppendErrorWithFormat("Value 0x%" PRIx641379" is too large to fit in a %" PRIu641380" byte unsigned integer value.\n",1381uval64, (uint64_t)item_byte_size);1382return;1383}1384buffer.PutMaxHex64(uval64, item_byte_size);1385break;1386}1387case eFormatBoolean:1388uval64 = OptionArgParser::ToBoolean(entry.ref(), false, &success);1389if (!success) {1390result.AppendErrorWithFormat(1391"'%s' is not a valid boolean string value.\n", entry.c_str());1392return;1393}1394buffer.PutMaxHex64(uval64, item_byte_size);1395break;13961397case eFormatBinary:1398if (entry.ref().getAsInteger(2, uval64)) {1399result.AppendErrorWithFormat(1400"'%s' is not a valid binary string value.\n", entry.c_str());1401return;1402} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1403result.AppendErrorWithFormat("Value 0x%" PRIx641404" is too large to fit in a %" PRIu641405" byte unsigned integer value.\n",1406uval64, (uint64_t)item_byte_size);1407return;1408}1409buffer.PutMaxHex64(uval64, item_byte_size);1410break;14111412case eFormatCharArray:1413case eFormatChar:1414case eFormatCString: {1415if (entry.ref().empty())1416break;14171418size_t len = entry.ref().size();1419// Include the NULL for C strings...1420if (m_format_options.GetFormat() == eFormatCString)1421++len;1422Status error;1423if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {1424addr += len;1425} else {1426result.AppendErrorWithFormat("Memory write to 0x%" PRIx641427" failed: %s.\n",1428addr, error.AsCString());1429return;1430}1431break;1432}1433case eFormatDecimal:1434if (entry.ref().getAsInteger(0, sval64)) {1435result.AppendErrorWithFormat(1436"'%s' is not a valid signed decimal value.\n", entry.c_str());1437return;1438} else if (!llvm::isIntN(item_byte_size * 8, sval64)) {1439result.AppendErrorWithFormat(1440"Value %" PRIi64 " is too large or small to fit in a %" PRIu641441" byte signed integer value.\n",1442sval64, (uint64_t)item_byte_size);1443return;1444}1445buffer.PutMaxHex64(sval64, item_byte_size);1446break;14471448case eFormatUnsigned:14491450if (entry.ref().getAsInteger(0, uval64)) {1451result.AppendErrorWithFormat(1452"'%s' is not a valid unsigned decimal string value.\n",1453entry.c_str());1454return;1455} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1456result.AppendErrorWithFormat("Value %" PRIu641457" is too large to fit in a %" PRIu641458" byte unsigned integer value.\n",1459uval64, (uint64_t)item_byte_size);1460return;1461}1462buffer.PutMaxHex64(uval64, item_byte_size);1463break;14641465case eFormatOctal:1466if (entry.ref().getAsInteger(8, uval64)) {1467result.AppendErrorWithFormat(1468"'%s' is not a valid octal string value.\n", entry.c_str());1469return;1470} else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {1471result.AppendErrorWithFormat("Value %" PRIo641472" is too large to fit in a %" PRIu641473" byte unsigned integer value.\n",1474uval64, (uint64_t)item_byte_size);1475return;1476}1477buffer.PutMaxHex64(uval64, item_byte_size);1478break;1479}1480}14811482if (!buffer.GetString().empty()) {1483Status error;1484const char *buffer_data = buffer.GetString().data();1485const size_t buffer_size = buffer.GetString().size();1486const size_t write_size =1487process->WriteMemory(addr, buffer_data, buffer_size, error);14881489if (write_size != buffer_size) {1490result.AppendErrorWithFormat("Memory write to 0x%" PRIx641491" failed: %s.\n",1492addr, error.AsCString());1493return;1494}1495}1496}14971498OptionGroupOptions m_option_group;1499OptionGroupFormat m_format_options;1500OptionGroupWriteMemory m_memory_options;1501};15021503// Get malloc/free history of a memory address.1504class CommandObjectMemoryHistory : public CommandObjectParsed {1505public:1506CommandObjectMemoryHistory(CommandInterpreter &interpreter)1507: CommandObjectParsed(interpreter, "memory history",1508"Print recorded stack traces for "1509"allocation/deallocation events "1510"associated with an address.",1511nullptr,1512eCommandRequiresTarget | eCommandRequiresProcess |1513eCommandProcessMustBePaused |1514eCommandProcessMustBeLaunched) {1515CommandArgumentEntry arg1;1516CommandArgumentData addr_arg;15171518// Define the first (and only) variant of this arg.1519addr_arg.arg_type = eArgTypeAddress;1520addr_arg.arg_repetition = eArgRepeatPlain;15211522// There is only one variant this argument could be; put it into the1523// argument entry.1524arg1.push_back(addr_arg);15251526// Push the data for the first argument into the m_arguments vector.1527m_arguments.push_back(arg1);1528}15291530~CommandObjectMemoryHistory() override = default;15311532std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,1533uint32_t index) override {1534return m_cmd_name;1535}15361537protected:1538void DoExecute(Args &command, CommandReturnObject &result) override {1539const size_t argc = command.GetArgumentCount();15401541if (argc == 0 || argc > 1) {1542result.AppendErrorWithFormat("%s takes an address expression",1543m_cmd_name.c_str());1544return;1545}15461547Status error;1548lldb::addr_t addr = OptionArgParser::ToAddress(1549&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);15501551if (addr == LLDB_INVALID_ADDRESS) {1552result.AppendError("invalid address expression");1553result.AppendError(error.AsCString());1554return;1555}15561557Stream *output_stream = &result.GetOutputStream();15581559const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();1560const MemoryHistorySP &memory_history =1561MemoryHistory::FindPlugin(process_sp);15621563if (!memory_history) {1564result.AppendError("no available memory history provider");1565return;1566}15671568HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);15691570const bool stop_format = false;1571for (auto thread : thread_list) {1572thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format);1573}15741575result.SetStatus(eReturnStatusSuccessFinishResult);1576}1577};15781579// CommandObjectMemoryRegion1580#pragma mark CommandObjectMemoryRegion15811582#define LLDB_OPTIONS_memory_region1583#include "CommandOptions.inc"15841585class CommandObjectMemoryRegion : public CommandObjectParsed {1586public:1587class OptionGroupMemoryRegion : public OptionGroup {1588public:1589OptionGroupMemoryRegion() : m_all(false, false) {}15901591~OptionGroupMemoryRegion() override = default;15921593llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1594return llvm::ArrayRef(g_memory_region_options);1595}15961597Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,1598ExecutionContext *execution_context) override {1599Status status;1600const int short_option = g_memory_region_options[option_idx].short_option;16011602switch (short_option) {1603case 'a':1604m_all.SetCurrentValue(true);1605m_all.SetOptionWasSet();1606break;1607default:1608llvm_unreachable("Unimplemented option");1609}16101611return status;1612}16131614void OptionParsingStarting(ExecutionContext *execution_context) override {1615m_all.Clear();1616}16171618OptionValueBoolean m_all;1619};16201621CommandObjectMemoryRegion(CommandInterpreter &interpreter)1622: CommandObjectParsed(interpreter, "memory region",1623"Get information on the memory region containing "1624"an address in the current target process.",1625"memory region <address-expression> (or --all)",1626eCommandRequiresProcess | eCommandTryTargetAPILock |1627eCommandProcessMustBeLaunched) {1628// Address in option set 1.1629m_arguments.push_back(CommandArgumentEntry{CommandArgumentData(1630eArgTypeAddressOrExpression, eArgRepeatPlain, LLDB_OPT_SET_1)});1631// "--all" will go in option set 2.1632m_option_group.Append(&m_memory_region_options);1633m_option_group.Finalize();1634}16351636~CommandObjectMemoryRegion() override = default;16371638Options *GetOptions() override { return &m_option_group; }16391640protected:1641void DumpRegion(CommandReturnObject &result, Target &target,1642const MemoryRegionInfo &range_info, lldb::addr_t load_addr) {1643lldb_private::Address addr;1644ConstString section_name;1645if (target.ResolveLoadAddress(load_addr, addr)) {1646SectionSP section_sp(addr.GetSection());1647if (section_sp) {1648// Got the top most section, not the deepest section1649while (section_sp->GetParent())1650section_sp = section_sp->GetParent();1651section_name = section_sp->GetName();1652}1653}16541655ConstString name = range_info.GetName();1656result.AppendMessageWithFormatv(1657"[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",1658range_info.GetRange().GetRangeBase(),1659range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),1660range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",1661name, section_name ? " " : "", section_name);1662MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged();1663if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)1664result.AppendMessage("memory tagging: enabled");16651666const std::optional<std::vector<addr_t>> &dirty_page_list =1667range_info.GetDirtyPageList();1668if (dirty_page_list) {1669const size_t page_count = dirty_page_list->size();1670result.AppendMessageWithFormat(1671"Modified memory (dirty) page list provided, %zu entries.\n",1672page_count);1673if (page_count > 0) {1674bool print_comma = false;1675result.AppendMessageWithFormat("Dirty pages: ");1676for (size_t i = 0; i < page_count; i++) {1677if (print_comma)1678result.AppendMessageWithFormat(", ");1679else1680print_comma = true;1681result.AppendMessageWithFormat("0x%" PRIx64, (*dirty_page_list)[i]);1682}1683result.AppendMessageWithFormat(".\n");1684}1685}1686}16871688void DoExecute(Args &command, CommandReturnObject &result) override {1689ProcessSP process_sp = m_exe_ctx.GetProcessSP();1690if (!process_sp) {1691m_prev_end_addr = LLDB_INVALID_ADDRESS;1692result.AppendError("invalid process");1693return;1694}16951696Status error;1697lldb::addr_t load_addr = m_prev_end_addr;1698m_prev_end_addr = LLDB_INVALID_ADDRESS;16991700const size_t argc = command.GetArgumentCount();1701const lldb::ABISP &abi = process_sp->GetABI();17021703if (argc == 1) {1704if (m_memory_region_options.m_all) {1705result.AppendError(1706"The \"--all\" option cannot be used when an address "1707"argument is given");1708return;1709}17101711auto load_addr_str = command[0].ref();1712load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,1713LLDB_INVALID_ADDRESS, &error);1714if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {1715result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n",1716command[0].c_str(), error.AsCString());1717return;1718}1719} else if (argc > 1 ||1720// When we're repeating the command, the previous end address is1721// used for load_addr. If that was 0xF...F then we must have1722// reached the end of memory.1723(argc == 0 && !m_memory_region_options.m_all &&1724load_addr == LLDB_INVALID_ADDRESS) ||1725// If the target has non-address bits (tags, limited virtual1726// address size, etc.), the end of mappable memory will be lower1727// than that. So if we find any non-address bit set, we must be1728// at the end of the mappable range.1729(abi && (abi->FixAnyAddress(load_addr) != load_addr))) {1730result.AppendErrorWithFormat(1731"'%s' takes one argument or \"--all\" option:\nUsage: %s\n",1732m_cmd_name.c_str(), m_cmd_syntax.c_str());1733return;1734}17351736// It is important that we track the address used to request the region as1737// this will give the correct section name in the case that regions overlap.1738// On Windows we get mutliple regions that start at the same place but are1739// different sizes and refer to different sections.1740std::vector<std::pair<lldb_private::MemoryRegionInfo, lldb::addr_t>>1741region_list;1742if (m_memory_region_options.m_all) {1743// We don't use GetMemoryRegions here because it doesn't include unmapped1744// areas like repeating the command would. So instead, emulate doing that.1745lldb::addr_t addr = 0;1746while (error.Success() && addr != LLDB_INVALID_ADDRESS &&1747// When there are non-address bits the last range will not extend1748// to LLDB_INVALID_ADDRESS but to the max virtual address.1749// This prevents us looping forever if that is the case.1750(!abi || (abi->FixAnyAddress(addr) == addr))) {1751lldb_private::MemoryRegionInfo region_info;1752error = process_sp->GetMemoryRegionInfo(addr, region_info);17531754if (error.Success()) {1755region_list.push_back({region_info, addr});1756addr = region_info.GetRange().GetRangeEnd();1757}1758}1759} else {1760lldb_private::MemoryRegionInfo region_info;1761error = process_sp->GetMemoryRegionInfo(load_addr, region_info);1762if (error.Success())1763region_list.push_back({region_info, load_addr});1764}17651766if (error.Success()) {1767for (std::pair<MemoryRegionInfo, addr_t> &range : region_list) {1768DumpRegion(result, process_sp->GetTarget(), range.first, range.second);1769m_prev_end_addr = range.first.GetRange().GetRangeEnd();1770}17711772result.SetStatus(eReturnStatusSuccessFinishResult);1773return;1774}17751776result.AppendErrorWithFormat("%s\n", error.AsCString());1777}17781779std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,1780uint32_t index) override {1781// If we repeat this command, repeat it without any arguments so we can1782// show the next memory range1783return m_cmd_name;1784}17851786lldb::addr_t m_prev_end_addr = LLDB_INVALID_ADDRESS;17871788OptionGroupOptions m_option_group;1789OptionGroupMemoryRegion m_memory_region_options;1790};17911792// CommandObjectMemory17931794CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)1795: CommandObjectMultiword(1796interpreter, "memory",1797"Commands for operating on memory in the current target process.",1798"memory <subcommand> [<subcommand-options>]") {1799LoadSubCommand("find",1800CommandObjectSP(new CommandObjectMemoryFind(interpreter)));1801LoadSubCommand("read",1802CommandObjectSP(new CommandObjectMemoryRead(interpreter)));1803LoadSubCommand("write",1804CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));1805LoadSubCommand("history",1806CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));1807LoadSubCommand("region",1808CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));1809LoadSubCommand("tag",1810CommandObjectSP(new CommandObjectMemoryTag(interpreter)));1811}18121813CommandObjectMemory::~CommandObjectMemory() = default;181418151816