diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-01-08 16:25:15 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-08 16:25:15 -0800 |
| commit | deed19496a98a22ed39025721d448ce2f47642ea (patch) | |
| tree | 6c42e2d891058c8f0cc5896c8738d8c6d8a85bbc /lib/std/debug.zig | |
| parent | 4cf08932b51ab433933f5b3059d0cab90acc9696 (diff) | |
| parent | 25d2e7fce04d5cbe63331cc56ab7bafe89c249c4 (diff) | |
| download | zig-deed19496a98a22ed39025721d448ce2f47642ea.tar.gz zig-deed19496a98a22ed39025721d448ce2f47642ea.zip | |
Merge pull request #16650 from wooster0/hexdump
general-use std.debug.hexdump for printing hexdumps
Diffstat (limited to 'lib/std/debug.zig')
| -rw-r--r-- | lib/std/debug.zig | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 179e821da2..4670c49dfa 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -104,6 +104,67 @@ pub fn getSelfDebugInfo() !*DebugInfo { } } +/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. +/// Obtains the stderr mutex while dumping. +pub fn dump_hex(bytes: []const u8) void { + stderr_mutex.lock(); + defer stderr_mutex.unlock(); + dump_hex_fallible(bytes) catch {}; +} + +/// Prints a hexadecimal view of the bytes, unbuffered, returning any error that occurs. +pub fn dump_hex_fallible(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 { + // Related: https://github.com/ziglang/zig/issues/7600 + 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 { @@ -2774,3 +2835,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize } }; } + +test { + _ = &dump_hex; +} |
