authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2023-08-03 09:02:24+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-08 00:13:06-07:00
logdfc4d618dd31c00e339344962a839db5208ade8f
tree961ec373c4685a246cf746c9babc965dfe3a6dbe
parentf5978181e41e272b5c272440b9c543ead0357e2e

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.

1 files changed, 57 insertions(+), 0 deletions(-)

lib/std/debug.zig+57
......@@ -104,6 +104,63 @@ pub fn getSelfDebugInfo() !*DebugInfo {
104104 }
105105}
106106
107/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
108pub fn hexdump(bytes: []const u8) void {
109 hexdump_internal(bytes) catch {};
110}
111
112fn hexdump_internal(bytes: []const u8) !void {
113 const stderr = std.io.getStdErr();
114 const ttyconf = std.io.tty.detectConfig(stderr);
115 const writer = stderr.writer();
116 var chunks = mem.window(u8, bytes, 16, 16);
117 while (chunks.next()) |window| {
118 // 1. Print the address.
119 const address = (@intFromPtr(bytes.ptr) + 0x10 * (chunks.index orelse 0) / 16) - 0x10;
120 try ttyconf.setColor(writer, .dim);
121 // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
122 // Also, make sure all lines are aligned by padding the address.
123 try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
124 try ttyconf.setColor(writer, .reset);
125
126 // 2. Print the bytes.
127 for (window, 0..) |byte, index| {
128 try writer.print("{X:0>2} ", .{byte});
129 if (index == 7) try writer.writeByte(' ');
130 }
131 try writer.writeByte(' ');
132 if (window.len < 16) {
133 var missing_columns = (16 - window.len) * 3;
134 if (window.len < 8) missing_columns += 1;
135 try writer.writeByteNTimes(' ', missing_columns);
136 }
137
138 // 3. Print the characters.
139 for (window) |byte| {
140 if (std.ascii.isPrint(byte)) {
141 try writer.writeByte(byte);
142 } else {
143 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
144 if (ttyconf == .windows_api) {
145 try writer.writeByte('.');
146 continue;
147 }
148
149 // Let's print some common control codes as graphical Unicode symbols.
150 // We don't want to do this for all control codes because most control codes apart from
151 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.
152 switch (byte) {
153 '\n' => try writer.writeAll("␊"),
154 '\r' => try writer.writeAll("␍"),
155 '\t' => try writer.writeAll("␉"),
156 else => try writer.writeByte('.'),
157 }
158 }
159 }
160 try writer.writeByte('\n');
161 }
162}
163
107164/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
108165/// TODO multithreaded awareness
109166pub fn dumpCurrentStackTrace(start_addr: ?usize) void {