Skip to content

Commit 91c46d4

Browse files
robnbehlendorf
authored andcommitted
zdb: bring crash handling over from ztest
ztest has a very nice ability to show a backtrace when there's an unexpected crash. zdb is used often enough on corrupted data and can blow up too, so nice output is useful there too. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Rob Norris <[email protected]> Closes openzfs#16181
1 parent 0a543db commit 91c46d4

File tree

1 file changed

+56
-5
lines changed

1 file changed

+56
-5
lines changed

cmd/zdb/zdb.c

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585
#include <sys/brt_impl.h>
8686
#include <zfs_comutil.h>
8787
#include <sys/zstd/zstd.h>
88+
#if (__GLIBC__ && !__UCLIBC__)
89+
#include <execinfo.h> /* for backtrace() */
90+
#endif
8891

8992
#include <libnvpair.h>
9093
#include <libzutil.h>
@@ -828,11 +831,41 @@ usage(void)
828831
static void
829832
dump_debug_buffer(void)
830833
{
831-
if (dump_opt['G']) {
832-
(void) printf("\n");
833-
(void) fflush(stdout);
834-
zfs_dbgmsg_print("zdb");
835-
}
834+
ssize_t ret __attribute__((unused));
835+
836+
if (!dump_opt['G'])
837+
return;
838+
/*
839+
* We use write() instead of printf() so that this function
840+
* is safe to call from a signal handler.
841+
*/
842+
ret = write(STDOUT_FILENO, "\n", 1);
843+
zfs_dbgmsg_print("zdb");
844+
}
845+
846+
#define BACKTRACE_SZ 100
847+
848+
static void sig_handler(int signo)
849+
{
850+
struct sigaction action;
851+
#if (__GLIBC__ && !__UCLIBC__) /* backtrace() is a GNU extension */
852+
int nptrs;
853+
void *buffer[BACKTRACE_SZ];
854+
855+
nptrs = backtrace(buffer, BACKTRACE_SZ);
856+
backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
857+
#endif
858+
dump_debug_buffer();
859+
860+
/*
861+
* Restore default action and re-raise signal so SIGSEGV and
862+
* SIGABRT can trigger a core dump.
863+
*/
864+
action.sa_handler = SIG_DFL;
865+
sigemptyset(&action.sa_mask);
866+
action.sa_flags = 0;
867+
(void) sigaction(signo, &action, NULL);
868+
raise(signo);
836869
}
837870

838871
/*
@@ -8899,9 +8932,27 @@ main(int argc, char **argv)
88998932
char *spa_config_path_env, *objset_str;
89008933
boolean_t target_is_spa = B_TRUE, dataset_lookup = B_FALSE;
89018934
nvlist_t *cfg = NULL;
8935+
struct sigaction action;
89028936

89038937
dprintf_setup(&argc, argv);
89048938

8939+
/*
8940+
* Set up signal handlers, so if we crash due to bad on-disk data we
8941+
* can get more info. Unlike ztest, we don't bail out if we can't set
8942+
* up signal handlers, because zdb is very useful without them.
8943+
*/
8944+
action.sa_handler = sig_handler;
8945+
sigemptyset(&action.sa_mask);
8946+
action.sa_flags = 0;
8947+
if (sigaction(SIGSEGV, &action, NULL) < 0) {
8948+
(void) fprintf(stderr, "zdb: cannot catch SIGSEGV: %s\n",
8949+
strerror(errno));
8950+
}
8951+
if (sigaction(SIGABRT, &action, NULL) < 0) {
8952+
(void) fprintf(stderr, "zdb: cannot catch SIGABRT: %s\n",
8953+
strerror(errno));
8954+
}
8955+
89058956
/*
89068957
* If there is an environment variable SPA_CONFIG_PATH it overrides
89078958
* default spa_config_path setting. If -U flag is specified it will

0 commit comments

Comments
 (0)