mwrap (Perl version) user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH] use backtrace_symbols_fmt on FreeBSD to emulate glibc output
@ 2022-12-11  6:30 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2022-12-11  6:30 UTC (permalink / raw)
  To: mwrap-perl

"'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 <<EOM;
 #include <execinfo.h>
-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);
 		}

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-12-11  6:29 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-11  6:30 [PATCH] use backtrace_symbols_fmt on FreeBSD to emulate glibc output Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mwrap-perl.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).