host: libbacktrace/print_stacktrace_glibc improves

- rename some symbols (state bs->bt), callbacks prefix with libbt
- assemble the line with strappend-like functions and write() just the
result
- flush the output after backtrace_symbols_fd() in case that the later
calls fail to have at least something output
- write_number->append_number for point 2 + tid write
This commit is contained in:
Martin Pulec
2025-08-13 14:18:36 +02:00
parent 9a2956ef34
commit 1115d403de
3 changed files with 84 additions and 59 deletions

View File

@@ -195,7 +195,7 @@ void *mainloop_udata;
extern "C" int _fltused = 0;
#endif
static struct backtrace_state *bs;
static struct backtrace_state *bt;
struct init_data {
bool com_initialized = false;
@@ -438,42 +438,52 @@ static void echeck_unexpected_exit(void ) {
#ifdef HAVE_LIBBACKTRACE
static void
error_callback(void *data, const char *msg, int errnum)
libbt_error_callback(void *data, const char *msg, int errnum)
{
int fd = *reinterpret_cast<int*>(data);
char buf[STR_LEN];
char *start = buf;
const char *const end = buf + sizeof buf;
//fprintf(stderr, "libbacktrace error: %s (%d)\n", msg, errnum);
int fd = *reinterpret_cast<int*>(data);
char buf[] = "libbacktrace error: ";
write_all(fd, sizeof buf - 1, buf);
write_all(fd, strlen(msg), msg);
write_all(fd, 2, " (");
write_number(fd, errnum);
write_all(fd, 2, ")\n");
strappend(&start, end, "libbacktrace error: ");
strappend(&start, end, msg);
strappend(&start, end, " (");
append_number(&start, end, errnum);
write_all(fd, start - buf, buf);
}
static int
full_callback(void *data, uintptr_t pc, const char *filename, int lineno,
libbt_full_callback(void *data, uintptr_t pc, const char *filename, int lineno,
const char *function)
{
int fd = *reinterpret_cast<int*>(data);
char buf[STR_LEN];
char *start = buf;
const char *const end = buf + sizeof buf;
// printf(" %s at %s:%d [pc=%p]\n", function ? function : "??",
// filename ? filename : "??", lineno, (void *) pc);
int fd = *reinterpret_cast<int*>(data);
write_all(fd, 2, " ");
strappend(&start, end, " ");
if (function == nullptr) {
function = "??";
}
write_all(fd, strlen(function), function);
write_all(fd, 4, " at ");
strappend(&start, end, function);
strappend(&start, end, " at ");
if (filename == nullptr) {
filename = "??";
}
write_all(fd, strlen(filename), filename);
write_all(fd, 1, ":");
write_number(fd, lineno);
write_all(fd, 7, " [pc=0x");
write_number(fd, (uintmax_t) pc);
write_all(fd, 2, "]\n");
strappend(&start, end, filename);
strappend(&start, end, ":");
append_number(&start, end, lineno);
strappend(&start, end, " [pc=0x");
append_number(&start, end, (uintmax_t) pc);
strappend(&start, end, "]\n");
write_all(fd, start - buf, buf);
return 0; // continue
}
@@ -580,8 +590,8 @@ struct init_data *common_preinit(int argc, char *argv[])
#ifdef HAVE_LIBBACKTRACE
int fd = STDERR_FILENO;
bs = backtrace_create_state(uv_argv[0], 1 /*thread safe*/,
error_callback, &fd);
bt = backtrace_create_state(uv_argv[0], 1 /*thread safe*/,
libbt_error_callback, &fd);
#endif
atexit(echeck_unexpected_exit);
@@ -1255,6 +1265,30 @@ bool running_in_debugger(){
}
#if defined(__GLIBC__)
/// dumps output of fd (from start_off offset) to stderr
/// and keep the pointer at the end of the file
/// @retval size of the file pointed by fd (current pos)
static off_t
st_glibc_flush_output(int fd, off_t start_off)
{
if (fd == STDERR_FILENO) {
return 0;
}
lseek(fd, start_off, SEEK_SET);
char buf[STR_LEN];
ssize_t rbytes = 0;
while ((rbytes = read(fd, buf, sizeof buf)) > 0) {
ssize_t written = 0;
ssize_t wbytes = 0;
while (written < rbytes &&
(wbytes = write(STDERR_FILENO, buf + written,
rbytes - written)) > 0) {
written += wbytes;
}
}
return lseek(fd, 0, SEEK_CUR);
}
/**
* print stacktrace with backtrace_symbols_fd() (glibc or macOS)
*
@@ -1276,16 +1310,13 @@ print_stacktrace_glibc()
unsigned long tid = syscall(__NR_gettid);
#endif
// snprintf(path, sizeof path, "%s/ug-%lu", get_temp_dir(), tid);
strncpy(path, get_temp_dir(), sizeof path);
char *start = path;
path[sizeof path - 1] = '\0';
strncat(path + strlen(path), "/ug-bt-", sizeof path - strlen(path) - 1);
while (tid != 0 && strlen(path) < sizeof path - 1) {
// (tid will be actually printed in reversed order (123->321))
size_t len = strlen(path);
path[len] = '0' + tid % 10;
path[len + 1] = '\0';
tid /= 10;
}
const char *const end = path + sizeof path - 1;
strappend(&start, end, get_temp_dir());
strappend(&start, end, "/ug-bt-");
append_number(&start, end, tid);
*start = '\0';
int fd = open(path, O_CLOEXEC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
unlink(path);
#endif
@@ -1298,46 +1329,36 @@ print_stacktrace_glibc()
const int num_symbols = backtrace(addresses.data(), addresses.size());
backtrace_symbols_fd(addresses.data(), num_symbols, fd);
// in case that the below fails, try write at least something
off_t last_pos = st_glibc_flush_output(fd, 0);
#ifdef HAVE_LIBBACKTRACE
char backtrace2_msg[] = "\nBacktrace symbolic:\n";
write_all(fd, sizeof backtrace2_msg - 1, backtrace2_msg);
for (int i = 0; i < num_symbols; i++) {
char sym_nr[5];
// printf("%2d: ", i);
enum { NDIGITS = 2 };
char sym_nr[] = { 'X', 'X', ':', ' ' };
int num_tmp = i;
for (int i = 0; i < 3; ++i) {
for (int i = 0; i < NDIGITS; ++i) {
if (num_tmp == 0 && i != 0) {
sym_nr[2 - i] = ' ';
sym_nr[NDIGITS - 1 - i] = ' ';
} else {
sym_nr[2 - i] = '0' + (num_tmp % 10);
sym_nr[NDIGITS - 1 - i] = '0' + (num_tmp % 10);
num_tmp /= 10;
}
}
sym_nr[3] = ':';
sym_nr[4] = ' ';
write_all(fd, sizeof sym_nr, sym_nr);
// printf("%3d: ", i);
backtrace_pcinfo(bs, (uintptr_t) addresses[i], full_callback,
error_callback, &fd);
// backtrace_pcinfo may not be async-signal-safe
backtrace_pcinfo(bt, (uintptr_t) addresses[i], libbt_full_callback,
libbt_error_callback, &fd);
}
st_glibc_flush_output(fd, last_pos);
#endif
if (fd == STDERR_FILENO) {
return;
if (fd != STDERR_FILENO) {
close(fd);
}
lseek(fd, 0, SEEK_SET);
char buf[STR_LEN];
ssize_t rbytes = 0;
while ((rbytes = read(fd, buf, sizeof buf)) > 0) {
ssize_t written = 0;
ssize_t wbytes = 0;
while (written < rbytes &&
(wbytes = write(STDERR_FILENO, buf + written,
rbytes - written)) > 0) {
written += wbytes;
}
}
close(fd);
}
#endif // defined(__GLIBC__)

View File

@@ -49,6 +49,7 @@
#include "compat/strings.h"
#include "debug.h"
#include "utils/macros.h" // for MIN
#include "utils/string.h"
/**
@@ -155,7 +156,7 @@ void write_all(int fd, size_t len, const char *msg) {
}
void
write_number(int fd, uintmax_t num)
append_number(char **ptr, const char *ptr_end, uintmax_t num)
{
char num_buf[100];
int idx = sizeof num_buf;
@@ -163,7 +164,10 @@ write_number(int fd, uintmax_t num)
while ((num /= 10) != 0) {
num_buf[--idx] = '0' + num % 10;
}
write_all(fd, sizeof num_buf - idx, num_buf + idx);
const size_t buflen = ptr_end - *ptr;
const size_t len = MIN(buflen, sizeof num_buf - idx);
strncpy(*ptr, num_buf + idx, len);
*ptr += len;
}
/**

View File

@@ -57,9 +57,9 @@ bool is_prefix_of(const char *haystack, const char *needle);
/// same as strpbrk but finds in a reverse order (last occurrence returned)
char *strrpbrk(char *s, const char *accept);
void strappend(char **ptr, const char *ptr_end, const char *src);
void append_number(char **ptr, const char *ptr_end, uintmax_t num);
void append_sig_desc(char **ptr, const char *ptr_end, int signum);
void write_all(int fd, size_t len, const char *msg);
void write_number(int fd, uintmax_t num);
const char *pretty_print_fourcc(const void *fcc);
#ifdef __cplusplus