aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp
blob: 37ebda8e488fb18537f941296d0fe2d062a09656 (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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <library/cpp/yt/backtrace/backtrace.h>

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

#include <util/system/compiler.h>

#include <dlfcn.h>
#include <cxxabi.h>

namespace NYT::NBacktrace {

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

namespace {

int GetSymbolInfo(const void* pc, char* buffer, int length)
{
    TBaseFormatter formatter(buffer, length);

    // See http://www.codesourcery.com/cxx-abi/abi.html#mangling
    // And, yes, dladdr() is not async signal safe. We can substitute it
    // with hand-written symbolization code from google-glog in case of any trouble.
    Dl_info info;
    if (!dladdr(pc, &info)) {
        return 0;
    }

    /*
     * typedef struct {
     *     const char *dli_fname;  // Pathname of shared object that
     *                             // contains address
     *     void       *dli_fbase;  // Address at which shared object
     *                             // is loaded
     *     const char *dli_sname;  // Name of nearest symbol with address
     *                             // lower than addr
     *     void       *dli_saddr;  // Exact address of symbol named
     *                             // in dli_sname
     * } Dl_info;
     *
     * If no symbol matching addr could be found, then dli_sname and dli_saddr are set to NULL.
     */

    if (info.dli_sname && info.dli_saddr) {
        formatter.AppendString("<");
        int demangleStatus = 0;

        if (info.dli_sname[0] == '_' && info.dli_sname[1] == 'Z') {
            // This is also not async signal safe.
            // But (ta-dah!) we can replace it with symbolization code from google-glob.
            char* demangledName = abi::__cxa_demangle(info.dli_sname, 0, 0, &demangleStatus);
            if (demangleStatus == 0) {
                formatter.AppendString(demangledName);
            } else {
                formatter.AppendString(info.dli_sname);
            }
            free(demangledName);
        } else {
            formatter.AppendString(info.dli_sname);
        }
        formatter.AppendString("+");
        formatter.AppendNumber((char*)pc - (char*)info.dli_saddr);
        formatter.AppendString(">");
        formatter.AppendString(" ");
    }

    if (info.dli_fname && info.dli_fbase) {
        formatter.AppendString("(");
        formatter.AppendString(info.dli_fname);
        formatter.AppendString("+");
        formatter.AppendNumber((char*)pc - (char*)info.dli_fbase);
        formatter.AppendString(")");
    }
    return formatter.GetBytesWritten();
}

void DumpStackFrameInfo(TBaseFormatter* formatter, const void* pc)
{
    formatter->AppendString("@ ");
    const int width = (sizeof(void*) == 8 ? 12 : 8) + 2;
    // +2 for "0x"; 12 for x86_64 because higher bits are always zeroed.
    formatter->AppendNumberAsHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
    formatter->AppendString(" ");
    // Get the symbol from the previous address of PC,
    // because PC may be in the next function.
    formatter->Advance(GetSymbolInfo(
        reinterpret_cast<const char*>(pc) - 1,
        formatter->GetCursor(),
        formatter->GetBytesRemaining()));
    if (formatter->GetBytesRemaining() == 0) {
        formatter->Revert(1);
    }
    formatter->AppendString("\n");
}

} // namespace

Y_WEAK void SymbolizeBacktrace(
    TBacktrace backtrace,
    const std::function<void(TStringBuf)>& frameCallback)
{
    for (int i = 0; i < std::ssize(backtrace); ++i) {
        TRawFormatter<1024> formatter;
        formatter.Reset();
        formatter.AppendNumber(i + 1, 10, 2);
        formatter.AppendString(". ");
        DumpStackFrameInfo(&formatter, backtrace[i]);
        frameCallback(formatter.GetBuffer());
    }
}

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

} // namespace NYT::NBacktrace