#!/bin/ksh -p # Wrapper to do libumem memory debugging on given command. # can also be used to set current env. for mem. debug usage() { cat <<-EOF Usage $me [[-l|-f|-m][-v]|[-w ] command (and command args) Usage $me [-l|-f|-m][-v] -e Usage $me [-l|-f|-m][-v] -S " SMF_service" Catch memory problems with either watchmalloc or libumen lib depending on flags. By default $me uses libumem. -e set current environment, must be sourced by ksh compat shell like so . -e -f Firewall: every object >= minbytes in size will have its end against an unmapped page. Good for catching read or write past buffer errors. Does slow down execution significantly. -l leak checking using libumem. -m MBTF: the mean time between injected alloc failures. Works best if the argument is a prime number. -S " " Add libumem debug settings to SMF service (good for daemons started by SMF). -v set verbose arg to libumem, output to stderr. -w use watchmalloc to catch just write past buffer or read and write past buffer (very slow). Default debug level (no flags): catch write errors with libumem. For more info: "man umem_debug" Use 'echo ::findleaks|mdb -nostop -p ' to see leak report or Use 'echo ::findleaks|mdb core' (hint: gcore can produce core dump) then use: echo '000cb608::bufctl_audit' | mdb -nostop -p ' or echo '000cb608::bufctl_audit' | mdb core to see the stack trace where the leak allocation took place (Note, LEAKED is the number of times a leak occurred). echo ::umem_status|mdb core to see umem status for user space core when debugging with libumem. echo ::umalog|mdb core to see umem transaction log and stack traces. Do 'echo ::dcmds|mdb core|grep umem' to see other umem cmds. EOF return 1 } me=${0##*/} orig_ld_preload="$LD_PRELOAD" LD_PRELOAD="libumem.so.1 $orig_ld_preload" export LD_PRELOAD #UMEM_LOGGING='transaction=1M'; export UMEM_LOGGING UMEM_DEBUG='audit,contents,guards' export UMEM_DEBUG unset MALLOC_DEBUG leakcheck=false set_env=false do_svc=false verbose=false while getopts :ef:lm:S:vw: arg do case $arg in e) set_env=true ;; f) # libumem firewall LD_PRELOAD="libumem.so.1 $orig_ld_preload" UMEM_DEBUG="audit,firewall=$OPTARG,guards" ;; l) # libumem supports leak checking LD_PRELOAD="libumem.so.1 $orig_ld_preload" UMEM_LOGGING='transaction=1M,contents' UMEM_DEBUG='audit,contents,guards' export UMEM_LOGGING leakcheck=true ;; m) # libumem mean time between failure LD_PRELOAD="libumem.so.1 $orig_ld_preload" UMEM_DEBUG="audit,mtbf=$OPTARG,guards" export UMEM_DEBUG ;; S) S_args="$OPTARG" do_svc=true ;; v) verbose=true UMEM_DEBUG="$UMEM_DEBUG,verbose" ;; w) # use watchmalloc LD_PRELOAD="watchmalloc.so.1 $orig_ld_preload" case "$OPTARG" in r) # watch for read/write past buffer errors export MALLOC_DEBUG="RW";; w) # watch for write past buffer errors export MALLOC_DEBUG="WATCH";; esac ;; *) usage; return ;; esac done shift OPTIND-1 if $set_env then unset leakcheck set_env orig_ld_preload return 0 fi if $do_svc then print $S_args|read action service case $action in set) if $leakcheck then # unset just in case svccfg -s $service unsetenv LD_PRELOAD svccfg -s $service unsetenv UMEM_LOGGING svccfg -s $service unsetenv UMEM_DEBUG svccfg -s $service setenv LD_PRELOAD libumem.so.1 if svccfg -s $service listprop | grep '^start/environment' > /dev/null 2>&1 then # special svccfg workaround because svccfg parsing of = sucks (bug 6250426) svccfg -s $service 'addpropvalue start/environment astring: "UMEM_LOGGING=transaction=1M"' elif svccfg -s $service listprop | grep '^inetd_start/environment' > /dev/null 2>&1 then svccfg -s $service 'addpropvalue inetd_start/environment astring: "UMEM_LOGGING=transaction=1M"' else svccfg -s $service unsetenv LD_PRELOAD print -u2 "Error: could not find either a start or inetd_start SMF property for the $service service, aborting..." return 1 fi if $verbose then svccfg -s $service setenv UMEM_DEBUG audit,contents,guards,verbose else svccfg -s $service setenv UMEM_DEBUG audit,contents,guards fi else # default, libumem write checking svccfg -s $service unsetenv LD_PRELOAD svccfg -s $service unsetenv UMEM_DEBUG svccfg -s $service setenv LD_PRELOAD libumem.so.1 if $verbose then svccfg -s $service setenv UMEM_DEBUG guards,verbose else svccfg -s $service setenv UMEM_DEBUG guards fi fi ;; unset) if $leakcheck then svccfg -s $service unsetenv LD_PRELOAD svccfg -s $service unsetenv UMEM_LOGGING svccfg -s $service unsetenv UMEM_DEBUG else # default, libumem write checking svccfg -s $service unsetenv LD_PRELOAD svccfg -s $service unsetenv UMEM_DEBUG fi ;; *) print -u2 "Usage error: $action specified, must be either set or unset." return 1 ;; esac # Must refresh (and the service must be restarted) for the change to be used svcadm refresh $service print "Remember to: 'svcadm restart $service' for changes to take effect." return fi # exec command exec "$@"