diff options
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/debug.zig | 57 |
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 { |
