1 #!/bin/sh
   2 
   3 #
   4 # Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
   5 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6 #
   7 # This code is free software; you can redistribute it and/or modify it
   8 # under the terms of the GNU General Public License version 2 only, as
   9 # published by the Free Software Foundation.
  10 #
  11 # This code is distributed in the hope that it will be useful, but WITHOUT
  12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14 # version 2 for more details (a copy is included in the LICENSE file that
  15 # accompanied this code).
  16 #
  17 # You should have received a copy of the GNU General Public License version
  18 # 2 along with this work; if not, write to the Free Software Foundation,
  19 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20 #
  21 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22 # or visit www.oracle.com if you need additional information or have any
  23 # questions.
  24 #
  25 
  26 #
  27 #
  28 # jtreg runs this in a scratch dir.
  29 # It (and runregress -no) sets these env vars:
  30 #    TESTSRC:      The dir that contains this file
  31 #    TESTCLASSES:  Where .class files are compiled to
  32 #    TESTJAVA:     The jdk to run
  33 #
  34 # This is a 'library' script that is included by
  35 # shell script test cases that want to run a .java file as the debuggee
  36 # and use jdb as the debugger.  This file contains
  37 # several functions that support such a test.
  38 
  39 # The caller script can also set these shell vars before
  40 # including this file:
  41 #    pkg=<package name>       To use a package, define it here and put
  42 #                                package $pkg
  43 #                             in your java file
  44 #    classname=<classnam>     Omit this to use the default class name, 'shtest'.
  45 
  46 #    compileOptions=<string>  compile options for at least the first compile, 
  47 #                             eg, compileOptions=-g
  48 #    compileOptions2=<string> Options for the 2nd, ..., compile. compileOptions1
  49 #                             is used if this is not set.  To use no compile
  50 #                             options for the 2nd ... compiles, do 
  51 #                             compileOptions2=none
  52 #
  53 #    mode=-Xcomp or mode=-Xint to run in these modes.  These should not
  54 #                              really be used since the tests are normally
  55 #                              run in both modes.
  56 #    javacCmd=path-to-javac    to use a non-standard javac for compiling
  57 #    compileOptions=<string>   Options to pass to javac
  58 #
  59 # See RedefineException.sh as an example of a caller script.
  60 #
  61 # To do RedefineClasses operations, embed @1 tags in the .java
  62 # file to tell this script how to modify it to produce the 2nd
  63 # version of the .class file to be used in the redefine operation.
  64 # Here are examples of each editting tag and what change
  65 # it causes in the new file.  Note that blanks are not preserved
  66 # in these editing operations.
  67 #
  68 # @1 uncomment
  69 #  orig:   // @1 uncomment   gus = 89;
  70 #  new:         gus = 89;
  71 #
  72 # @1 commentout
  73 #  orig:   gus = 89      // @1 commentout
  74 #  new: // gus = 89      // @1 commentout
  75 #
  76 # @1 delete
  77 #  orig:  gus = 89      // @1 delete
  78 #  new:   entire line deleted
  79 #
  80 # @1 newline
  81 #  orig:  gus = 89;     // @1 newline gus++;
  82 #  new:   gus = 89;     //
  83 #         gus++;
  84 #
  85 # @1 replace
  86 #  orig:  gus = 89;     // @1 replace gus = 90;
  87 #  new:   gus = 90;
  88 #
  89 # The only other tag supported is @1 breakpoint.  The setbkpts function
  90 # sets bkpts at all lines that contain this string.
  91 # 
  92 # Currently, all these tags are start with @1.  It is envisioned that this script
  93 # could be ehanced to allow multiple cycles of redefines by allowing
  94 # @2, @3, ... tags.  IE, processing the @i tags in the ith version of
  95 # the file will produce the i+1th version of the file.
  96 # 
  97 # There are problem with jtreg leaving behind orphan java and jdb processes
  98 # when this script is run.  Sometimes, on some platforms, it just doesn't
  99 # get them all killed properly.
 100 # The solution is to put a magic word in the cmd lines of background java
 101 # and jdb processes this script launches.  We can then do the right kind
 102 # of ps cmds to find all these processes and kill them.  We do this by
 103 # trapping the completion of this script.
 104 #
 105 # An associated problem is that our trap handler (cleanup) doesn't
 106 # always get called when jtreg terminates a test.  This can leave tests
 107 # hanging but following tests should run ok because each test uses
 108 # unique names for the port and temp files (based on the PID returned
 109 # by $$).
 110 #
 111 # mks 6.2a on win 98 presents two problems:
 112 #   $! returns the PID as a negative number whereas ps returns
 113 #      it in the form 0xFFF....  This means our trick of 
 114 #      of using $! to get the PIDs of the jdb and debuggee processes
 115 #      doesn't work.  This will cause some error cases to fail
 116 #      with a jtreg timeout instead of failing more gracefully.
 117 #
 118 #   There is no form of the ps command that will show the whole
 119 #   cmd line.  Thus, the magic keyword trick doesn't work.  We
 120 #   resort to just killing java.exe and jdb.exes
 121 #
 122 # pid usage:
 123 #   debuggeepid: used in jdb process to detect if debuggee has died.
 124 #                - waitForDebuggeeMsg: fail if debuggee is gone
 125 #
 126 #   jdbpid:   dofail: used to detect if in main process or jdb process
 127 #             waitforfinish: quit if the jdb process is gone
 128 
 129 #killcmd=/bin/kill
 130 killcmd=kill
 131 
 132 # This can be increased if timing seems to be an issue.
 133 sleep_seconds=1
 134 
 135 echo "ShellScaffold.sh: Version" >& 2
 136 topPid=$$
 137 
 138 # Be careful to echo to >& in these general functions.
 139 # If they are called from the functions that are sending
 140 # cmds to jdb, then stdout is redirected to jdb.
 141 cleanup()
 142 {
 143     if [ -r "$failFile" ] ; then
 144         ls -l "$failFile" >&2
 145         echo "<cleanup:_begin_failFile_contents>" >&2
 146         cat "$failFile" >&2
 147         echo "<cleanup:_end_failFile_contents>" >&2
 148     fi
 149 
 150     # Kill all processes that have our special
 151     # keyword in their cmd line.
 152     killOrphans cleanup $jdbKeyword
 153     killOrphans cleanup $debuggeeKeyword
 154 }
 155 
 156 # Kill all processes with $2 in their cmd lines
 157 # Print a msg about this using $1 as the prefix
 158 killOrphans()
 159 {
 160     str=$2
 161 
 162     if [ -z "$isCygwin" ] ; then
 163         toBeKilled=`$psCmd | $grep -v grep | $grep -i $str | awk '{print $1}' | tr '\n\r' '  '`
 164     else
 165         # The cygwin ps command doesn't show the options passed to a cmd.
 166         # We will use jps to get the win PID of the command, and
 167         # then use ps to find the cygwin pid to be killed.
 168         # The form of a ps output line is
 169         # ^   ddddd    dddd    dddd    dddd.*
 170         # where the 4th digits are the win pid and the first 
 171         # are the cygwin pid.
 172         if [ -r "$jdk/bin/$jstack" ] ; then
 173             winPid=`$jdk/bin/jps -v | $grep -i $str | sed -e 's@ .*@@'`
 174             if [ ! -z "$winPid" ] ; then
 175                 # Here is a way to kill using a win cmd and the win PID.
 176                 #echo "$1: taskkill /F $winPid"  >& 2
 177                 #taskkill /F /PID $winPid
 178 
 179                 toBeKilled=`$psCmd | $grep -v grep | \
 180                             $grep '^ +[0-9]+ +[0-9]+ +[0-9]+ +'"$winPid" |\
 181                             awk '{print $1}' | tr '\n\r' '  '`
 182             fi
 183         else
 184             # Well, too bad - we can't find what to kill.  
 185             toBeKilled=
 186         fi
 187     fi
 188 
 189     if [ ! -z "$toBeKilled" ] ; then
 190         echo "$1: kill -9 $toBeKilled"  >& 2
 191         kill -9 $toBeKilled
 192     fi
 193 }    
 194 
 195 findPid()
 196 {
 197     # Return 0 if $1 is the pid of a running process.
 198     if [ -z "$isWin98" ] ; then
 199         if [ "$osname" = SunOS ] ; then
 200             # Solaris and OpenSolaris use pgrep and not ps in psCmd
 201             findPidCmd="$psCmd"
 202         elif [ "$osname" = AIX ] ; then
 203             findPidCmd="$psCmd"
 204         else
 205             #   Never use plain 'ps', which requires a "controlling terminal"
 206             #     and will fail  with a "ps: no controlling terminal" error.
 207             #     Running under 'rsh' will cause this ps error.
 208             # cygwin ps puts an I in column 1 for some reason.
 209             findPidCmd="$psCmd -e"
 210         fi
 211         $findPidCmd | $grep '^I* *'"$1 " > $devnull 2>&1
 212         return $?
 213     fi
 214 
 215     # mks 6.2a on win98 has $! getting a negative
 216     # number and in ps, it shows up as 0x...
 217     # Thus, we can't search in ps output for 
 218     # PIDs gotten via $!
 219     # We don't know if it is running or not - assume it is.
 220     # We don't really care about win98 anymore.
 221     return 0
 222 }
 223 
 224 setup()
 225 {
 226     failed=
 227     # This is used to tag each java and jdb cmd we issue so
 228     # we can kill them at the end of the run.
 229 
 230     orphanKeyword=HANGINGJAVA-$$
 231     debuggeeKeyword=${orphanKeyword}_DEB
 232     jdbKeyword=${orphanKeyword}_JDB
 233     baseArgs=-D${debuggeeKeyword}
 234     if [ -z "$TESTCLASSES" ] ; then
 235         echo "--Warning:  TESTCLASSES is not defined; using TESTCLASSES=."
 236         echo "  You should run: "
 237         echo "    runregress $0 -no"
 238         echo "  or"
 239         echo "    (setenv TESTCLASSES .; $0 $*)"
 240         TESTCLASSES=.
 241     fi
 242     if [ ! -z "$TESTJAVA" ] ; then
 243         jdk="$TESTJAVA"
 244     else
 245         echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test."
 246         exit 1
 247     fi
 248     
 249     ulimitCmd=
 250     osname=`uname -s`
 251     isWin98=
 252     isCygwin=
 253     case "$osname" in
 254        Windows* | CYGWIN*)         
 255          devnull=NUL
 256          if [ "$osname" = Windows_98 -o "$osname" = Windows_ME ]; then
 257              isWin98=1
 258              debuggeeKeyword='we_cant_kill_debuggees_on_win98'
 259              jdbKeyword='jdb\.exe'
 260          fi
 261 
 262          case "$osname" in
 263            CYGWIN*)
 264              isCygwin=1
 265              devnull=/dev/null
 266              ;;
 267          esac
 268 
 269          if [ -r $jdk/bin/dt_shmem.dll -o -r $jdk/jre/bin/dt_shmem.dll ] ; then
 270             transport=dt_shmem
 271             address=kkkk.$$
 272          else
 273             transport=dt_socket
 274             address=
 275          fi
 276          baseArgs="$baseArgs -XX:-ShowMessageBoxOnError"
 277          # jtreg puts \\s in TESTCLASSES and some uses, eg. echo
 278          # treat them as control chars on mks (eg \t is tab)
 279          # Oops; windows mks really seems to want this cat line
 280          # to start in column 1
 281          if [ -w "$SystemRoot" ] ; then
 282             tmpFile=$SystemRoot/tmp.$$
 283          elif [ -w "$SYSTEMROOT" ] ; then
 284             tmpFile=$SYSTEMROOT/tmp.$$
 285          else
 286             tmpFile=tmp.$$
 287          fi
 288 cat <<EOF >$tmpFile
 289 $TESTCLASSES
 290 EOF
 291          TESTCLASSES=`cat $tmpFile | sed -e 's@\\\\@/@g'`
 292          rm -f $tmpFile
 293          # on mks
 294          grep=egrep
 295          psCmd=ps
 296          jstack=jstack.exe
 297          ;;
 298        SunOS | Linux | Darwin | AIX)
 299          transport=dt_socket
 300          address=
 301          devnull=/dev/null
 302          grep=egrep
 303          jstack=jstack
 304          # On linux, core files take a long time, and can leave
 305          # zombie processes
 306          if [ "$osname" = SunOS ] ; then
 307              # Experiments show Solaris '/usr/ucb/ps -axwww' and
 308              # '/usr/bin/pgrep -f -l' provide the same small amount of the
 309              # argv string (PRARGSZ=80 in /usr/include/sys/procfs.h)
 310              #  1) This seems to have been working OK in ShellScaffold.
 311              #  2) OpenSolaris does not provide /usr/ucb/ps, so use pgrep
 312              #     instead
 313              # The alternative would be to use /usr/bin/pargs [pid] to get
 314              # all the args for a process, splice them back into one
 315              # long string, then grep.
 316              UU=`/usr/xpg4/bin/id -u -n`
 317              psCmd="pgrep -f -l -U $UU"
 318          else
 319              ulimit -c 0
 320              # See bug 6238593.
 321              psCmd="ps axwww"
 322          fi
 323          ;;
 324        *)
 325          echo "--Error:  Unknown result from 'uname -s':  $osname"
 326          exit 1
 327          ;;
 328     esac
 329 
 330 
 331     tmpFileDir=$TESTCLASSES/aa$$
 332     TESTCLASSES=$tmpFileDir
 333 
 334     mkdir -p $tmpFileDir
 335 
 336     # This must not contain 'jdb' or it shows up
 337     # in grep of ps output for some platforms
 338     jdbOutFile=$tmpFileDir/jxdbOutput.txt
 339     rm -f $jdbOutFile
 340     touch $jdbOutFile
 341 
 342     debuggeeOutFile=$tmpFileDir/debuggeeOutput.txt
 343     failFile=$tmpFileDir/testFailed
 344     debuggeepidFile=$tmpFileDir/debuggeepid
 345     rm -f $failFile $debuggeepidFile
 346     if [ -f "$failFile" ]; then
 347         echo "ERROR: unable to delete existing failFile:" >&2
 348         ls -l "$failFile" >&2
 349     fi
 350 
 351     if [ -z "$pkg" ] ; then
 352         pkgSlash=
 353         pkgDot=
 354         redefineSubdir=.
 355     else
 356         pkgSlash=$pkg/
 357         pkgDot=$pkg.
 358         redefineSubdir=$pkgSlash
 359     fi
 360     if [ -z "$classname" ] ; then
 361         classname=shtest
 362     fi
 363 
 364     if [ -z "$java" ] ; then
 365         java=java
 366     fi
 367 
 368     if [ -z "$jdb" ] ; then
 369         jdb=$jdk/bin/jdb
 370     fi
 371 
 372 ####################################################3
 373 ####################################################3
 374 ####################################################3
 375 ####################################################3
 376 #  sol:  this gets all processes killed but 
 377 #        no jstack
 378 #  linux same as above
 379 #  win mks:  No dice; processes still running
 380     trap "cleanup" 0 1 2 3 4 6 9 10 15
 381     
 382     jdbOptions="$jdbOptions -J-D${jdbKeyword}"
 383 }
 384 
 385 docompile()
 386 {
 387     if [ "$compile" = 0 ] ; then
 388         return
 389     fi
 390     saveDir=`pwd`
 391     cd $tmpFileDir
 392     rm -f *.java
 393     createJavaFile $classname
 394 
 395     # Compile two versions of the file, the original and with the
 396     # indicated lines modified.
 397     cp $classname.java.1 $classname.java
 398     echo "--Compiling first version of `pwd`/$classname.java with options: $compileOptions"
 399     # Result is in $pkgSlash$classname.class
 400     
 401     if [ -z "$javacCmd" ] ; then
 402         javacCmd=$jdk/bin/javac
 403     fi
 404 
 405     echo "compiling " `ls *.java`
 406     $javacCmd $compileOptions -d . *.java
 407     if [ $? != 0 ] ; then
 408        dofail "First compile failed"
 409     fi
 410     if [ -r vers1 ] ; then
 411         rm -rf vers1
 412     fi
 413     mkdir -p vers1
 414     mv *.class vers1
 415     if [ ! -z "$compileOptions2" ] ; then
 416         if [ "$compileOptions2" = none ] ; then
 417             compileOptions=
 418         else
 419             compileOptions=$compileOptions2
 420         fi
 421     fi
 422 
 423     while [ 1 = 1 ] ; do
 424         # Not really a loop; just a way to avoid goto
 425         # by using breaks
 426         sed -e '/@1 *delete/ d' \
 427             -e 's! *// *@1 *uncomment!     !' \
 428             -e 's!\(.*@1 *commentout\)!//\1!' \
 429             -e 's/@1 *newline/\
 430                  /' \
 431             -e 's/.*@1 *replace//' \
 432             $classname.java.1  >$classname.java
 433 
 434         cmp -s $classname.java.1 $classname.java
 435         if [ $? = 0 ] ; then
 436             break
 437         fi
 438         echo 
 439         echo "--Compiling second version of `pwd`/$classname.java with $compileOptions"
 440         $javacCmd $compileOptions -d . $classname.java
 441         if [ $? != 0 ] ; then
 442             dofail "Second compile failed"
 443         fi
 444         if [ -r vers2 ] ; then
 445             rm -rf vers2
 446         fi
 447         mkdir -p vers2
 448         mv *.class vers2
 449         mv $classname.java $classname.java.2
 450         cp $classname.java.1 $classname.java
 451 
 452         ###### Do the same for @2, and @3 allowing 3 redefines to occur.
 453         ###### If I had more time to write sed cmds, I would do
 454         ###### this in a loop.  But, I don't think we will ever need
 455         ###### more than 3 redefines.
 456         sed -e '/@2 *delete/ d' \
 457             -e 's! *// *@2 *uncomment!     !' \
 458             -e 's!\(.*@2 *commentout\)!//\1!' \
 459             -e 's/@2 *newline/\
 460                  /' \
 461             -e 's/.*@2 *replace//' \
 462             $classname.java.2 >$classname.java
 463         cmp -s $classname.java.2 $classname.java
 464         if [ $? = 0 ] ; then
 465             break
 466         fi
 467         echo 
 468         echo "--Compiling third version of `pwd`/$classname.java with $compileOptions"
 469         $javacCmd $compileOptions -d . $classname.java
 470         if [ $? != 0 ] ; then
 471             dofail "Third compile failed"
 472         fi
 473         if [ -r vers3 ] ; then
 474             rm -rf vers3
 475         fi
 476         mkdir -p vers3
 477         mv *.class vers3
 478         mv $classname.java $classname.java.3
 479         cp $classname.java.1 $classname.java
 480 
 481         ########
 482         sed -e '/@3 *delete/ d' \
 483             -e 's! *// *@3 *uncomment!     !' \
 484             -e 's!\(.*@3 *commentout\)!//\1!' \
 485             -e 's/@3 *newline/\
 486                     /' \
 487             -e 's/.*@3 *replace//' \
 488             $classname.java.3 >$classname.java
 489         cmp -s $classname.java.3 $classname.java
 490         if [ $? = 0 ] ; then
 491             break
 492         fi
 493         echo 
 494         echo "--Compiling fourth version of `pwd`/$classname.java with $compileOptions"
 495         $javacCmd $compileOptions -d . $classname.java
 496         if [ $? != 0 ] ; then
 497             dofail "fourth compile failed"
 498         fi
 499         if [ -r vers4 ] ; then
 500             rm -rf vers4
 501         fi
 502         mkdir -p vers4
 503         mv *.class vers4
 504         mv $classname.java $classname.java.4
 505         cp $classname.java.1 $classname.java
 506         break
 507         fgrep @4 $classname.java
 508         if [ $? = 0 ] ; then
 509             echo "--Error: @4 and above are not yet allowed"
 510             exit 1
 511         fi
 512     done
 513 
 514     cp vers1/* $redefineSubdir
 515     cd $saveDir
 516 }
 517 
 518 # Send a cmd to jdb and wait for the jdb prompt to appear.
 519 # We don't want to allow > as a prompt because if the debuggee
 520 # runs for awhile after a command, jdb will show this prompt
 521 # but is not really ready to accept another command for the
 522 # debuggee - ie, a cont in this state will be ignored.
 523 # If it ever becomes necessary to send a jdb command before
 524 # a  main[10] form of prompt appears, then this
 525 # code will have to be modified.
 526 cmd() 
 527 {
 528     if [ $1 = quit -o -r "$failFile" ] ; then
 529         # if jdb got a cont cmd that caused the debuggee
 530         # to run to completion, jdb can be gone before
 531         # we get here.
 532         echo "--Sending cmd: quit" >& 2
 533         echo quit
 534         # See 6562090. Maybe there is a way that the exit
 535         # can cause jdb to not get the quit.
 536         sleep 5
 537 
 538         # The exit code value here doesn't matter since this function
 539         # is called as part of a pipeline and it is not the last command
 540         # in the pipeline.
 541         exit 1
 542     fi
 543     
 544     # $jdbOutFile always exists here and is non empty
 545     # because after starting jdb, we waited 
 546     # for the prompt.
 547     fileSize=`wc -c $jdbOutFile | awk '{ print $1 }'`
 548     echo "--Sending cmd: " $* >&2
 549 
 550     # jjh: We have a few intermittent failures here.
 551     # It is as if every so often, jdb doesn't
 552     # get the first cmd that is sent to it here.  
 553     # (actually, I have seen it get the first cmd ok,
 554     # but then not get some subsequent cmd).
 555     # It seems like jdb really doesn't get the cmd; jdb's response
 556     # does not appear in the jxdboutput file. It contains:
 557     # main[1] 
 558     # The application has been disconnected
 559 
 560     # Is it possible
 561     # that jdb got the cmd ok, but its response didn't make
 562     # it to the jxdboutput file?  If so, why did 'The application
 563     # has been disconnected' make it?
 564 
 565     # This causes the following loop to timeout and the test to fail.
 566     # The above echo works because the cmd (stop at ...)
 567     # is in the System.err shown in the .jtr file.
 568     # Also, the cmd is shown in the 'jdb never responded ...'
 569     # msg output below after the timeout.
 570     # And, we know jdb is started because the main[1] output is in the .jtr
 571     # file.  And, we wouldn't have gotten here if mydojdbcmds hadn't
 572     # seen the ].  
 573     echo $*
 574 
 575     # Now we have to wait for the next jdb prompt.  We wait for a pattern
 576     # to appear in the last line of jdb output.  Normally, the prompt is
 577     #
 578     # 1) ^main[89] @
 579     #
 580     # where ^ means start of line, and @ means end of file with no end of line
 581     # and 89 is the current command counter. But we have complications e.g.,
 582     # the following jdb output can appear:
 583     #
 584     # 2) a[89] = 10
 585     #
 586     # The above form is an array assignment and not a prompt.
 587     #
 588     # 3) ^main[89] main[89] ...
 589     #
 590     # This occurs if the next cmd is one that causes no jdb output, e.g.,
 591     # 'trace methods'.
 592     #
 593     # 4) ^main[89] [main[89]] .... > @
 594     #
 595     # jdb prints a > as a prompt after something like a cont.
 596     # Thus, even though the above is the last 'line' in the file, it
 597     # isn't the next prompt we are waiting for after the cont completes.
 598     # HOWEVER, sometimes we see this for a cont command:
 599     #
 600     #   ^main[89] $
 601     #      <lines output for hitting a bkpt>
 602     #
 603     # 5) ^main[89] > @
 604     #
 605     # i.e., the > prompt comes out AFTER the prompt we we need to wait for.
 606     #
 607     # So, how do we know when the next prompt has appeared??
 608     # 1.  Search for 
 609     #         main[89] $
 610     #     This will handle cases 1, 2, 3
 611     # 2.  This leaves cases 4 and 5.
 612     #
 613     # What if we wait for 4 more chars to appear and then search for
 614     #
 615     #    main[89] [>]$
 616     #
 617     # on the last line?
 618     #
 619     # a.  if we are currently at
 620     #
 621     #       ^main[89] main[89] @
 622     #
 623     #     and a 'trace methods comes in, we will wait until at least
 624     #
 625     #       ^main[89] main[89] main@
 626     #
 627     #     and then the search will find the new prompt when it completes.
 628     #
 629     # b.  if we are currently at
 630     #
 631     #       ^main[89] main[89] @
 632     #
 633     #     and the first form of cont comes in, then we will see
 634     #
 635     #       ^main[89] main[89] > $
 636     #       ^x@
 637     #
 638     #     where x is the first char of the msg output when the bkpt is hit
 639     #     and we will start our search, which will find the prompt
 640     #     when it comes out after the bkpt output, with or without the
 641     #     trailing >
 642     #
 643 
 644     # wait for 4 new chars to appear in the jdb output
 645     count=0
 646     desiredFileSize=`expr $fileSize + 4`
 647     msg1=`echo At start: cmd/size/waiting : $* / $fileSize / \`date\``
 648     while [ 1 = 1 ] ; do
 649         newFileSize=`wc -c $jdbOutFile | awk '{ print $1 } '`
 650         #echo jj: desired = $desiredFileSize, new = $newFileSize >& 2
 651 
 652         done=`expr $newFileSize \>= $desiredFileSize`
 653         if [ $done = 1 ] ; then
 654             break
 655         fi
 656         sleep ${sleep_seconds}
 657         count=`expr $count + 1`
 658         if [ $count = 30 -o $count = 60 ] ; then
 659             # record some debug info.
 660             echo "--DEBUG: jdb $$ didn't responded to command in $count secs: $*" >& 2
 661             echo "--DEBUG:" $msg1 >& 2
 662             echo "--DEBUG: "done size/waiting : / $newFileSize  / `date` >& 2
 663             echo "-- $jdbOutFile follows-------------------------------" >& 2
 664             cat $jdbOutFile >& 2
 665             echo "------------------------------------------" >& 2
 666             dojstack
 667             #$psCmd | sed -e '/com.sun.javatest/d' -e '/nsk/d' >& 2
 668             if [ $count = 60 ] ; then
 669                 dofail "jdb never responded to command: $*"
 670             fi
 671         fi
 672     done
 673     # Note that this assumes just these chars in thread names.
 674     waitForJdbMsg '[a-zA-Z0-9_-][a-zA-Z0-9_-]*\[[1-9][0-9]*\] [ >]*$' \
 675         1 allowExit
 676 }
 677 
 678 setBkpts()
 679 {
 680     # Can set multiple bkpts, but only in one class.
 681     # $1 is the bkpt name, eg, @1
 682     allLines=`$grep -n "$1 *breakpoint" $tmpFileDir/$classname.java.1 | sed -e 's@^\([0-9]*\).*@\1@g'`
 683     for ii in $allLines ; do
 684         cmd stop at $pkgDot$classname:$ii
 685     done
 686 }
 687 
 688 runToBkpt()
 689 {
 690     cmd run
 691     # Don't need to do this - the above waits for the next prompt which comes out
 692     # AFTER the Breakpoint hit message.
 693     # Wait for jdb to hit the bkpt
 694     #waitForJdbMsg "Breakpoint hit" 5
 695 }
 696 
 697 contToBkpt()
 698 {
 699     cmd cont
 700     # Don't need to do this - the above waits for the next prompt which comes out
 701     # AFTER the Breakpoint hit message.
 702     # Wait for jdb to hit the bkpt
 703     #waitForJdbMsg "Breakpoint hit" 5
 704 }
 705 
 706 
 707 # Wait until string $1 appears in the output file, within the last $2 lines
 708 # If $3 is allowExit, then don't fail if jdb exits before
 709 # the desired string appears.
 710 waitForJdbMsg()
 711 {
 712     # This can be called from the jdb thread which doesn't
 713     # have access to $debuggeepid, so we have to read it from the file.
 714     nlines=$2
 715     allowExit="$3"
 716     myCount=0
 717     timeLimit=40  # wait a max of this many secs for a response from a jdb command
 718     while [ 1 = 1 ] ; do 
 719         if [  -r $jdbOutFile ] ; then
 720             # Something here causes jdb to complain about Unrecognized cmd on x86.
 721             tail -$nlines $jdbOutFile | $grep -s "$1" > $devnull 2>&1
 722             if [ $? = 0 ] ; then
 723                 # Found desired string
 724                 break
 725             fi
 726         fi
 727         tail -2 $jdbOutFile | $grep -s "The application exited" > $devnull 2>&1
 728         if [ $? = 0 ] ; then
 729             # Found 'The application exited'
 730             if [ ! -z "$allowExit" ] ; then
 731                 break
 732             fi
 733             # Otherwise, it is an error if we don't find $1
 734             if [  -r $jdbOutFile ] ; then 
 735                 tail -$nlines $jdbOutFile | $grep -s "$1" > $devnull 2>&1             
 736                 if [ $? = 0 ] ; then
 737                    break
 738                 fi
 739             fi
 740             dofail "Waited for jdb msg $1, but it never appeared"                   
 741         fi
 742 
 743         sleep ${sleep_seconds}
 744         findPid $topPid
 745         if [ $? != 0 ] ; then
 746             # Top process is dead.  We better die too
 747             dojstack
 748             exit 1
 749         fi
 750 
 751         myCount=`expr $myCount + ${sleep_seconds}`
 752         if [ $myCount -gt $timeLimit ] ; then
 753             echo "--Fail: waitForJdbMsg timed out after $timeLimit seconds, looking for /$1/, in $nlines lines; exitting" >> $failFile
 754             echo "vv jdbOutFile  vvvvvvvvvvvvvvvvvvvvvvvvvvvv" >& 2
 755             cat $jdbOutFile >& 2
 756             echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" >& 2
 757             dojstack
 758             exit 1
 759         fi
 760     done
 761 
 762 }
 763 
 764 # $1 is the string to print.  If $2 exists,
 765 # it is the name of a file to print, ie, the name
 766 # of the file that contains the $1 string.
 767 dofail()
 768 {
 769     if [ ! -z "$jdbpid" ] ; then
 770         # we are in the main process instead of the jdb process
 771         echo " " >> $failFile
 772         echo "--Fail: main: $*" >> $failFile
 773     else
 774         # Kill the debuggee ; it could be hung so
 775         # we want to get rid of it as soon as possible.
 776         killOrphans "killing debuggee" $debuggeeKeyword
 777 
 778         echo " "  >>$failFile
 779         echo "--Fail: $*" >> $failFile
 780         echo quit
 781     fi
 782     if [ ! -z "$2" ] ; then
 783         echo  "---- contents of $2 follows -------" >> $failFile
 784         cat "$2" >> $failFile
 785         echo "---------------" >>$failFile
 786     fi
 787     exit 1
 788 }
 789 
 790 
 791 redefineClass() 
 792 {
 793     if [ -z "$1" ] ; then
 794         vers=2
 795     else
 796         vers=`echo $1 | sed -e 's/@//'`
 797         vers=`expr $vers + 1`
 798     fi
 799         
 800     cmd redefine $pkgDot$classname $tmpFileDir/vers$vers/$classname.class
 801 
 802     cp $tmpFileDir/$classname.java.$vers \
 803        $tmpFileDir/$classname.java
 804 }
 805 
 806 mydojdbCmds()
 807 {
 808    # Wait for jdb to start before we start sending cmds
 809    waitForJdbMsg ']' 1
 810    dojdbCmds
 811    cmd quit
 812 }
 813 
 814 startJdb()
 815 {
 816     if [ ! -r "$jdb" -a ! -r "$jdb.exe" ] ; then
 817         dofail "$jdb does not exist"
 818     fi
 819     echo
 820     echo "--Starting jdb, address=$address"
 821     if [ -z "$address" ] ; then
 822        # Let jdb choose the port and write it to stdout
 823        mydojdbCmds | $jdb $jdbOptions -listenany | tee $jdbOutFile &
 824 
 825        while [ 1 ] ; do
 826            lastLine=`$grep 'Listening at address' $jdbOutFile`
 827            if [ ! -z "$lastLine" ] ; then
 828                break
 829            fi
 830            sleep 1
 831        done
 832        # jjh: we got the address ok, and seemed to start the debuggee
 833        address=`echo $lastLine | sed -e 's@.*: *@@'`
 834     else
 835        mydojdbCmds | $jdb $jdbOptions -listen $address | tee $jdbOutFile &
 836     fi
 837     #echo address = $address
 838 
 839 
 840     # this gets the pid of tee, at least it does on solaris
 841     jdbpid=$!
 842 
 843     # This fails on linux because there is an entry for each thread in jdb
 844     # so we get a list of numbers in jdbpid
 845     # jdbpid=`$psCmd | $grep -v grep | $grep ${orphanKeyword}_JDB | awk '{print $1}'  | tr '\n\r' '  '`
 846 }
 847 
 848 startDebuggee()
 849 {
 850     args=
 851     # Note that @debuggeeVMOptions is unique to a test run instead of
 852     # a test in a run.  It is not modified during a test run.
 853     if [ -r $TESTCLASSES/../@debuggeeVMOptions ] ; then
 854        args=`cat $TESTCLASSES/../@debuggeeVMOptions`
 855     fi
 856     
 857     if [ ! -z "$args" ] ; then
 858        echo "--Starting debuggee with args from @debuggeeVMOptions: $args"
 859     else
 860        echo "--Starting debuggee"
 861     fi
 862 
 863     debuggeepid=
 864     waitForJdbMsg Listening 4
 865 
 866     beOption="-agentlib:jdwp=transport=$transport,address=$address,server=n,suspend=y"
 867 #   beOption="-Xdebug -Xrunjdwp:transport=$transport,address=$address,server=n,suspend=y"
 868 
 869     thecmd="$jdk/bin/$java $mode -classpath $tmpFileDir $baseArgs $args \
 870             -Djtreg.classDir=$TESTCLASSES \
 871             -showversion \
 872              $beOption \
 873              $pkgDot$classname"
 874     echo "Cmd: $thecmd"
 875 
 876     sh -c "$thecmd | tee $debuggeeOutFile" &
 877 
 878     # Note that the java cmd and the tee cmd will be children of
 879     # the sh process.  We can use that to find them to kill them.
 880     debuggeepid=$!
 881 
 882     # Save this in a place where the jdb process can find it.
 883     # Note that it is possible for the java cmd to abort during startup
 884     # due to a bad classpath or whatever.
 885     echo $debuggeepid > $debuggeepidFile
 886 }
 887 
 888 dojstack()
 889 {
 890     if [ -r "$jdk/bin/$jstack" ] ; then
 891         # If jstack exists, so will jps
 892         # Show stack traces of jdb and debuggee as a possible debugging aid.
 893         jdbCmd=`$jdk/bin/jps -v | $grep $jdbKeyword`
 894         realJdbPid=`echo "$jdbCmd" | sed -e 's@ TTY.*@@'`
 895         if [ ! -z "$realJdbPid" ] ; then
 896             echo "-- jdb process info ----------------------" >&2
 897             echo "      $jdbCmd"                              >&2
 898             echo "-- jdb threads: jstack $realJdbPid"         >&2
 899             $jdk/bin/$jstack $realJdbPid                      >&2
 900             echo "------------------------------------------" >&2
 901             echo                                              >&2
 902         fi
 903         debuggeeCmd=`$jdk/bin/jps -v | $grep $debuggeeKeyword`
 904         realDebuggeePid=`echo "$debuggeeCmd" | sed -e 's@ .*@@'`
 905         if [ ! -z "$realDebuggeePid" ] ; then
 906             if [ -r "$jdk/lib/sa-jdi.jar" ] ; then
 907                 # disableVersionCheck can be removed after 6475822
 908                 # is fixed.
 909                 moption="-m -J-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck"
 910             else
 911                 moption=
 912             fi
 913 
 914             echo "-- debuggee process info ----------------------" >&2
 915             echo "      $debuggeeCmd"                              >&2
 916             echo "-- debuggee threads: jstack $moption $realDebuggeePid" >&2
 917             $jdk/bin/$jstack $moption $realDebuggeePid             >&2
 918             echo "============================================="   >&2
 919             echo                                                   >&2
 920         fi
 921     fi
 922 }
 923 
 924 waitForFinish()
 925 {
 926     # This is the main process
 927     # Wait for the jdb process to finish, or some error to occur
 928 
 929     while [ 1 = 1 ] ; do
 930         findPid $jdbpid
 931         if [ $? != 0 ] ; then
 932             break
 933         fi
 934         if [ ! -z "$isWin98" ] ; then
 935            $psCmd | $grep -i 'JDB\.EXE' >$devnull 2>&1 
 936            if [ $? != 0 ] ; then
 937                break;
 938            fi
 939         fi
 940         $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1
 941         if [ $? = 0 ] ; then
 942             #something went wrong
 943             dofail "jdb input stream closed prematurely"
 944         fi
 945 
 946         # If a failure has occured, quit
 947         if [ -r "$failFile" ] ; then
 948             break
 949         fi
 950 
 951         sleep ${sleep_seconds}
 952     done
 953 
 954     if [ -r "$failFile" ] ; then
 955         ls -l "$failFile" >&2
 956         echo "<waitForFinish:_begin_failFile_contents>" >&2
 957         cat "$failFile" >&2
 958         echo "<waitForFinish:_end_failFile_contents>" >&2
 959         exit 1
 960     fi
 961 }
 962 
 963 # $1 is the filename, $2 is the string to look for,
 964 # $3 is the number of lines to search (from the end)
 965 grepForString()
 966 {
 967     if [ -z "$3" ] ; then
 968         theCmd=cat
 969     else
 970         theCmd="tail -$3"
 971     fi
 972 
 973     case "$2" in 
 974     *\>*)
 975         # Target string contains a '>' so we better not ignore it
 976         $theCmd $1 | $grep -s "$2"  > $devnull 2>&1
 977         stat="$?"
 978         ;;
 979     *)
 980         # Target string does not contain a '>'.
 981         # NOTE:  if $1 does not end with a new line, piping it to sed
 982         # doesn't include the chars on the last line.  Detect this
 983         # case, and add a new line.
 984         theFile="$1"
 985         if [ `tail -1 "$theFile" | wc -l | sed -e 's@ @@g'` = 0 ] ; then
 986             # The target file doesn't end with a new line so we have
 987             # add one to a copy of the target file so the sed command
 988             # below can filter that last line.
 989             cp "$theFile" "$theFile.tmp"
 990             theFile="$theFile.tmp"
 991             echo >> "$theFile"
 992         fi
 993 
 994         # See bug 6220903. Sometimes the jdb prompt chars ('> ') can
 995         # get interleaved in the target file which can keep us from
 996         # matching the target string.
 997         $theCmd "$theFile" | sed -e 's@> @@g' -e 's@>@@g' \
 998             | $grep -s "$2" > $devnull 2>&1
 999         stat=$?
1000         if [ "$theFile" != "$1" ]; then
1001             # remove the copy of the target file
1002             rm -f "$theFile"
1003         fi
1004         unset theFile
1005     esac
1006     return $stat
1007 }
1008 
1009 # $1 is the filename, $2 is the regexp to match and return,
1010 # $3 is the number of lines to search (from the end)
1011 matchRegexp()
1012 {
1013     if [ -z "$3" ] ; then
1014         theCmd=cat
1015     else
1016         theCmd="tail -$3"
1017     fi
1018 
1019     case "$2" in 
1020     *\>*)
1021         # Target string contains a '>' so we better not ignore it
1022         res=`$theCmd $1 | sed -e "$2"`
1023         ;;
1024     *)
1025         # Target string does not contain a '>'.
1026         # NOTE:  if $1 does not end with a new line, piping it to sed
1027         # doesn't include the chars on the last line.  Detect this
1028         # case, and add a new line.
1029         theFile="$1"
1030         if [ `tail -1 "$theFile" | wc -l | sed -e 's@ @@g'` = 0 ] ; then
1031             # The target file doesn't end with a new line so we have
1032             # add one to a copy of the target file so the sed command
1033             # below can filter that last line.
1034             cp "$theFile" "$theFile.tmp"
1035             theFile="$theFile.tmp"
1036             echo >> "$theFile"
1037         fi
1038 
1039         # See bug 6220903. Sometimes the jdb prompt chars ('> ') can
1040         # get interleaved in the target file which can keep us from
1041         # matching the target string.
1042         res=`$theCmd "$theFile" | sed -e 's@> @@g' -e 's@>@@g' \
1043             | sed -e "$2"`
1044         if [ "$theFile" != "$1" ]; then
1045             # remove the copy of the target file
1046             rm -f "$theFile"
1047         fi
1048         unset theFile
1049     esac
1050     return $res
1051 }
1052 
1053 # $1 is the filename, $2 is the string to look for,
1054 # $3 is the number of lines to search (from the end)
1055 failIfPresent()
1056 {
1057     if [ -r "$1" ] ; then
1058         grepForString "$1" "$2" "$3"
1059         if [ $? = 0 ] ; then
1060             dofail "Error output found: \"$2\" in $1" $1
1061         fi
1062     fi
1063 }
1064 
1065 # $1 is the filename, $2 is the string to look for
1066 # $3 is the number of lines to search (from the end)
1067 failIfNotPresent()
1068 {
1069     if [ ! -r "$1" ] ; then
1070         dofail "Required output \"$2\" not found in $1"
1071     fi
1072     grepForString "$1" "$2" "$3"
1073     if [ $? != 0 ] ; then
1074         dofail "Required output \"$2\" not found in $1" $1
1075     fi
1076 
1077 }
1078 
1079 # fail if $1 is not in the jdb output
1080 # $2 is the number of lines to search (from the end)
1081 jdbFailIfNotPresent()
1082 {
1083     failIfNotPresent $jdbOutFile "$1" $2
1084 }
1085 
1086 # fail if $1 is not in the debuggee output
1087 # $2 is the number of lines to search (from the end)
1088 debuggeeFailIfNotPresent()
1089 {
1090     failIfNotPresent $debuggeeOutFile "$1" $2
1091 }
1092 
1093 # fail if $1 is in the jdb output
1094 # $2 is the number of lines to search (from the end)
1095 jdbFailIfPresent()
1096 {
1097     failIfPresent $jdbOutFile "$1" $2
1098 }
1099 
1100 # fail if $1 is in the debuggee output
1101 # $2 is the number of lines to search (from the end)
1102 debuggeeFailIfPresent()
1103 {
1104     failIfPresent $debuggeeOutFile "$1" $2
1105 }
1106 
1107 # match and return the output from the regexp $1 in the debuggee output
1108 # $2 is the number of lines to search (from the end)
1109 debuggeeMatchRegexp()
1110 {
1111     matchRegexp $debuggeeOutFile "$1" $2
1112 }
1113 
1114 
1115 # This should really be named 'done' instead of pass.
1116 pass()
1117 {
1118     if [ ! -r "$failFile" ] ; then
1119         echo
1120         echo "--Done: test passed"
1121         exit 0
1122     else
1123         ls -l "$failFile" >&2
1124         echo "<pass:_begin_failFile_contents>" >&2
1125         cat "$failFile" >&2
1126         echo "<pass:_end_failFile_contents>" >&2
1127     fi
1128 }
1129 
1130 runit()
1131 {
1132     setup
1133     runitAfterSetup
1134 }
1135 
1136 runitAfterSetup()
1137 {
1138     docompile
1139     startJdb 
1140     startDebuggee
1141     waitForFinish
1142 
1143     # in hs_err file from 1.3.1
1144     debuggeeFailIfPresent "Virtual Machine Error"
1145 
1146     # in hs_err file from 1.4.2, 1.5:  An unexpected error
1147     debuggeeFailIfPresent "An unexpected error"
1148 
1149     # in hs_err file from 1.4.2, 1.5:  Internal error
1150     debuggeeFailIfPresent "Internal error"
1151 
1152 
1153     # Don't know how this arises
1154     debuggeeFailIfPresent "An unexpected exception"
1155 
1156     # Don't know how this arises
1157     debuggeeFailIfPresent "Internal exception"
1158 }
1159 
1160