Skip to content

Commit 1115d40

Browse files
committed
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
1 parent 9a2956e commit 1115d40

File tree

3 files changed

+84
-59
lines changed

3 files changed

+84
-59
lines changed

src/host.cpp

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ void *mainloop_udata;
195195
extern "C" int _fltused = 0;
196196
#endif
197197

198-
static struct backtrace_state *bs;
198+
static struct backtrace_state *bt;
199199

200200
struct init_data {
201201
bool com_initialized = false;
@@ -438,42 +438,52 @@ static void echeck_unexpected_exit(void ) {
438438

439439
#ifdef HAVE_LIBBACKTRACE
440440
static void
441-
error_callback(void *data, const char *msg, int errnum)
441+
libbt_error_callback(void *data, const char *msg, int errnum)
442442
{
443+
int fd = *reinterpret_cast<int*>(data);
444+
char buf[STR_LEN];
445+
char *start = buf;
446+
const char *const end = buf + sizeof buf;
447+
443448
//fprintf(stderr, "libbacktrace error: %s (%d)\n", msg, errnum);
444449

445-
int fd = *reinterpret_cast<int*>(data);
446-
char buf[] = "libbacktrace error: ";
447-
write_all(fd, sizeof buf - 1, buf);
448-
write_all(fd, strlen(msg), msg);
449-
write_all(fd, 2, " (");
450-
write_number(fd, errnum);
451-
write_all(fd, 2, ")\n");
450+
strappend(&start, end, "libbacktrace error: ");
451+
strappend(&start, end, msg);
452+
strappend(&start, end, " (");
453+
append_number(&start, end, errnum);
454+
455+
write_all(fd, start - buf, buf);
452456
}
453457

454458
static int
455-
full_callback(void *data, uintptr_t pc, const char *filename, int lineno,
459+
libbt_full_callback(void *data, uintptr_t pc, const char *filename, int lineno,
456460
const char *function)
457461
{
462+
int fd = *reinterpret_cast<int*>(data);
463+
char buf[STR_LEN];
464+
char *start = buf;
465+
const char *const end = buf + sizeof buf;
466+
458467
// printf(" %s at %s:%d [pc=%p]\n", function ? function : "??",
459468
// filename ? filename : "??", lineno, (void *) pc);
460469

461-
int fd = *reinterpret_cast<int*>(data);
462-
write_all(fd, 2, " ");
470+
strappend(&start, end, " ");
463471
if (function == nullptr) {
464472
function = "??";
465473
}
466-
write_all(fd, strlen(function), function);
467-
write_all(fd, 4, " at ");
474+
strappend(&start, end, function);
475+
strappend(&start, end, " at ");
468476
if (filename == nullptr) {
469477
filename = "??";
470478
}
471-
write_all(fd, strlen(filename), filename);
472-
write_all(fd, 1, ":");
473-
write_number(fd, lineno);
474-
write_all(fd, 7, " [pc=0x");
475-
write_number(fd, (uintmax_t) pc);
476-
write_all(fd, 2, "]\n");
479+
strappend(&start, end, filename);
480+
strappend(&start, end, ":");
481+
append_number(&start, end, lineno);
482+
strappend(&start, end, " [pc=0x");
483+
append_number(&start, end, (uintmax_t) pc);
484+
strappend(&start, end, "]\n");
485+
486+
write_all(fd, start - buf, buf);
477487

478488
return 0; // continue
479489
}
@@ -580,8 +590,8 @@ struct init_data *common_preinit(int argc, char *argv[])
580590

581591
#ifdef HAVE_LIBBACKTRACE
582592
int fd = STDERR_FILENO;
583-
bs = backtrace_create_state(uv_argv[0], 1 /*thread safe*/,
584-
error_callback, &fd);
593+
bt = backtrace_create_state(uv_argv[0], 1 /*thread safe*/,
594+
libbt_error_callback, &fd);
585595
#endif
586596

587597
atexit(echeck_unexpected_exit);
@@ -1255,6 +1265,30 @@ bool running_in_debugger(){
12551265
}
12561266

12571267
#if defined(__GLIBC__)
1268+
/// dumps output of fd (from start_off offset) to stderr
1269+
/// and keep the pointer at the end of the file
1270+
/// @retval size of the file pointed by fd (current pos)
1271+
static off_t
1272+
st_glibc_flush_output(int fd, off_t start_off)
1273+
{
1274+
if (fd == STDERR_FILENO) {
1275+
return 0;
1276+
}
1277+
1278+
lseek(fd, start_off, SEEK_SET);
1279+
char buf[STR_LEN];
1280+
ssize_t rbytes = 0;
1281+
while ((rbytes = read(fd, buf, sizeof buf)) > 0) {
1282+
ssize_t written = 0;
1283+
ssize_t wbytes = 0;
1284+
while (written < rbytes &&
1285+
(wbytes = write(STDERR_FILENO, buf + written,
1286+
rbytes - written)) > 0) {
1287+
written += wbytes;
1288+
}
1289+
}
1290+
return lseek(fd, 0, SEEK_CUR);
1291+
}
12581292
/**
12591293
* print stacktrace with backtrace_symbols_fd() (glibc or macOS)
12601294
*
@@ -1276,16 +1310,13 @@ print_stacktrace_glibc()
12761310
unsigned long tid = syscall(__NR_gettid);
12771311
#endif
12781312
// snprintf(path, sizeof path, "%s/ug-%lu", get_temp_dir(), tid);
1279-
strncpy(path, get_temp_dir(), sizeof path);
1313+
char *start = path;
12801314
path[sizeof path - 1] = '\0';
1281-
strncat(path + strlen(path), "/ug-bt-", sizeof path - strlen(path) - 1);
1282-
while (tid != 0 && strlen(path) < sizeof path - 1) {
1283-
// (tid will be actually printed in reversed order (123->321))
1284-
size_t len = strlen(path);
1285-
path[len] = '0' + tid % 10;
1286-
path[len + 1] = '\0';
1287-
tid /= 10;
1288-
}
1315+
const char *const end = path + sizeof path - 1;
1316+
strappend(&start, end, get_temp_dir());
1317+
strappend(&start, end, "/ug-bt-");
1318+
append_number(&start, end, tid);
1319+
*start = '\0';
12891320
int fd = open(path, O_CLOEXEC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
12901321
unlink(path);
12911322
#endif
@@ -1298,46 +1329,36 @@ print_stacktrace_glibc()
12981329
const int num_symbols = backtrace(addresses.data(), addresses.size());
12991330
backtrace_symbols_fd(addresses.data(), num_symbols, fd);
13001331

1332+
// in case that the below fails, try write at least something
1333+
off_t last_pos = st_glibc_flush_output(fd, 0);
1334+
13011335
#ifdef HAVE_LIBBACKTRACE
13021336
char backtrace2_msg[] = "\nBacktrace symbolic:\n";
13031337
write_all(fd, sizeof backtrace2_msg - 1, backtrace2_msg);
13041338
for (int i = 0; i < num_symbols; i++) {
1305-
char sym_nr[5];
1339+
// printf("%2d: ", i);
1340+
enum { NDIGITS = 2 };
1341+
char sym_nr[] = { 'X', 'X', ':', ' ' };
13061342
int num_tmp = i;
1307-
for (int i = 0; i < 3; ++i) {
1343+
for (int i = 0; i < NDIGITS; ++i) {
13081344
if (num_tmp == 0 && i != 0) {
1309-
sym_nr[2 - i] = ' ';
1345+
sym_nr[NDIGITS - 1 - i] = ' ';
13101346
} else {
1311-
sym_nr[2 - i] = '0' + (num_tmp % 10);
1347+
sym_nr[NDIGITS - 1 - i] = '0' + (num_tmp % 10);
13121348
num_tmp /= 10;
13131349
}
13141350
}
1315-
sym_nr[3] = ':';
1316-
sym_nr[4] = ' ';
13171351
write_all(fd, sizeof sym_nr, sym_nr);
1318-
// printf("%3d: ", i);
1319-
backtrace_pcinfo(bs, (uintptr_t) addresses[i], full_callback,
1320-
error_callback, &fd);
1352+
// backtrace_pcinfo may not be async-signal-safe
1353+
backtrace_pcinfo(bt, (uintptr_t) addresses[i], libbt_full_callback,
1354+
libbt_error_callback, &fd);
13211355
}
1356+
st_glibc_flush_output(fd, last_pos);
13221357
#endif
13231358

1324-
if (fd == STDERR_FILENO) {
1325-
return;
1326-
}
1327-
1328-
lseek(fd, 0, SEEK_SET);
1329-
char buf[STR_LEN];
1330-
ssize_t rbytes = 0;
1331-
while ((rbytes = read(fd, buf, sizeof buf)) > 0) {
1332-
ssize_t written = 0;
1333-
ssize_t wbytes = 0;
1334-
while (written < rbytes &&
1335-
(wbytes = write(STDERR_FILENO, buf + written,
1336-
rbytes - written)) > 0) {
1337-
written += wbytes;
1338-
}
1359+
if (fd != STDERR_FILENO) {
1360+
close(fd);
13391361
}
1340-
close(fd);
13411362
}
13421363
#endif // defined(__GLIBC__)
13431364

src/utils/string.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
#include "compat/strings.h"
5151
#include "debug.h"
52+
#include "utils/macros.h" // for MIN
5253
#include "utils/string.h"
5354

5455
/**
@@ -155,15 +156,18 @@ void write_all(int fd, size_t len, const char *msg) {
155156
}
156157

157158
void
158-
write_number(int fd, uintmax_t num)
159+
append_number(char **ptr, const char *ptr_end, uintmax_t num)
159160
{
160161
char num_buf[100];
161162
int idx = sizeof num_buf;
162163
num_buf[--idx] = '0' + num % 10; // write '0' if num=0
163164
while ((num /= 10) != 0) {
164165
num_buf[--idx] = '0' + num % 10;
165166
}
166-
write_all(fd, sizeof num_buf - idx, num_buf + idx);
167+
const size_t buflen = ptr_end - *ptr;
168+
const size_t len = MIN(buflen, sizeof num_buf - idx);
169+
strncpy(*ptr, num_buf + idx, len);
170+
*ptr += len;
167171
}
168172

169173
/**

src/utils/string.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ bool is_prefix_of(const char *haystack, const char *needle);
5757
/// same as strpbrk but finds in a reverse order (last occurrence returned)
5858
char *strrpbrk(char *s, const char *accept);
5959
void strappend(char **ptr, const char *ptr_end, const char *src);
60+
void append_number(char **ptr, const char *ptr_end, uintmax_t num);
6061
void append_sig_desc(char **ptr, const char *ptr_end, int signum);
6162
void write_all(int fd, size_t len, const char *msg);
62-
void write_number(int fd, uintmax_t num);
6363
const char *pretty_print_fourcc(const void *fcc);
6464

6565
#ifdef __cplusplus

0 commit comments

Comments
 (0)