norio-nomura / SwiftBacktrace

Stack traces for Swift on Mac and Linux using `libunwind`.
MIT License
17 stars 1 forks source link

Is it possible to retrieve the source location (file and line number) as well? #20

Open MrMage opened 5 years ago

MrMage commented 5 years ago

This library is super helpful for getting symbolicating stack traces on Linux, thank you so much!

I'd like to create a custom SymbolFormatter that outputs stack traces in Ruby format, as these could presumably be parsed by Google Stackdriver Error Reporting. However, for that I would need each symbol's corresponding source file name and line number as well.

Is there any possibility of retrieving these with SwiftBacktrace? I do not mind compiling my binary with debug symbols (-Xswiftc -g).

weissi commented 5 years ago

@MrMage this shouldn't actually be hard. I believe if we make a script similar (will be much easier) to this one, then we could use lldb (on your Mac for example) for the symbolication instead of addr2line and that should give you the line numbers.

The linked script does quite a lot more than we need because the current output already gives us everything we need which is:

from just the library file name + the offset it is possible to get exact file/line information. For some reason though addr2line doesn't seem to be able to get that out of the DWARF that Swift produces. But lldb definitely can do that.

norio-nomura commented 5 years ago

AFAIK, libunwind parses ELF symbols, but does not expose API that returns line number in source file. So, if we want to get line number in source file, we need to use another functions other than provided by libunwind.

If I do, I might use the latter. 🤔

MrMage commented 5 years ago

Thank you for these insights! I have filed an issue with Stackdriver Error reporting now asking for the correct stack trace format for parsing. Until they reply, I could probably get by with manually symbolicating the stack traces as you guys described. In any case, this is not a super-high priority; hard crashes should be fairly rare, after all.

MrMage commented 5 years ago

FYI, in case anyone is interested, this is the formatter I am using right now to get my stack straces sort-of parsed by Google Stackdriver:

let stackdriverStyleFormat = SymbolFormatter { symbol -> String in
    let (module, name, _, _) = symbol
    let sanitizedName = name
        // All these need to be replaced to make Stackdriver happy. Characters we can keep: $.<>
        .replacingOccurrences(of: "(", with: "[")
        .replacingOccurrences(of: ")", with: "]")
        .replacingOccurrences(of: " ", with: "_")
        .replacingOccurrences(of: "?", with: "0")
        .replacingOccurrences(of: "->", with: "_returns_")
        .replacingOccurrences(of: "-", with: "_")
        .replacingOccurrences(of: "@", with: "")
        .replacingOccurrences(of: ":", with: "_")
        .replacingOccurrences(of: "#", with: "")
    return "   at \(sanitizedName) (\(module):1:1)"
}

addSignalHandler {
    JSONLogger.sharedInstance.fatal("UnknownCrash\n"
        + backtrace(500, formatter: .init(stackdriverStyleFormat.compose(.default)))
            .joined(separator: "\n"))
}