Skip to content

Commit 1b3d584

Browse files
robnlundman
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 d2ce1ab commit 1b3d584

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

839872
/*
@@ -8905,9 +8938,27 @@ main(int argc, char **argv)
89058938
char *spa_config_path_env, *objset_str;
89068939
boolean_t target_is_spa = B_TRUE, dataset_lookup = B_FALSE;
89078940
nvlist_t *cfg = NULL;
8941+
struct sigaction action;
89088942

89098943
dprintf_setup(&argc, argv);
89108944

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

0 commit comments

Comments
 (0)