blob: 0c9fb124e37f01f0c4ba859c036f0c1f497e4f7b [file] [log] [blame]
// Copyright 2018 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 "garnet/bin/zxdb/console/format_memory.h"
#include <inttypes.h>
#include <limits>
#include "garnet/bin/zxdb/client/memory_dump.h"
#include "garnet/public/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
const char kUnknownByte[] = "??";
const char kNonAscii =
' '; // When printing ASCII and the character is not in range.
bool IsPrintableAscii(uint8_t c) { return c >= ' ' && c < 0x7f; }
} // namespace
// Optimized for simplicity over speed. But this does not use the table output
// to avoid having giant table computations for large memory dumps.
std::string FormatMemory(const MemoryDump& dump, uint64_t begin, uint32_t size,
const MemoryFormatOptions& opts) {
std::string out;
// Compute the last address we'll print. Watch for overflow.
uint64_t max_addr = std::numeric_limits<uint64_t>::max();
if (max_addr - size > begin)
max_addr = begin + size - 1;
// Max address character width.
int addr_width = 0;
if (opts.show_addrs) {
addr_width =
static_cast<int>(fxl::StringPrintf("%" PRIx64, max_addr).size());
}
uint64_t cur = begin; // Current address being printed.
std::string line; // These string buffers are outside the loop to prevent
// reallocation.
std::string address;
std::string values;
std::string ascii;
bool done = false;
while (!done) { // Line loop
// Compute address at beginning of line.
if (opts.show_addrs) {
address = fxl::StringPrintf("0x%0*" PRIx64, addr_width, cur);
address.append(": ");
}
values.clear();
ascii.clear();
for (int i = 0; i < opts.values_per_line; i++) { // Value loop.
// Separator between values.
if (i > 0) {
if (!done && opts.separator_every > 0 &&
(i % opts.separator_every) == 0) {
values.push_back('-');
} else {
values.push_back(' ');
}
}
if (!done) {
uint8_t byte;
if (dump.GetByte(cur, &byte)) {
values += fxl::StringPrintf("%02x", static_cast<int>(byte));
if (IsPrintableAscii(byte)) {
ascii.push_back(static_cast<char>(byte));
} else {
ascii.push_back(kNonAscii);
}
} else {
values.append(kUnknownByte);
ascii.push_back(kNonAscii);
}
// Carefully only increment address if it won't overflow.
if (cur == max_addr) {
done = true;
} else {
cur++;
}
} else {
// Line is done, but we still want padding for values.
values.append(" ");
ascii.push_back(' ');
}
}
// Append the constructed elements.
out.append(address); // Will be empty if not showing.
out.append(values);
if (opts.show_ascii) {
out.append(" |");
out.append(ascii);
}
out.push_back('\n');
address.clear();
values.clear();
}
return out;
}
} // namespace zxdb