How to print caller's file&line number at runtime?

For debugging purposes, I want to write a function that returns file&line information for the call-site. I know about @src(), and I use it elsewhere, but for this use-case I’d rather avoid that. Instead, what want to do is to essentially the same thing as stack-trace printing does — lookup the return address on the stack, then lookup that address in the debug info, and extract file&line info based on that.

I know that std has code for doing that, as that’s exactly what happens in std.debug.dumpCurrentStackTrace(). Is there some convenience function I should call here? Or should I just copy-paste parts of the implementation of dumpCurrentStackTrace()?

In case this is X/Y — I want implement rust’s dbg! for Zig. Zig doesn’t have macros, but I think debug info contains everything I need for this too work, but I also want to write as little of my own code as possible :slight_smile:

There is: std.debug.printSourceAtAddress that prints filename, line number, and the source code line if it is available.
Example:

❯ cat test.zig
const std = @import("std");

pub fn main() !void {
    const info = try std.debug.getSelfDebugInfo();
    const addr = @returnAddress();
    const out = std.io.getStdErr();
    const tty = std.io.tty.detectConfig(out);
    try std.debug.printSourceAtAddress(info, out.writer(), addr, tty);
}

❯ zig run test.zig
/home/din/zig/0.13.0/lib/std/start.zig:524:37: 0x1034b36 in posixCallMainAndExit (test)
            const result = root.main() catch |err| {
                                    ^

5 Likes

Reminded me my recent “who called me” problem inside some utility function (C).
I kinda solved it (but not in its entirety as you wish) in this way:

On the callee side I had

int vt_size(int type, const char *caller) {
    switch (type) { 
    ...  // known types
        default:
            log_bug_msg("%s() - illegal type id (%d), from %s\n", __func__, type, caller);

On the caller side:

s = vt_size(vd->type, __func__);

In this way a log points me to buggy caller name at least.

Ended up not using the trick and using an explicit caller-provided label:

Still, going to bookmark this for later. Now that I know the solution, I bet I’ll be able to find a problem to apply it to!

3 Likes