From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.7 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, UNWANTED_LANGUAGE_BODY shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 6DCB41F61A for ; Sun, 11 Dec 2022 06:29:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1670740168; bh=dK7YOi5TJMz6LDKo/K5/+RP6U24ofPzlg03sA0g16ZQ=; h=From:To:Subject:Date:From; b=sedNkbmSPaGqYO3nnwhFsdjY5eesXTKV7UZCTPBn3uu+hd0ctVCd7NhBGoORaiYXy MggvZZ1bjgNyCYduOJLyTgaevB2tQBhMBOa+2Kxp1ha76Y2D047U62omV6yi9zFSC7 Qq3eqnQ29OOhTPr6Ch5o1/i4UxGeQ3c9U2o35JSc= From: Eric Wong To: mwrap-perl@80x24.org Subject: [PATCH] use backtrace_symbols_fmt on FreeBSD to emulate glibc output Date: Sun, 11 Dec 2022 06:30:08 +0000 Message-Id: <20221211063008.92812-1-mwrap-perl@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: "'Tis better to emit than to parse" Since FreeBSD has backtrace_symbols_fmt(3) and glibc does not, we'll use the hard-coded glibc backtrace_symbols(3) format. This saves us the trouble of maintaining separate parsers. I consider the default glibc format superior, anyways, since the important piece (%f - filename) is up front, since the %a (address) is process-specific and not useful when viewed from a different process. --- Makefile.PL | 2 +- Mwrap.xs | 9 ++------- mwrap_core.h | 43 ++++++++++++++++++++----------------------- mwrap_httpd.h | 10 +++------- 4 files changed, 26 insertions(+), 38 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 6f563c1..e7e24cf 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -57,7 +57,7 @@ print '# checking for -lexecinfo... '; open my $fh, '>', "$d/execinfo.c"; print $fh < -int main(void) { return backtrace_symbols ? 1 : 0; } +int main(void) { return backtrace_symbols_fmt ? 1 : 0; } EOM close $fh; open $olderr, '+>&', *STDERR{IO}; diff --git a/Mwrap.xs b/Mwrap.xs index 5541559..ceeb495 100644 --- a/Mwrap.xs +++ b/Mwrap.xs @@ -23,14 +23,9 @@ static SV *location_string(struct src_loc *l) else sv_setpvf(ret, "%s:%zu", l->f->fn, l->lineno); } else { - char **s = backtrace_symbols((void *)l->bt, (int)l->bt_len); - - if (!s) { - fprintf(stderr, "backtrace_symbols => NULL: %s\n", - strerror(errno)); - return &PL_sv_undef; - } + char **s = bt_syms(l->bt, l->bt_len); + if (!s) return &PL_sv_undef; ret = newSVpvn(s[0], strlen(s[0])); free(s); } diff --git a/mwrap_core.h b/mwrap_core.h index b2d0511..6d498c1 100644 --- a/mwrap_core.h +++ b/mwrap_core.h @@ -134,7 +134,7 @@ static void *my_mempcpy(void *dest, const void *src, size_t n) (uintptr_t)(__builtin_extract_return_addr(__builtin_return_address(nr))) /* - * only for interpreted sources (Perl/Ruby/etc), not backtrace_symbols files + * only for interpreted sources (Perl/Ruby/etc), not backtrace_symbols* files */ struct src_file { struct cds_lfht_node nd; /* <=> files table */ @@ -160,7 +160,7 @@ struct src_loc { struct src_file *f; /* .lineno only needs `unsigned', but is size_t for alignment */ size_t lineno; - uintptr_t bt[]; + void *bt[]; }; /* @@ -400,7 +400,7 @@ update_stats_rcu_lock(size_t *generation, size_t size, uintptr_t caller) k->total = size; k->f = NULL; k->lineno = 0; - k->bt[0] = caller; + k->bt[0] = (void *)caller; k->bt_len = 1; hash_src_loc(k); ret = totals_add_rcu(k); @@ -681,6 +681,18 @@ struct dump_arg { size_t min; }; +char **bt_syms(void * const *addrlist, uint32_t size) +{ + mwrap_assert(size < INT_MAX); +#if defined(__GLIBC__) + char **s = backtrace_symbols(addrlist, size); +#else /* make FreeBSD look like glibc output: */ + char **s = backtrace_symbols_fmt(addrlist, size, "%f(%n%D) [%a]"); +#endif + if (!s) fprintf(stderr, "backtrace_symbols: %m\n"); + return s; +} + static void *dump_to_file(struct dump_arg *a) { struct cds_lfht_iter iter; @@ -697,15 +709,12 @@ static void *dump_to_file(struct dump_arg *a) if (l->total <= a->min) continue; if (loc_is_addr(l)) { - char **s = backtrace_symbols((void **)l->bt, 1); + char **s = bt_syms(l->bt, 1); if (s) { fprintf(a->fp, "%16zu %12zu %s\n", l->total, l->allocations, s[0]); free(s); - } else { - fprintf(stderr, "backtrace_symbols: %s\n", - strerror(errno)); } } else { fprintf(a->fp, "%16zu %12zu %s:%zu\n", @@ -718,14 +727,14 @@ out_unlock: return 0; } -/* extract from backtrace_symbols(3) output */ +/* str = "/path/to/foo.so(+0x123) [0xdeadbeefcafe]" (see bt_syms()) */ static int extract_addr(const char *str, size_t len, void **p) { unsigned long x; char *e; -#if defined(__GLIBC__) /* str = "/path/to/foo.so(+0x123) [0xdeadbeefcafe]" */ const char *end = str + len; const char *c = memrchr(str, '[', len); + if (c && (c + 2) < end && c[1] == '0' && c[2] == 'x') { errno = 0; x = strtoul(c + 3, &e, 16); @@ -734,18 +743,6 @@ static int extract_addr(const char *str, size_t len, void **p) return 1; } } -#elif defined(__FreeBSD__) /* str = "0xdeadbeefcafe <%n%D> at %f" */ - const char *c = memchr(str, ' ', len); - errno = 0; - if (len > 4 && c && str[0] == '0' && str[1] == 'x') { - errno = 0; - x = strtoul(str + 2, &e, 16); - if (!errno && *e == ' ') { - *p = (void *)x; - return 1; - } - } -#endif return 0; } @@ -890,11 +887,11 @@ static void mwrap_reset(void) static struct src_loc *mwrap_get(const char *str, size_t len) { struct src_loc *l = NULL; - uintptr_t p; + void *p; if (len >= PATH_MAX) return l; - if (extract_addr(str, len, (void **)&p)) { + if (extract_addr(str, len, &p)) { struct cds_lfht *t = CMM_LOAD_SHARED(totals); struct src_loc *k; diff --git a/mwrap_httpd.h b/mwrap_httpd.h index 5c5a58b..6856208 100644 --- a/mwrap_httpd.h +++ b/mwrap_httpd.h @@ -410,15 +410,11 @@ static off_t write_loc_name(FILE *fp, const struct src_loc *l) else fprintf(fp, ":%zu", l->lineno); } else { - size_t i; - char **s = backtrace_symbols((void *)l->bt, (int)l->bt_len); + char **s = bt_syms(l->bt, l->bt_len); + if (!s) return -1; - if (!s) { - fprintf(stderr, "backtrace_symbols: %m\n"); - return -1; - } fputs(s[0], fp); - for (i = 1; i < l->bt_len; i++) { + for (uint32_t i = 1; i < l->bt_len; i++) { fputc('\n', fp); fputs(s[i], fp); }