#include #include #include #include #include #include #include #include #include /* Just call "stacktrace();" at key points in your code. * decode sysctl ring buffer later in userland. * I lost that code. write your own and let me know. I cheated and * parsed the output of 'nm /boot/kernel/kernel' to keep it simple. */ #define TRACERECORD 1024 #define TRACEBACK 15 struct stackframe { struct stackframe *link; void *retval; }; struct tracerecord { int nest; void *ra[TRACEBACK]; }; /* 32 bytes per record */ int tracenext = 0; SYSCTL_INT(_kern, OID_AUTO, tracenext, CTLFLAG_RW, &tracenext, 0, ""); int tracesize = TRACERECORD; SYSCTL_INT(_kern, OID_AUTO, tracesize, CTLFLAG_RW, &tracesize, 0, ""); struct tracerecord tracebuffer[TRACERECORD]; static int sysctl_kern_tracebuf(SYSCTL_HANDLER_ARGS) { int error; /* * Unwind the buffer so that it is linear, possibly with initial * nulls at the start. */ error = sysctl_handle_opaque(oidp, &tracebuffer[tracenext], (tracesize - tracenext) * sizeof(struct tracerecord), req); if (error) return error; if (tracenext > 0) { error = sysctl_handle_opaque(oidp, &tracebuffer[0], tracenext * sizeof(struct tracerecord), req); } return error; } SYSCTL_PROC(_kern, OID_AUTO, tracebuf, CTLTYPE_OPAQUE | CTLFLAG_RD, 0, 0, sysctl_kern_tracebuf, "S,tracerecord", ""); int tracecons = 0; SYSCTL_INT(_kern, OID_AUTO, tracecons, CTLFLAG_RW, &tracecons, 0, ""); int traceactive = 0; SYSCTL_INT(_kern, OID_AUTO, traceactive, CTLFLAG_RW, &traceactive, 0, ""); void stacktrace(void) { struct stackframe *frame; int i; if (!traceactive) return; frame = (struct stackframe *)__builtin_frame_address(0); if (tracecons) printf("TRACE:"); for (i = 0; i < TRACEBACK; i++) { if (tracecons) printf(" %p", frame->retval); tracebuffer[tracenext].nest = i + 1; tracebuffer[tracenext].ra[i] = frame->retval; if (tracenext >= TRACERECORD) tracenext = 0; frame = frame->link; if ((u_int32_t)frame < (u_int32_t)KERNBASE) break; } tracenext++; if (tracecons) printf("\n"); } #if 0 void stacktrace_set(struct tracerecord *tr); void stacktrace_set(struct tracerecord *tr) { struct stackframe *frame; int i; frame = (struct stackframe *)__builtin_frame_address(0); for (i = 0; i < TRACEBACK; i++) { tr->nest = i + 1; tr->ra[i] = frame->retval; frame = frame->link; if ((u_int32_t)frame < (u_int32_t)KERNBASE) break; } } #endif