aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/backtrace/symbolizers/dwarf/dwarf_symbolizer.cpp
blob: f5d02aaa3322ccee58c57de9d9d64f615cfdaaf3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <library/cpp/yt/backtrace/backtrace.h>

#include <library/cpp/dwarf_backtrace/backtrace.h>

#include <library/cpp/yt/string/raw_formatter.h>

namespace NYT::NBacktrace {

////////////////////////////////////////////////////////////////////////////////

void SymbolizeBacktrace(
    TBacktrace backtrace,
    const std::function<void(TStringBuf)>& frameCallback)
{
    auto error = NDwarf::ResolveBacktrace({backtrace.begin(), backtrace.size()}, [&] (const NDwarf::TLineInfo& info) {
        TRawFormatter<1024> formatter;
        formatter.AppendNumber(info.Index + 1, 10, 2);
        formatter.AppendString(". ");
        formatter.AppendString("0x");
        const int width = (sizeof(void*) == 8 ? 12 : 8);
        // 12 for x86_64 because higher bits are always zeroed.
        formatter.AppendNumber(info.Address, 16, width, '0');
        formatter.AppendString(" in ");
        formatter.AppendString(info.FunctionName);
        const int bytesToAppendEstimate = 4 + info.FileName.Size() + 1 + 4 /* who cares about line numbers > 9999 */ + 1;
        if (formatter.GetBytesRemaining() < bytesToAppendEstimate) {
            const int offset = formatter.GetBytesRemaining() - bytesToAppendEstimate;
            if (formatter.GetBytesWritten() + offset >= 0) {
                formatter.Advance(offset);
            }
        }
        formatter.AppendString(" at ");
        formatter.AppendString(info.FileName);
        formatter.AppendChar(':');
        formatter.AppendNumber(info.Line);
        if (formatter.GetBytesRemaining() == 0) {
            formatter.Revert(1);
        }
        formatter.AppendString("\n");
        frameCallback(formatter.GetBuffer());
        // Call the callback exactly `frameCount` times,
        // even if there are inline functions and one frame resolved to several lines.
        // It needs for case when caller uses `frameCount` less than 100 for pretty formatting.
        if (info.Index + 1 == std::ssize(backtrace)) {
            return NDwarf::EResolving::Break;
        }
        return NDwarf::EResolving::Continue;
    });
    if (error) {
        TRawFormatter<1024> formatter;
        formatter.AppendString("*** Error symbolizing backtrace via Dwarf\n");
        formatter.AppendString("***   Code: ");
        formatter.AppendNumber(error->Code);
        formatter.AppendString("\n");
        formatter.AppendString("***   Message: ");
        formatter.AppendString(error->Message);
        formatter.AppendString("\n");
        frameCallback(formatter.GetBuffer());
    }
}

////////////////////////////////////////////////////////////////////////////////

} // namespace NYT::NBacktrace