blob: 38c9d24cd24a7c466bbfb6dc8c1b4e62c7f0ad70 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/console/commands/verb_mem_read.h"
#include "src/developer/debug/zxdb/client/memory_dump.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/target.h"
#include "src/developer/debug/zxdb/console/command.h"
#include "src/developer/debug/zxdb/console/command_utils.h"
#include "src/developer/debug/zxdb/console/console.h"
#include "src/developer/debug/zxdb/console/format_memory.h"
#include "src/developer/debug/zxdb/console/input_location_parser.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
namespace zxdb {
namespace {
constexpr int kSizeSwitch = 1;
void MemoryReadComplete(const Err& err, MemoryDump dump) {
OutputBuffer out;
if (err.has_error()) {
out.Append(err);
} else {
MemoryFormatOptions opts;
opts.address_mode = MemoryFormatOptions::kAddresses;
opts.show_ascii = true;
opts.values_per_line = 16;
opts.separator_every = 8;
out.Append(FormatMemory(dump, dump.address(), static_cast<uint32_t>(dump.size()), opts));
}
Console::get()->Output(out);
}
const char kMemReadShortHelp[] = R"(mem-read / x: Read memory from debugged process.)";
const char kMemReadHelp[] =
R"(mem-read [ --size=<bytes> ] <address-expression>
Alias: "x"
Reads memory from the process at the given address and prints it to the
screen. Currently, only a byte-oriented hex dump format is supported.
The address can be an explicit number or any expression ("help expressions")
that evaluates to a memory address.
When no size is given, the size will be the object size if a typed expression
is given, otherwise 20 lines will be output.
See also the "mem-analyze" command to print a memory analysis and the "stack"
command to print a more useful dump of the raw stack.
Arguments
--size=<bytes> | -s <bytes>
Bytes to read. This defaults to the size of the function if a function
name is given as the location, or 64 otherwise.
Examples
x --size=128 0x75f19ba
x &foo->bar
mem-read --size=16 0x8f1763a7
process 3 mem-read 83242384560
)";
Err RunVerbMemRead(ConsoleContext* context, const Command& cmd) {
// Only a process can have its memory read.
if (Err err = cmd.ValidateNouns({Noun::kProcess}); err.has_error())
return err;
// Size argument (optional).
std::optional<uint64_t> input_size;
if (cmd.HasSwitch(kSizeSwitch)) {
uint64_t read_size = 0;
if (Err err = StringToUint64(cmd.GetSwitchValue(kSizeSwitch), &read_size); err.has_error())
return err;
input_size = read_size;
}
return EvalCommandAddressExpression(
cmd, "mem-read", GetEvalContextForCommand(cmd),
[weak_target = cmd.target()->GetWeakPtr(), input_size](const Err& err, uint64_t address,
std::optional<uint64_t> object_size) {
Console* console = Console::get();
if (err.has_error()) {
console->Output(err); // Evaluation error.
return;
}
if (!weak_target) {
// Target has been destroyed during evaluation. Normally a message will be printed when
// that happens so we can skip reporting the error.
return;
}
Err run_err = AssertRunningTarget(&console->context(), "mem-read", weak_target.get());
if (run_err.has_error()) {
console->Output(run_err);
return;
}
uint64_t read_size;
if (input_size)
read_size = *input_size;
else if (object_size)
read_size = *object_size;
else
read_size = 64;
weak_target->GetProcess()->ReadMemory(address, read_size, &MemoryReadComplete);
});
return Err();
}
} // namespace
VerbRecord GetMemReadVerbRecord() {
// Mem-read. Note: "x" is the GDB command to read memory.
VerbRecord mem_read(&RunVerbMemRead, &CompleteInputLocation, {"mem-read", "x"}, kMemReadShortHelp,
kMemReadHelp, CommandGroup::kQuery);
mem_read.switches.emplace_back(kSizeSwitch, true, "size", 's');
mem_read.param_type = VerbRecord::kOneParam;
return mem_read;
}
} // namespace zxdb