1*434283fdSDevin Teske# -*- tab-width: 4 -*- ;; Emacs 2*434283fdSDevin Teske# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM 3*434283fdSDevin Teske############################################################ IDENT(1) 4*434283fdSDevin Teske# 5*434283fdSDevin Teske# $Title: dwatch(8) module for coredump-worthy signal delivery $ 6*434283fdSDevin Teske# $Copyright: 2026 Devin Teske. All rights reserved. $ 7*434283fdSDevin Teske# 8*434283fdSDevin Teske############################################################ DESCRIPTION 9*434283fdSDevin Teske# 10*434283fdSDevin Teske# Print signals whose default action produces a coredump, as they are 11*434283fdSDevin Teske# sent, together with a verdict of whether a core will actually be 12*434283fdSDevin Teske# written, rendered the same way and in the same order the kernel will 13*434283fdSDevin Teske# decide it: the target may be ignoring or catching the signal, dumps 14*434283fdSDevin Teske# may be disabled (kern.coredump), the target may be flagged sugid 15*434283fdSDevin Teske# (kern.sugid_coredump) or may have disabled tracing via procctl(2) 16*434283fdSDevin Teske# PROC_TRACE_CTL, or RLIMIT_CORE may be 0. 17*434283fdSDevin Teske# Coredump-worthy is defined by the SIGPROP_CORE entries of the 18*434283fdSDevin Teske# sigproptbl in kern_sig.c: SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, 19*434283fdSDevin Teske# SIGFPE, SIGBUS, SIGSEGV, and SIGSYS. 20*434283fdSDevin Teske# The coredump-top profile maintains a running catalog, updated 21*434283fdSDevin Teske# every 3 seconds, of coredump-worthy signals by process and signal. 22*434283fdSDevin Teske# Combine with `-O cmd' to capture state as each event occurs. 23*434283fdSDevin Teske# 24*434283fdSDevin Teske############################################################ PRAGMAS 25*434283fdSDevin Teske 26*434283fdSDevin Teskecase "$PROFILE" in 27*434283fdSDevin Teskecoredump-top) 28*434283fdSDevin Teske DTRACE_PRAGMA=" 29*434283fdSDevin Teske option quiet 30*434283fdSDevin Teske option aggsortrev 31*434283fdSDevin Teske " # END-QUOTE 32*434283fdSDevin Teske ;; 33*434283fdSDevin Teskeesac 34*434283fdSDevin Teske 35*434283fdSDevin Teske############################################################ PROBE 36*434283fdSDevin Teske 37*434283fdSDevin Teskecase "$PROFILE" in 38*434283fdSDevin Teskecoredump-top) 39*434283fdSDevin Teske : ${PROBE:=profile:::tick-3s} ;; 40*434283fdSDevin Teske*) 41*434283fdSDevin Teske : ${PROBE:=proc:::signal-send} 42*434283fdSDevin Teskeesac 43*434283fdSDevin Teske 44*434283fdSDevin Teske############################################################ GLOBALS 45*434283fdSDevin Teske 46*434283fdSDevin Teskeexec 9<<EOF 47*434283fdSDevin Teske/* 48*434283fdSDevin Teske * Signals whose default action includes a coredump, per the 49*434283fdSDevin Teske * SIGPROP_CORE entries of the sigproptbl in kern_sig.c of FreeBSD 50*434283fdSDevin Teske */ 51*434283fdSDevin Teskeinline int coredump_sig[int sig] = 52*434283fdSDevin Teske sig == SIGQUIT ? 1 : 53*434283fdSDevin Teske sig == SIGILL ? 1 : 54*434283fdSDevin Teske sig == SIGTRAP ? 1 : 55*434283fdSDevin Teske sig == SIGABRT ? 1 : /* SIGIOT */ 56*434283fdSDevin Teske sig == SIGEMT ? 1 : 57*434283fdSDevin Teske sig == SIGFPE ? 1 : 58*434283fdSDevin Teske sig == SIGBUS ? 1 : 59*434283fdSDevin Teske sig == SIGSEGV ? 1 : 60*434283fdSDevin Teske sig == SIGSYS ? 1 : 61*434283fdSDevin Teske 0; 62*434283fdSDevin TeskeEOF 63*434283fdSDevin TeskeGLOBALS=$( cat <&9 ) 64*434283fdSDevin Teske 65*434283fdSDevin Teske############################################################ EVENT ACTION 66*434283fdSDevin Teske 67*434283fdSDevin Teske[ "$CUSTOM_TEST" ] || case "$PROFILE" in 68*434283fdSDevin Teskecoredump-top) ;; 69*434283fdSDevin Teske*) EVENT_TEST="coredump_sig[this->sig]" 70*434283fdSDevin Teskeesac 71*434283fdSDevin Teske 72*434283fdSDevin Teske############################################################ ACTIONS 73*434283fdSDevin Teske 74*434283fdSDevin Teskeif [ "$PROFILE" = "coredump-top" ]; then 75*434283fdSDevin Teskeexec 9<<EOF 76*434283fdSDevin Teske$GLOBALS 77*434283fdSDevin Teske 78*434283fdSDevin TeskeBEGIN { printf("Cataloging coredump-worthy signals ...") } /* probe ID $ID */ 79*434283fdSDevin Teske 80*434283fdSDevin Teskeproc:::signal-send /coredump_sig[(int)arg2]/ /* probe ID $(( $ID + 1 )) */ 81*434283fdSDevin Teske{ 82*434283fdSDevin Teske @cores[stringof(((struct proc *)args[1])->p_comm), 83*434283fdSDevin Teske signal_string[(int)arg2]] = count(); 84*434283fdSDevin Teske} 85*434283fdSDevin TeskeEOF 86*434283fdSDevin TeskeACTIONS=$( cat <&9 ) 87*434283fdSDevin TeskeID=$(( $ID + 2 )) 88*434283fdSDevin Teskeelse 89*434283fdSDevin Teskeexec 9<<EOF 90*434283fdSDevin Teske$GLOBALS 91*434283fdSDevin Teske 92*434283fdSDevin Teskethis int sig; 93*434283fdSDevin Teskethis pid_t pid; 94*434283fdSDevin Teskethis string verdict; 95*434283fdSDevin Teskethis struct proc * target; 96*434283fdSDevin Teskethis u_int core_catch; 97*434283fdSDevin Teskethis u_int core_ign; 98*434283fdSDevin Teskethis u_int core_notrace; 99*434283fdSDevin Teskethis u_int core_sugid; 100*434283fdSDevin Teskethis uint64_t core_limit; 101*434283fdSDevin Teske 102*434283fdSDevin Teske$PROBE /* probe ID $ID */ 103*434283fdSDevin Teske{${TRACE:+ 104*434283fdSDevin Teske printf("<$ID>"); 105*434283fdSDevin Teske} 106*434283fdSDevin Teske this->target = (struct proc *)args[1]; 107*434283fdSDevin Teske this->pid = (pid_t)this->target->p_pid; 108*434283fdSDevin Teske this->sig = (int)arg2; 109*434283fdSDevin Teske} 110*434283fdSDevin Teske 111*434283fdSDevin Teske$PROBE /* probe ID $(( $ID + 1 )) */ 112*434283fdSDevin Teske{${TRACE:+ 113*434283fdSDevin Teske printf("<$(( $ID + 1 ))>"); 114*434283fdSDevin Teske} 115*434283fdSDevin Teske /* 116*434283fdSDevin Teske * Render a verdict the way the kernel will: disposition first 117*434283fdSDevin Teske * (struct sigacts), then the coredump() gauntlet in its order: 118*434283fdSDevin Teske * kern.coredump, kern.sugid_coredump vs P_SUGID, procctl(2) 119*434283fdSDevin Teske * PROC_TRACE_CTL (P2_NOTRACE), and finally RLIMIT_CORE 120*434283fdSDevin Teske */ 121*434283fdSDevin Teske this->core_ign = 122*434283fdSDevin Teske this->target->p_sigacts->ps_sigignore.__bits[ 123*434283fdSDevin Teske (this->sig - 1) >> 5] & 124*434283fdSDevin Teske (1 << ((this->sig - 1) & 31)); 125*434283fdSDevin Teske this->core_catch = 126*434283fdSDevin Teske this->target->p_sigacts->ps_sigcatch.__bits[ 127*434283fdSDevin Teske (this->sig - 1) >> 5] & 128*434283fdSDevin Teske (1 << ((this->sig - 1) & 31)); 129*434283fdSDevin Teske this->core_sugid = 130*434283fdSDevin Teske this->target->p_flag & 0x00000100; /* P_SUGID */ 131*434283fdSDevin Teske this->core_notrace = 132*434283fdSDevin Teske this->target->p_flag2 & 0x00000002; /* P2_NOTRACE */ 133*434283fdSDevin Teske this->core_limit = this->target->p_limit-> 134*434283fdSDevin Teske pl_rlimit[4].rlim_cur; /* RLIMIT_CORE */ 135*434283fdSDevin Teske 136*434283fdSDevin Teske this->verdict = 137*434283fdSDevin Teske this->core_ign ? "ignored" : 138*434283fdSDevin Teske this->core_catch ? "caught" : 139*434283fdSDevin Teske \`do_coredump == 0 ? "denied by kern.coredump" : 140*434283fdSDevin Teske this->core_sugid && \`sugid_coredump == 0 ? 141*434283fdSDevin Teske "denied by kern.sugid_coredump" : 142*434283fdSDevin Teske this->core_notrace ? "denied by procctl trace ctl" : 143*434283fdSDevin Teske this->core_limit == 0 ? "denied by RLIMIT_CORE" : 144*434283fdSDevin Teske "will dump core"; 145*434283fdSDevin Teske 146*434283fdSDevin Teske $( pproc -P _core "(struct proc *)args[1]" ) 147*434283fdSDevin Teske} 148*434283fdSDevin TeskeEOF 149*434283fdSDevin TeskeACTIONS=$( cat <&9 ) 150*434283fdSDevin TeskeID=$(( $ID + 2 )) 151*434283fdSDevin Teskefi 152*434283fdSDevin Teske 153*434283fdSDevin Teske############################################################ EVENT TAG 154*434283fdSDevin Teske 155*434283fdSDevin Teske# For the running catalog, override the default `UID.GID CMD[PID]: ' tag 156*434283fdSDevin Teske# with ANSI cursor-homing and screen-clearing codes plus column headers. 157*434283fdSDevin Teske 158*434283fdSDevin Teskeif [ "$PROFILE" = "coredump-top" ]; then 159*434283fdSDevin Teskesize=$( stty size 2> /dev/null ) 160*434283fdSDevin Teskerows="${size%% *}" 161*434283fdSDevin Teskecols="${size#* }" 162*434283fdSDevin Teske 163*434283fdSDevin Teskeexec 9<<EOF 164*434283fdSDevin Teske printf("\033[H"); /* Position the cursor at top-left */ 165*434283fdSDevin Teske printf("\033[J"); /* Clear display from cursor to end */ 166*434283fdSDevin Teske 167*434283fdSDevin Teske /* Header line containing probe (left) and date (right) */ 168*434283fdSDevin Teske printf("%-*s%s%Y%s\n", 169*434283fdSDevin Teske $(( ${cols:-80} - 20 )), "$PROBE", 170*434283fdSDevin Teske console ? "\033[32m" : "", 171*434283fdSDevin Teske walltimestamp, 172*434283fdSDevin Teske console ? "\033[39m" : ""); 173*434283fdSDevin Teske 174*434283fdSDevin Teske /* Column headers */ 175*434283fdSDevin Teske printf("%s%8s %-20s %s%s\n", 176*434283fdSDevin Teske console ? "\033[1m" : "", 177*434283fdSDevin Teske "COUNT", 178*434283fdSDevin Teske "EXECNAME", 179*434283fdSDevin Teske "SIGNAL", 180*434283fdSDevin Teske console ? "\033[22m" : ""); 181*434283fdSDevin TeskeEOF 182*434283fdSDevin TeskeEVENT_TAG=$( cat <&9 ) 183*434283fdSDevin Teskefi 184*434283fdSDevin Teske 185*434283fdSDevin Teske############################################################ EVENT DETAILS 186*434283fdSDevin Teske 187*434283fdSDevin Teskeif [ "$PROFILE" = "coredump-top" ]; then 188*434283fdSDevin Teskeexec 9<<EOF 189*434283fdSDevin Teske /* NB: Cumulative; not truncated between updates */ 190*434283fdSDevin Teske printa("%@8u %-20s %s\n", @cores); 191*434283fdSDevin TeskeEOF 192*434283fdSDevin TeskeEVENT_DETAILS=$( cat <&9 ) 193*434283fdSDevin Teskeelif [ ! "$CUSTOM_DETAILS" ]; then 194*434283fdSDevin Teskeexec 9<<EOF 195*434283fdSDevin Teske /* 196*434283fdSDevin Teske * Print coredump-worthy signal details 197*434283fdSDevin Teske */ 198*434283fdSDevin Teske printf("%s[%d] pid %d (%s) -- %s", 199*434283fdSDevin Teske signal_string[this->sig], 200*434283fdSDevin Teske this->sig, 201*434283fdSDevin Teske this->pid, 202*434283fdSDevin Teske this->verdict, 203*434283fdSDevin Teske this->args_core); 204*434283fdSDevin TeskeEOF 205*434283fdSDevin TeskeEVENT_DETAILS=$( cat <&9 ) 206*434283fdSDevin Teskefi 207*434283fdSDevin Teske 208*434283fdSDevin Teske################################################################################ 209*434283fdSDevin Teske# END 210*434283fdSDevin Teske################################################################################ 211