blob: e43946ad4dc566b9ab8aaf71dda73db1bdbbe217 [file] [log] [blame]
// Copyright 2016 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 <ctype.h>
#include <inttypes.h>
#include <lib/zircon-internal/align.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <pretty/hexdump.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
void hexdump_stdio_printf(void* printf_arg, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(static_cast<FILE*>(printf_arg), fmt, args);
va_end(args);
}
// In the kernel, these are used in panic and debugging paths where the
// buffers passed might be suspect and it would be worse to get a sanitizer
// fault reading them than to display some garbage. The other functions
// here (and their callees) have normal instrumentation since they don't
// derference pointers into the suspect buffer.
#if defined(__clang__) && _KERNEL
#define MAYBE_NO_ASAN [[clang::no_sanitize("address")]]
#else
#define MAYBE_NO_ASAN
#endif
MAYBE_NO_ASAN
void hexdump_very_ex(const void* ptr, size_t len, uint64_t disp_addr,
hexdump_printf_func_t* printf_func, void* printf_arg) {
uintptr_t address = (uintptr_t)ptr;
size_t count;
for (count = 0; count < len; count += 16) {
union {
uint32_t buf[4];
uint8_t cbuf[16];
} u;
size_t s = ZX_ROUNDUP(MIN(len - count, 16), 4);
size_t i;
printf_func(printf_arg,
((disp_addr + len) > 0xFFFFFFFF ? "0x%016" PRIx64 ": " : "0x%08" PRIx64 ": "),
disp_addr + count);
for (i = 0; i < s / 4; i++) {
u.buf[i] = ((const uint32_t*)address)[i];
printf_func(printf_arg, "%08x ", static_cast<unsigned int>(u.buf[i]));
}
for (; i < 4; i++) {
printf_func(printf_arg, " ");
}
printf_func(printf_arg, "|");
for (i = 0; i < 16; i++) {
char c = u.cbuf[i];
if (i < s && isprint(c)) {
printf_func(printf_arg, "%c", c);
} else {
printf_func(printf_arg, ".");
}
}
printf_func(printf_arg, "|\n");
address += 16;
}
}
MAYBE_NO_ASAN
void hexdump8_very_ex(const void* ptr, size_t len, uint64_t disp_addr,
hexdump_printf_func_t* printf_func, void* printf_arg) {
uintptr_t address = (uintptr_t)ptr;
size_t count;
size_t i;
for (count = 0; count < len; count += 16) {
printf_func(printf_arg,
((disp_addr + len) > 0xFFFFFFFF ? "0x%016" PRIx64 ": " : "0x%08" PRIx64 ": "),
disp_addr + count);
for (i = 0; i < MIN(len - count, 16); i++) {
printf_func(printf_arg, "%02hhx ", *(const uint8_t*)(address + i));
}
for (; i < 16; i++) {
printf_func(printf_arg, " ");
}
printf_func(printf_arg, "|");
for (i = 0; i < MIN(len - count, 16); i++) {
char c = ((const char*)address)[i];
printf_func(printf_arg, "%c", isprint(c) ? c : '.');
}
printf_func(printf_arg, "\n");
address += 16;
}
}
void hexdump_ex(const void* ptr, size_t len, uint64_t disp_addr) {
hexdump_very_ex(ptr, len, disp_addr, hexdump_stdio_printf, stdout);
}
void hexdump8_ex(const void* ptr, size_t len, uint64_t disp_addr) {
hexdump8_very_ex(ptr, len, disp_addr, hexdump_stdio_printf, stdout);
}