brintos

brintos / llvm-project-archived public Read only

0
0
Text · 64.5 KiB · 5786e75 Raw
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 &current_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 &current_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 &current_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