aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authorWooster <wooster0@proton.me>2023-08-03 09:02:24 +0200
committerAndrew Kelley <andrew@ziglang.org>2024-01-08 00:13:06 -0700
commitdfc4d618dd31c00e339344962a839db5208ade8f (patch)
tree961ec373c4685a246cf746c9babc965dfe3a6dbe /lib/std/debug.zig
parentf5978181e41e272b5c272440b9c543ead0357e2e (diff)
downloadzig-dfc4d618dd31c00e339344962a839db5208ade8f.tar.gz
zig-dfc4d618dd31c00e339344962a839db5208ade8f.zip
general-use std.debug.hexdump for printing hexdumps
Recently, when I've been working with structures of data that is not directly in RAM but rather laid out in bytes somewhere else, it was always very useful to print out maybe the next 50 bytes or the previous 50 bytes or so to see what's ahead or before me. I would usually do this with a quick `std.debug.print("{any}\n", .{bytes});` or something but the output is not as nice obviously.
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig57
1 files changed, 57 insertions, 0 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 179e821da2..4d7c7ed9a3 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -104,6 +104,63 @@ pub fn getSelfDebugInfo() !*DebugInfo {
}
}
+/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
+pub fn hexdump(bytes: []const u8) void {
+ hexdump_internal(bytes) catch {};
+}
+
+fn hexdump_internal(bytes: []const u8) !void {
+ const stderr = std.io.getStdErr();
+ const ttyconf = std.io.tty.detectConfig(stderr);
+ const writer = stderr.writer();
+ var chunks = mem.window(u8, bytes, 16, 16);
+ while (chunks.next()) |window| {
+ // 1. Print the address.
+ const address = (@intFromPtr(bytes.ptr) + 0x10 * (chunks.index orelse 0) / 16) - 0x10;
+ try ttyconf.setColor(writer, .dim);
+ // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
+ // Also, make sure all lines are aligned by padding the address.
+ try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
+ try ttyconf.setColor(writer, .reset);
+
+ // 2. Print the bytes.
+ for (window, 0..) |byte, index| {
+ try writer.print("{X:0>2} ", .{byte});
+ if (index == 7) try writer.writeByte(' ');
+ }
+ try writer.writeByte(' ');
+ if (window.len < 16) {
+ var missing_columns = (16 - window.len) * 3;
+ if (window.len < 8) missing_columns += 1;
+ try writer.writeByteNTimes(' ', missing_columns);
+ }
+
+ // 3. Print the characters.
+ for (window) |byte| {
+ if (std.ascii.isPrint(byte)) {
+ try writer.writeByte(byte);
+ } else {
+ // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
+ if (ttyconf == .windows_api) {
+ try writer.writeByte('.');
+ continue;
+ }
+
+ // Let's print some common control codes as graphical Unicode symbols.
+ // We don't want to do this for all control codes because most control codes apart from
+ // the ones that Zig has escape sequences for are likely not very useful to print as symbols.
+ switch (byte) {
+ '\n' => try writer.writeAll("␊"),
+ '\r' => try writer.writeAll("␍"),
+ '\t' => try writer.writeAll("␉"),
+ else => try writer.writeByte('.'),
+ }
+ }
+ }
+ try writer.writeByte('\n');
+ }
+}
+
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {