1 #!/usr/bin/ksh
   2 #
   3 #
   4 # This file and its contents are supplied under the terms of the
   5 # Common Development and Distribution License ("CDDL"), version 1.0.
   6 # You may only use this file in accordance with the terms of version
   7 # 1.0 of the CDDL.
   8 #
   9 # A full copy of the text of the CDDL should have accompanied this
  10 # source.  A copy of the CDDL is also available via the Internet at
  11 # http://www.illumos.org/license/CDDL.
  12 #
  13 
  14 #
  15 # Copyright 2023 Oxide Computer Company
  16 #
  17 
  18 #
  19 # This test attempts to verify that we can mdb (via libproc / thread_db)
  20 # and xregs sees the expected extended register set. It also ensures
  21 # that the same values are visible via a core file from that process at
  22 # the same point.
  23 #
  24 
  25 unalias -a
  26 set -o pipefail
  27 export LANG=C.UTF-8
  28 
  29 mx_exit=0
  30 mx_arg0="$(basename $0)"
  31 mx_dir="$(dirname $0)"
  32 mx_data="$mx_dir/data"
  33 mx_tmpdir="/tmp/mdb_xregs.$$"
  34 
  35 typeset -A mx_seed
  36 mx_seed["32"]=0x12900922
  37 mx_seed["64"]=0x11900456
  38 typeset -A mx_hwtype
  39 mx_hwtype["32"]="$mx_dir/xsu_hwtype.32"
  40 mx_hwtype["64"]="$mx_dir/xsu_hwtype.64"
  41 typeset -A mx_setprog
  42 mx_setprog["32"]="$mx_dir/xregs_set.32"
  43 mx_setprog["64"]="$mx_dir/xregs_set.64"
  44 
  45 warn()
  46 {
  47         typeset msg="$*"
  48         echo "TEST FAILED: $msg" >&2
  49         mx_exit=1
  50 }
  51 
  52 fatal()
  53 {
  54         typeset msg="$*"
  55         [[ -z "$msg" ]] && msg="failed"
  56         echo "$mx_arg0: $msg" >&2
  57         exit 1
  58 }
  59 
  60 cleanup()
  61 {
  62         [[ -n "$mx_tmpdir" ]] && rm -rf "$mx_tmpdir"
  63 }
  64 
  65 setup()
  66 {
  67         if ! mkdir $mx_tmpdir; then
  68                 fatal "failed to create temporary directory: $mx_tmpdir"
  69         fi
  70 }
  71 
  72 check_file()
  73 {
  74         typeset src="$1"
  75         typeset act="$2"
  76         typeset desc="$3"
  77 
  78         if [[ ! -f "$act" ]]; then
  79                 warn "failed to generate $act"
  80                 return
  81         fi
  82 
  83         if ! diff -q $src $act; then
  84                 diff -u $src $act
  85                 warn "$desc: $act did not match expected output"
  86         else
  87                 printf "TEST PASSED: %s\n" "$desc"
  88         fi
  89 }
  90 
  91 #
  92 # Run one instance of mdb to grab and get our first pass data files
  93 # against a real process. We're not really counting on our exit status
  94 # from mdb here, mostly on whether or not the generated files all exist
  95 # in the end. We gather data from the generated cores in a separate run.
  96 #
  97 run_live_mdb()
  98 {
  99         typeset prog="$1"
 100         typeset seed="$2"
 101         typeset fpregs="$3"
 102         typeset core="$4"
 103         typeset coreloc="$5"
 104 
 105         mdb $prog <<EOF
 106 yield::bp
 107 ::run $seed
 108 ::tmodel lwp
 109 ::fpregs ! cat > $fpregs.lwp
 110 ::tmodel thread
 111 ::fpregs ! cat > $fpregs.thread
 112 _uberdata::printf "$core.%u" uberdata_t pid ! cat > $coreloc
 113 ::gcore -o $core
 114 ::kill
 115 \$q
 116 EOF
 117 }
 118 
 119 #
 120 # We've been given a core file that matches something we just ran above. We
 121 # should be able to read the ::fpregs from it and get the exact same data.
 122 #
 123 check_core()
 124 {
 125         typeset core="$1"
 126         typeset output="$2"
 127         typeset check="$3"
 128 
 129         if ! mdb -e "::fpregs ! cat > $output" $core; then
 130                 warn "mdb failed to get ::fpregs from $core"
 131                 return
 132         fi
 133 
 134         check_file $check $output "extracted core matches"
 135 }
 136 
 137 run_one_isa()
 138 {
 139         typeset isa="$1"
 140         typeset target=${mx_setprog[$isa]}
 141         typeset hwprog=${mx_hwtype[$isa]}
 142         typeset seed=${mx_seed[$isa]}
 143         typeset coreloc="$mx_tmpdir/coreloc"
 144         typeset fpu_type=
 145         typeset corename=
 146         typeset fpregs=
 147         typeset check=
 148 
 149         if ! fpu_type=$($hwprog 2>/dev/null); then
 150                 warn "failed to determine $isa-bit FPU type"
 151                 return
 152         fi
 153 
 154         printf "Discovered FPU: %s %s-bit\n" $fpu_type $isa
 155         corename="$mx_tmpdir/core.$fpu_type.$isa"
 156         fpregs="$mx_tmpdir/fpregs.$fpu_type.$isa"
 157         check="$mx_data/mdb_xregs.$fpu_type.$isa"
 158 
 159         run_live_mdb $target $seed $fpregs $corename $coreloc
 160         check_file "$check" "$fpregs.lwp" "$isa-bit $fpu_type ::fpregs (lwp)"
 161         check_file "$check" "$fpregs.lwp" "$isa-bit $fpu_type ::fpregs (thread)"
 162 
 163         if [[ ! -f "$coreloc" ]]; then
 164                 warn "missing core file location file, cannot run core tests"
 165                 return
 166         fi
 167 
 168         typeset -i ncores=0
 169         for f in $(cat $coreloc); do
 170                 ((ncores++))
 171                 if [[ ! -f "$f" ]]; then
 172                         warn "core file location $f is not a file"
 173                         continue
 174                 fi
 175 
 176                 check_core "$f" "$mx_tmpdir/fpregs.core" $check
 177         done
 178 
 179         if ((ncores == 0)); then
 180                 warn "No core files found!"
 181         fi
 182 }
 183 
 184 setup
 185 trap 'cleanup' EXIT
 186 
 187 run_one_isa "32"
 188 run_one_isa "64"
 189 
 190 exit $mx_exit