static zstring_view demangler char stack_memory size_t stack_memory_si

  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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
static zstring_view demangler(char *stack_memory, size_t stack_memory_size, zstring_view name) {
if (!has_demangler) {
return name;
}
assert(demangler_path != "");
int channel[2];
if (pipe(channel) < 0) {
writeLogfSS(Error, "Can't create pipe %d", errno);
has_demangler = false;
return name;
}
scope_guard {
close(channel[0]);
close(channel[1]);
};
pid_t pid = fork();
if (pid < -1) {
writeLogfSS(Error, "Can't perform fork %d", errno);
has_demangler = false;
return name;
}
if (pid == 0) {
/* child */
CHECKED_SS(dup2(channel[1], STDOUT_FILENO));
char const *argv[] = { demangler_path.c_str(), name.data(), nullptr };
execv(demangler_path.c_str(), const_cast<char **>(argv));
_exit(EXIT_FAILURE);
}
close(channel[1]);
channel[1] = -1;
scope_guard {
if (::waitpid(pid, nullptr, WNOHANG) == 0) {
kill(pid, 9);
::waitpid(pid, nullptr, WNOHANG);
}
};
pollfd pfd[1] = {};
pfd[0].fd = channel[0];
pfd[0].revents = 0;
pfd[0].events = POLLIN;
struct timespec start_time;
if (clock_gettime(CLOCK_MONOTONIC, &start_time) < 0) {
writeLogfSS(Error, "Can't perform clock_gettime %d", errno);
has_demangler = false;
return name;
}
struct timespec current_time;
constexpr int timeout = 100;
int time_wait = timeout;
size_t size = stack_memory_size;
size_t offset = 0;
for (;;) {
int ret = ::poll(pfd, 1, time_wait);
if (ret == 0) {
time_wait = 0;
break;
}
if (ret < 0) {
writeLogfSS(Error, "Can't perform poll %d", errno);
has_demangler = false;
return name;
}
int n = ::read(channel[0], stack_memory + offset, size);
if (n == 0) {
break;
}
if (n < 0) {
writeLogfSS(Error, "Can't perform read %d", errno);
has_demangler = false;
return name;
}
offset += n;
size -= n;
if (clock_gettime(CLOCK_MONOTONIC, &current_time) < 0) {
writeLogfSS(Error, "Can't perform clock_gettime %d", errno);
has_demangler = false;
return name;
}
int diff_ms = diff_in_ms(start_time, current_time);
time_wait = (timeout > diff_ms)? timeout - diff_ms : 0;
if (time_wait == 0) {
break;
}
}
if (time_wait == 0) {
return name;
}
return stack_memory;
}
void libbacktrace_symbol_callback(void *data, uintptr_t pc,
const char *symname,
uintptr_t symval,
uintptr_t symsize) {
auto frame_additional_data = reinterpret_cast<frame_data *>(data);
char memory[4096];
auto symbol = demangler(memory, sizeof(memory), symname);
writeLogfSS(Alert, "%d# %s+0x%lx", frame_additional_data->frame_number, symbol.data(), pc - symval + 1);
}
inline int libbacktrace_full_callback(void *data, uintptr_t pc,
const char *filename, int lineno,
const char *function) {
auto frame_additional_data = reinterpret_cast<frame_data *>(data);
if (filename) {
char memory[4096];
auto demangled_function = demangler(memory, sizeof(memory), function);
writeLogfSS(Alert, "%d# %s at %s:%d", frame_additional_data->frame_number, demangled_function.data(), filename, lineno);
} else if (function) {
char memory[4096];
auto demangled_function = demangler(memory, sizeof(memory), function);
writeLogfSS(Alert, "%d# %s (pc 0x%lx)", frame_additional_data->frame_number, demangled_function.data(), pc);
} else if (pc != (uintptr_t)-1) {
backtrace_syminfo(state, pc, libbacktrace_symbol_callback, libbacktrace_error_callback, data);
}
frame_additional_data->frame_number++;
return 0;
}