summaryrefslogtreecommitdiffstats
path: root/yql/essentials/utils/backtrace/backtrace_linux.cpp
blob: f819a04ae9048c64cfb472e3ef4f92f31e085662 (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
#include "backtrace_lib.h"

#include <libunwind.h>
#include <signal.h>

#include <util/system/backtrace.h>

namespace {
size_t BackTrace(void** p, size_t len, ucontext_t* con) {
    unw_context_t context;
    unw_cursor_t cursor;
    if (unw_getcontext(&context)) {
        return 0;
    }

    if (unw_init_local(&cursor, &context)) {
        return 0;
    }
    const sigcontext* signal_mcontext = (const sigcontext*)&(con->uc_mcontext);
    unw_set_reg(&cursor, UNW_X86_64_RSI, signal_mcontext->rsi);
    unw_set_reg(&cursor, UNW_X86_64_RDI, signal_mcontext->rdi);
    unw_set_reg(&cursor, UNW_X86_64_RBP, signal_mcontext->rbp);
    unw_set_reg(&cursor, UNW_X86_64_RAX, signal_mcontext->rax);
    unw_set_reg(&cursor, UNW_X86_64_RBX, signal_mcontext->rbx);
    unw_set_reg(&cursor, UNW_X86_64_RCX, signal_mcontext->rcx);
    unw_set_reg(&cursor, UNW_X86_64_R8, signal_mcontext->r8);
    unw_set_reg(&cursor, UNW_X86_64_R9, signal_mcontext->r9);
    unw_set_reg(&cursor, UNW_X86_64_R10, signal_mcontext->r10);
    unw_set_reg(&cursor, UNW_X86_64_R11, signal_mcontext->r11);
    unw_set_reg(&cursor, UNW_X86_64_R12, signal_mcontext->r12);
    unw_set_reg(&cursor, UNW_X86_64_R13, signal_mcontext->r13);
    unw_set_reg(&cursor, UNW_X86_64_R14, signal_mcontext->r14);
    unw_set_reg(&cursor, UNW_X86_64_R15, signal_mcontext->r15);
    unw_set_reg(&cursor, UNW_X86_64_RSP, signal_mcontext->rsp);

    unw_set_reg(&cursor, UNW_REG_SP, signal_mcontext->rsp);
    unw_set_reg(&cursor, UNW_REG_IP, signal_mcontext->rip);

    size_t pos = 0;
    p[pos++] = (void*)signal_mcontext->rip;
    while (pos < len && unw_step(&cursor) > 0) {
        unw_word_t ip = 0;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        if (unw_is_signal_frame(&cursor)) {
            continue;
        }
        p[pos++] = (void*)ip;
    }
    return pos;
}
} // namespace

namespace NYql {
namespace NBacktrace {
size_t CollectBacktrace(void** addresses, size_t limit, void* data) {
    if (!data) {
        return BackTrace(addresses, limit);
    }
    return BackTrace(addresses, limit, reinterpret_cast<ucontext_t*>(data));
}
} // namespace NBacktrace
} // namespace NYql