1 #!/bin/sh
   2 
   3 #
   4 # Copyright (c) 2002, 2017, 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 timeout_factor=1
 135 if [ -n "$TESTTIMEOUTFACTOR" ] ; then
 136   # convert float value to int
 137   timeout_factor=$(echo $TESTTIMEOUTFACTOR | awk '{printf "%d\n", int($1)}')
 138 fi
 139 
 140 echo "ShellScaffold.sh: Running with timeout_factor = $timeout_factor" >& 2
 141 topPid=$$
 142 
 143 # Be careful to echo to >& in these general functions.
 144 # If they are called from the functions that are sending
 145 # cmds to jdb, then stdout is redirected to jdb.
 146 cleanup()
 147 {
 148     if [ -r "$failFile" ] ; then
 149         ls -l "$failFile" >&2
 150         echo "<cleanup:_begin_failFile_contents>" >&2
 151         cat "$failFile" >&2
 152         echo "<cleanup:_end_failFile_contents>" >&2
 153     fi
 154 
 155     # Kill all processes that have our special
 156     # keyword in their cmd line.
 157     killOrphans cleanup $jdbKeyword
 158     killOrphans cleanup $debuggeeKeyword
 159 }
 160 
 161 # Kill all processes with $2 in their cmd lines
 162 # Print a msg about this using $1 as the prefix
 163 killOrphans()
 164 {
 165     str=$2
 166 
 167     if [ -z "$isCygwin" ] ; then
 168         toBeKilled=`$psCmd | $grep -v grep | $grep -i $str | awk '{print $1}' | tr '\n\r' '  '`
 169     else
 170         # The cygwin ps command doesn't show the options passed to a cmd.
 171         # We will use jps to get the win PID of the command, and
 172         # then use ps to find the cygwin pid to be killed.
 173         # The form of a ps output line is
 174         # ^   ddddd    dddd    dddd    dddd.*
 175         # where the 4th digits are the win pid and the first 
 176         # are the cygwin pid.
 177         if [ -r "$jdk/bin/$jstack" ] ; then
 178             winPid=`$jdk/bin/jps -v | $grep -i $str | sed -e 's@ .*@@'`
 179             if [ ! -z "$winPid" ] ; then
 180                 # Here is a way to kill using a win cmd and the win PID.
 181                 #echo "$1: taskkill /F $winPid"  >& 2
 182                 #taskkill /F /PID $winPid
 183 
 184                 toBeKilled=`$psCmd | $grep -v grep | \
 185                             $grep '^ +[0-9]+ +[0-9]+ +[0-9]+ +'"$winPid" |\
 186                             awk '{print $1}' | tr '\n\r' '  '`
 187             fi
 188         else
 189             # Well, too bad - we can't find what to kill.  
 190             toBeKilled=
 191         fi
 192     fi
 193 
 194     if [ ! -z "$toBeKilled" ] ; then
 195         echo "$1: kill -9 $toBeKilled"  >& 2
 196         kill -9 $toBeKilled
 197     fi
 198 }
 199 
 200 # Returns 0 if $1 is the pid of a running process
 201 findPid()
 202 {
 203     if [ -z "$1" ] ; then
 204         return 1
 205     fi
 206 
 207     case "$osname" in
 208         SunOS | AIX)
 209             $psCmd | $grep '^ *'"$1 " > $devnull 2>&1
 210             res=$?
 211             ;;
 212         Windows* | CYGWIN*)
 213             # Don't use ps on cygwin since it sometimes misses
 214             # some processes (!).
 215             tasklist /NH | $grep " $1 " > $devnull 2>&1
 216             res=$?
 217             ;;
 218        *)
 219             #   Never use plain 'ps', which requires a "controlling terminal"
 220             #     and will fail  with a "ps: no controlling terminal" error.
 221             #     Running under 'rsh' will cause this ps error.
 222             $psCmd -e | $grep '^ *'"$1 " > $devnull 2>&1
 223             res=$?
 224             ;;
 225     esac
 226     return $res
 227 }
 228 
 229 setup()
 230 {
 231     failed=
 232     # This is used to tag each java and jdb cmd we issue so
 233     # we can kill them at the end of the run.
 234 
 235     orphanKeyword=HANGINGJAVA-$$
 236     debuggeeKeyword=${orphanKeyword}_DEB
 237     jdbKeyword=${orphanKeyword}_JDB
 238     baseArgs=-D${debuggeeKeyword}
 239     if [ -z "$TESTCLASSES" ] ; then
 240         echo "--Warning:  TESTCLASSES is not defined; using TESTCLASSES=."
 241         echo "  You should run: "
 242         echo "    runregress $0 -no"
 243         echo "  or"
 244         echo "    (setenv TESTCLASSES .; $0 $*)"
 245         TESTCLASSES=.
 246     fi
 247     if [ ! -z "$TESTJAVA" ] ; then
 248         jdk="$TESTJAVA"
 249     else
 250         echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test."
 251         exit 1
 252     fi
 253 
 254     ulimitCmd=
 255     osname=`uname -s`
 256     isCygwin=
 257     case "$osname" in
 258         Windows* | CYGWIN*)
 259             devnull=NUL
 260             case "$osname" in
 261                 CYGWIN*)
 262                     isCygwin=1
 263                     devnull=/dev/null
 264                     ;;
 265             esac
 266 
 267             if [ -r $jdk/bin/dt_shmem.dll ] ; then
 268                 transport=dt_shmem
 269                 address=kkkk.$$
 270             else
 271                 transport=dt_socket
 272                 address=
 273             fi
 274             baseArgs="$baseArgs -XX:-ShowMessageBoxOnError"
 275             # jtreg puts \\s in TESTCLASSES and some uses, eg. echo
 276             # treat them as control chars on mks (eg \t is tab)
 277             # Oops; windows mks really seems to want this cat line
 278             # to start in column 1
 279             if [ -w "$Temp" ] ; then
 280                 tmpFile=$Temp/tmp.$$
 281             elif [ -w "$TEMP" ] ; then
 282                 tmpFile=$TEMP/tmp.$$
 283             else
 284                 tmpFile=tmp.$$
 285             fi
 286 cat <<EOF >$tmpFile
 287 $TESTCLASSES
 288 EOF
 289             TESTCLASSES=`cat $tmpFile | sed -e 's@\\\\@/@g'`
 290             rm -f $tmpFile
 291             # on mks
 292             grep=egrep
 293             psCmd=ps
 294             jstack=jstack.exe
 295             ;;
 296        SunOS | Linux | Darwin | AIX)
 297          transport=dt_socket
 298          address=
 299          devnull=/dev/null
 300          grep=egrep
 301          jstack=jstack
 302          # On linux, core files take a long time, and can leave
 303          # zombie processes
 304          if [ "$osname" = SunOS ] ; then
 305              # Experiments show Solaris '/usr/ucb/ps -axwww' and
 306              # '/usr/bin/pgrep -f -l' provide the same small amount of the
 307              # argv string (PRARGSZ=80 in /usr/include/sys/procfs.h)
 308              #  1) This seems to have been working OK in ShellScaffold.
 309              #  2) OpenSolaris does not provide /usr/ucb/ps, so use pgrep
 310              #     instead
 311              # The alternative would be to use /usr/bin/pargs [pid] to get
 312              # all the args for a process, splice them back into one
 313              # long string, then grep.
 314              UU=`/usr/xpg4/bin/id -u -n`
 315              psCmd="pgrep -f -l -U $UU"
 316          else
 317              ulimit -c 0
 318              # See bug 6238593.
 319              psCmd="ps axwww"
 320          fi
 321          ;;
 322        *)
 323          echo "--Error:  Unknown result from 'uname -s':  $osname"
 324          exit 1
 325          ;;
 326     esac
 327 
 328 
 329     tmpFileDir=$TESTCLASSES/aa$$
 330     TESTCLASSES=$tmpFileDir
 331 
 332     mkdir -p $tmpFileDir
 333 
 334     # This must not contain 'jdb' or it shows up
 335     # in grep of ps output for some platforms
 336     jdbOutFile=$tmpFileDir/jxdbOutput.txt
 337     rm -f $jdbOutFile
 338     touch $jdbOutFile
 339 
 340     debuggeeOutFile=$tmpFileDir/debuggeeOutput.txt
 341     failFile=$tmpFileDir/testFailed
 342     debuggeepidFile=$tmpFileDir/debuggeepid
 343     rm -f $failFile $debuggeepidFile
 344     if [ -f "$failFile" ]; then
 345         echo "ERROR: unable to delete existing failFile:" >&2
 346         ls -l "$failFile" >&2
 347     fi
 348 
 349     if [ -z "$pkg" ] ; then
 350         pkgSlash=
 351         pkgDot=
 352         redefineSubdir=.
 353     else
 354         pkgSlash=$pkg/
 355         pkgDot=$pkg.
 356         redefineSubdir=$pkgSlash
 357     fi
 358     if [ -z "$classname" ] ; then
 359         classname=shtest
 360     fi
 361 
 362     if [ -z "$java" ] ; then
 363         java=java
 364     fi
 365 
 366     if [ -z "$jdb" ] ; then
 367         jdb=$jdk/bin/jdb
 368     fi
 369 
 370 ####################################################3
 371 ####################################################3
 372 ####################################################3
 373 ####################################################3
 374 #  sol:  this gets all processes killed but 
 375 #        no jstack
 376 #  linux same as above
 377 #  win mks:  No dice; processes still running
 378     trap "cleanup" 0 1 2 3 4 6 9 10 15
 379 
 380     jdbOptions="$jdbOptions -J-D${jdbKeyword}"
 381 }
 382 
 383 docompile()
 384 {
 385     if [ "$compile" = 0 ] ; then
 386         return
 387     fi
 388     saveDir=`pwd`
 389     cd $tmpFileDir
 390     rm -f *.java
 391     createJavaFile $classname
 392 
 393     # Compile two versions of the file, the original and with the
 394     # indicated lines modified.
 395     cp $classname.java.1 $classname.java
 396     echo "--Compiling first version of `pwd`/$classname.java with options: $compileOptions"
 397     # Result is in $pkgSlash$classname.class
 398 
 399     if [ -z "$javacCmd" ] ; then
 400         javacCmd=$jdk/bin/javac
 401     fi
 402 
 403     echo "compiling " `ls *.java`
 404     $javacCmd $compileOptions -d . *.java
 405     if [ $? != 0 ] ; then
 406        dofail "First compile failed"
 407     fi
 408     if [ -r vers1 ] ; then
 409         rm -rf vers1
 410     fi
 411     mkdir -p vers1
 412     mv *.class vers1
 413     if [ ! -z "$compileOptions2" ] ; then
 414         if [ "$compileOptions2" = none ] ; then
 415             compileOptions=
 416         else
 417             compileOptions=$compileOptions2
 418         fi
 419     fi
 420 
 421     while [ 1 = 1 ] ; do
 422         # Not really a loop; just a way to avoid goto
 423         # by using breaks
 424         sed -e '/@1 *delete/ d' \
 425             -e 's! *// *@1 *uncomment!     !' \
 426             -e 's!\(.*@1 *commentout\)!//\1!' \
 427             -e 's/@1 *newline/\
 428                  /' \
 429             -e 's/.*@1 *replace//' \
 430             $classname.java.1  >$classname.java
 431 
 432         cmp -s $classname.java.1 $classname.java
 433         if [ $? = 0 ] ; then
 434             break
 435         fi
 436         echo 
 437         echo "--Compiling second version of `pwd`/$classname.java with $compileOptions"
 438         $javacCmd $compileOptions -d . $classname.java
 439         if [ $? != 0 ] ; then
 440             dofail "Second compile failed"
 441         fi
 442         if [ -r vers2 ] ; then
 443             rm -rf vers2
 444         fi
 445         mkdir -p vers2
 446         mv *.class vers2
 447         mv $classname.java $classname.java.2
 448         cp $classname.java.1 $classname.java
 449 
 450         ###### Do the same for @2, and @3 allowing 3 redefines to occur.
 451         ###### If I had more time to write sed cmds, I would do
 452         ###### this in a loop.  But, I don't think we will ever need
 453         ###### more than 3 redefines.
 454         sed -e '/@2 *delete/ d' \
 455             -e 's! *// *@2 *uncomment!     !' \
 456             -e 's!\(.*@2 *commentout\)!//\1!' \
 457             -e 's/@2 *newline/\
 458                  /' \
 459             -e 's/.*@2 *replace//' \
 460             $classname.java.2 >$classname.java
 461         cmp -s $classname.java.2 $classname.java
 462         if [ $? = 0 ] ; then
 463             break
 464         fi
 465         echo 
 466         echo "--Compiling third version of `pwd`/$classname.java with $compileOptions"
 467         $javacCmd $compileOptions -d . $classname.java
 468         if [ $? != 0 ] ; then
 469             dofail "Third compile failed"
 470         fi
 471         if [ -r vers3 ] ; then
 472             rm -rf vers3
 473         fi
 474         mkdir -p vers3
 475         mv *.class vers3
 476         mv $classname.java $classname.java.3
 477         cp $classname.java.1 $classname.java
 478 
 479         ########
 480         sed -e '/@3 *delete/ d' \
 481             -e 's! *// *@3 *uncomment!     !' \
 482             -e 's!\(.*@3 *commentout\)!//\1!' \
 483             -e 's/@3 *newline/\
 484                     /' \
 485             -e 's/.*@3 *replace//' \
 486             $classname.java.3 >$classname.java
 487         cmp -s $classname.java.3 $classname.java
 488         if [ $? = 0 ] ; then
 489             break
 490         fi
 491         echo 
 492         echo "--Compiling fourth version of `pwd`/$classname.java with $compileOptions"
 493         $javacCmd $compileOptions -d . $classname.java
 494         if [ $? != 0 ] ; then
 495             dofail "fourth compile failed"
 496         fi
 497         if [ -r vers4 ] ; then
 498             rm -rf vers4
 499         fi
 500         mkdir -p vers4
 501         mv *.class vers4
 502         mv $classname.java $classname.java.4
 503         cp $classname.java.1 $classname.java
 504         break
 505         fgrep @4 $classname.java
 506         if [ $? = 0 ] ; then
 507             echo "--Error: @4 and above are not yet allowed"
 508             exit 1
 509         fi
 510     done
 511 
 512     cp vers1/* $redefineSubdir
 513     cd $saveDir
 514 }
 515 
 516 # Send a cmd to jdb and wait for the jdb prompt to appear.
 517 # We don't want to allow > as a prompt because if the debuggee
 518 # runs for awhile after a command, jdb will show this prompt
 519 # but is not really ready to accept another command for the
 520 # debuggee - ie, a cont in this state will be ignored.
 521 # If it ever becomes necessary to send a jdb command before
 522 # a  main[10] form of prompt appears, then this
 523 # code will have to be modified.
 524 #
 525 # Specify $1 = allowExit to show that the command given
 526 # allows JDB to exit
 527 cmd()
 528 {
 529     allowExit=
 530     case "$1" in
 531         allowExit)
 532             allowExit="allowExit"
 533             shift
 534             ;;
 535         exitJdb)
 536             # Quit JDB only with this cmd() invocation
 537             echo "--Sending cmd: quit" >& 2
 538             echo quit
 539             echo "--Quit cmd was sent" >& 2
 540             # See 6562090. Maybe there is a way that the exit
 541             # can cause jdb to not get the quit.
 542             sleep 5
 543 
 544             # The exit code value here doesn't matter since this function
 545             # is called as part of a pipeline and it is not the last command
 546             # in the pipeline.
 547             exit 1
 548             ;;
 549     esac
 550     command=$*
 551 
 552     if [ -z "$command" ] ; then
 553         dofail "Command can't be a null string. Test failure"
 554     fi
 555     if [ "$command" = "quit" -o "$command" = "exit" ] ; then
 556         # We don't want the test to manually quit jdb,
 557         # we will do it in the end automatically
 558         dofail "It's not allowed to send quit or exit commands from the test"
 559     fi
 560     if [ -r "$failFile" ] ; then
 561         # failFile exists, it's better to finish execution
 562         dofinish "quit"
 563     fi
 564 
 565     # $jdbOutFile always exists here and is non empty
 566     # because after starting jdb, we waited 
 567     # for the prompt.
 568     fileSize=`wc -c $jdbOutFile | awk '{ print $1 }'`
 569     echo "--Sending cmd: " $command >&2
 570 
 571     # jjh: We have a few intermittent failures here.
 572     # It is as if every so often, jdb doesn't
 573     # get the first cmd that is sent to it here.  
 574     # (actually, I have seen it get the first cmd ok,
 575     # but then not get some subsequent cmd).
 576     # It seems like jdb really doesn't get the cmd; jdb's response
 577     # does not appear in the jxdboutput file. It contains:
 578     # main[1] 
 579     # The application has been disconnected
 580 
 581     # Is it possible
 582     # that jdb got the cmd ok, but its response didn't make
 583     # it to the jxdboutput file?  If so, why did 'The application
 584     # has been disconnected' make it?
 585 
 586     # This causes the following loop to timeout and the test to fail.
 587     # The above echo works because the cmd (stop at ...)
 588     # is in the System.err shown in the .jtr file.
 589     # Also, the cmd is shown in the 'jdb never responded ...'
 590     # msg output below after the timeout.
 591     # And, we know jdb is started because the main[1] output is in the .jtr
 592     # file.  And, we wouldn't have gotten here if mydojdbcmds hadn't
 593     # seen the ].  
 594     echo $command
 595 
 596     # Now we have to wait for the next jdb prompt.  We wait for a pattern
 597     # to appear in the last line of jdb output.  Normally, the prompt is
 598     #
 599     # 1) ^main[89] @
 600     #
 601     # where ^ means start of line, and @ means end of file with no end of line
 602     # and 89 is the current command counter. But we have complications e.g.,
 603     # the following jdb output can appear:
 604     #
 605     # 2) a[89] = 10
 606     #
 607     # The above form is an array assignment and not a prompt.
 608     #
 609     # 3) ^main[89] main[89] ...
 610     #
 611     # This occurs if the next cmd is one that causes no jdb output, e.g.,
 612     # 'trace methods'.
 613     #
 614     # 4) ^main[89] [main[89]] .... > @
 615     #
 616     # jdb prints a > as a prompt after something like a cont.
 617     # Thus, even though the above is the last 'line' in the file, it
 618     # isn't the next prompt we are waiting for after the cont completes.
 619     # HOWEVER, sometimes we see this for a cont command:
 620     #
 621     #   ^main[89] $
 622     #      <lines output for hitting a bkpt>
 623     #
 624     # 5) ^main[89] > @
 625     #
 626     # i.e., the > prompt comes out AFTER the prompt we we need to wait for.
 627     #
 628     # So, how do we know when the next prompt has appeared??
 629     # 1.  Search for 
 630     #         main[89] $
 631     #     This will handle cases 1, 2, 3
 632     # 2.  This leaves cases 4 and 5.
 633     #
 634     # What if we wait for 4 more chars to appear and then search for
 635     #
 636     #    main[89] [>]$
 637     #
 638     # on the last line?
 639     #
 640     # a.  if we are currently at
 641     #
 642     #       ^main[89] main[89] @
 643     #
 644     #     and a 'trace methods comes in, we will wait until at least
 645     #
 646     #       ^main[89] main[89] main@
 647     #
 648     #     and then the search will find the new prompt when it completes.
 649     #
 650     # b.  if we are currently at
 651     #
 652     #       ^main[89] main[89] @
 653     #
 654     #     and the first form of cont comes in, then we will see
 655     #
 656     #       ^main[89] main[89] > $
 657     #       ^x@
 658     #
 659     #     where x is the first char of the msg output when the bkpt is hit
 660     #     and we will start our search, which will find the prompt
 661     #     when it comes out after the bkpt output, with or without the
 662     #     trailing >
 663     #
 664 
 665     # wait for 4 new chars to appear in the jdb output
 666     count=0
 667     desiredFileSize=`expr $fileSize + 4`
 668     msg1=`echo At start: cmd/size/waiting : $command / $fileSize / \`date\``
 669     timeLimit=`expr 60 * $timeout_factor`
 670     while [ 1 = 1 ] ; do
 671         newFileSize=`wc -c $jdbOutFile | awk '{ print $1 } '`
 672         #echo jj: desired = $desiredFileSize, new = $newFileSize >& 2
 673 
 674         done=`expr $newFileSize \>= $desiredFileSize`
 675         if [ $done = 1 ] ; then
 676             break
 677         fi
 678         sleep ${sleep_seconds}
 679         count=`expr $count + ${sleep_seconds}`        
 680         if [ $count -gt $timeLimit ] ; then
 681             # record some debug info.
 682             echo "--DEBUG: jdb $$ didn't respond to command in $count secs: $command" >& 2
 683             echo "--DEBUG:" $msg1 >& 2
 684             echo "--DEBUG: "done size/waiting : / $newFileSize  / `date` >& 2
 685             echo "-- $jdbOutFile follows-------------------------------" >& 2
 686             cat $jdbOutFile >& 2
 687             echo "------------------------------------------" >& 2
 688             dojstack
 689             dofail "jdb never responded to command: $command"
 690         fi
 691     done
 692     # Note that this assumes just these chars in thread names.
 693     waitForJdbMsg '[a-zA-Z0-9_-][a-zA-Z0-9_-]*\[[1-9][0-9]*\] [ >]*$' 1 $allowExit
 694 }
 695 
 696 setBkpts()
 697 {
 698     # Can set multiple bkpts, but only in one class.
 699     # $1 is the bkpt name, eg, @1
 700     allLines=`$grep -n "$1 *breakpoint" $tmpFileDir/$classname.java.1 | sed -e 's@^\([0-9]*\).*@\1@g'`
 701     for ii in $allLines ; do
 702         cmd "stop at $pkgDot$classname:$ii"
 703     done
 704 }
 705 
 706 runToBkpt()
 707 {
 708     # Don't pass allowExit here as we don't want JDB to unexpectedly exit
 709     cmd run
 710     # Don't need to do this - the above waits for the next prompt which comes out
 711     # AFTER the Breakpoint hit message.
 712     # Wait for jdb to hit the bkpt
 713     #waitForJdbMsg "Breakpoint hit" 5
 714 }
 715 
 716 contToBkpt()
 717 {
 718     # Don't pass allowExit here as we don't want JDB to unexpectedly exit
 719     cmd cont
 720     # Don't need to do this - the above waits for the next prompt which comes out
 721     # AFTER the Breakpoint hit message.
 722     # Wait for jdb to hit the bkpt
 723     #waitForJdbMsg "Breakpoint hit" 5
 724 }
 725 
 726 
 727 # Wait until string $1 appears in the output file, within the last $2 lines
 728 # If $3 is allowExit, then don't fail if jdb exits before
 729 # the desired string appears.
 730 waitForJdbMsg()
 731 {
 732     # This can be called from the jdb thread which doesn't
 733     # have access to $debuggeepid, so we have to read it from the file.
 734     nlines=$2
 735     allowExit="$3"
 736     myCount=0
 737     timeLimit=`expr 40 * $timeout_factor`  # wait a max of this many secs for a response from a jdb command
 738 
 739     while [ 1 = 1 ] ; do 
 740         if [  -r $jdbOutFile ] ; then
 741             # Something here causes jdb to complain about Unrecognized cmd on x86.
 742             tail -$nlines $jdbOutFile | $grep -s "$1" > $devnull 2>&1
 743             if [ $? = 0 ] ; then
 744                 # Found desired string
 745                 break
 746             fi
 747         fi
 748         tail -2 $jdbOutFile | $grep -s "The application exited" > $devnull 2>&1
 749         if [ $? = 0 ] ; then
 750             # Found 'The application exited'
 751             echo "--JDB finished: The application exited" >&2
 752             if [ ! -z "$allowExit" ] ; then
 753                 # Exit is allowed
 754                 dofinish
 755             fi
 756             # Otherwise, it is an error if we don't find $1
 757             if [  -r $jdbOutFile ] ; then 
 758                 tail -$nlines $jdbOutFile | $grep -s "$1" > $devnull 2>&1
 759                 if [ $? = 0 ] ; then
 760                     break
 761                 fi
 762             fi
 763             dofail "JDB unexpectedly finished: Waited for jdb msg $1, but it never appeared"
 764         fi
 765 
 766         sleep ${sleep_seconds}
 767         findPid $topPid
 768         if [ $? != 0 ] ; then
 769             echo "--Top process ($topPid) is dead.  We better die too" >&2
 770             dojstack
 771             exit 1
 772         fi
 773 
 774         myCount=`expr $myCount + ${sleep_seconds}`
 775         if [ $myCount -gt $timeLimit ] ; then
 776             echo "--Fail: waitForJdbMsg timed out after $timeLimit seconds, looking for /$1/, in $nlines lines; exiting" >> $failFile
 777             echo "vv jdbOutFile  vvvvvvvvvvvvvvvvvvvvvvvvvvvv" >& 2
 778             cat $jdbOutFile >& 2
 779             echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" >& 2
 780             dojstack
 781             exit 1
 782         fi
 783     done
 784 
 785 }
 786 
 787 # Finishes JDB execution
 788 # Specify command to finish if it's needed
 789 dofinish()
 790 {
 791     if [ ! -z "$*" ] ; then
 792         echo "--Finish execution with sending \"$*\" command to JDB" >&2
 793         cmd "exitJdb" "$*"
 794     else
 795         echo "--Finish without sending \"quit\" command to JDB" >&2
 796     fi
 797     exit 0
 798 }
 799 
 800 # $1 is the string to print.  If $2 exists,
 801 # it is the name of a file to print, ie, the name
 802 # of the file that contains the $1 string.
 803 dofail()
 804 {
 805     if [ ! -z "$jdbpid" ] ; then
 806         # we are in the main process instead of the jdb process
 807         echo " " >> $failFile
 808         echo "--Fail: main: $*" >> $failFile
 809     else
 810         # Kill the debuggee ; it could be hung so
 811         # we want to get rid of it as soon as possible.
 812         killOrphans "killing debuggee" $debuggeeKeyword
 813         # Kill debugger, it could be hung
 814         killOrphans "killing debugger" $jdbKeyword
 815 
 816         echo " "  >>$failFile
 817         echo "--Fail: $*" >> $failFile
 818     fi
 819     if [ ! -z "$2" ] ; then
 820         echo  "---- contents of $2 follows -------" >> $failFile
 821         cat "$2" >> $failFile
 822         echo "---------------" >>$failFile
 823     fi
 824     exit 1
 825 }
 826 
 827 
 828 redefineClass()
 829 {
 830     if [ -z "$1" ] ; then
 831         vers=2
 832     else
 833         vers=`echo $1 | sed -e 's/@//'`
 834         vers=`expr $vers + 1`
 835     fi
 836 
 837     cmd "redefine $pkgDot$classname $tmpFileDir/vers$vers/$classname.class"
 838 
 839     cp $tmpFileDir/$classname.java.$vers \
 840        $tmpFileDir/$classname.java
 841 }
 842 
 843 mydojdbCmds()
 844 {
 845    # Wait for jdb to start before we start sending cmds
 846    waitForJdbMsg ']' 1
 847    # Send commands from the test
 848    dojdbCmds
 849    # Finish jdb with quit command
 850    dofinish "quit"
 851 }
 852 
 853 startJdb()
 854 {
 855     if [ ! -r "$jdb" -a ! -r "$jdb.exe" ] ; then
 856         dofail "$jdb does not exist"
 857     fi
 858     echo
 859     echo "--Starting jdb, address=$address"
 860     if [ -z "$address" ] ; then
 861        # Let jdb choose the port and write it to stdout
 862        mydojdbCmds | $jdb $jdbOptions -listenany | tee $jdbOutFile &
 863 
 864        while [ 1 ] ; do
 865            lastLine=`$grep 'Listening at address' $jdbOutFile`
 866            if [ ! -z "$lastLine" ] ; then
 867                break
 868            fi
 869            sleep 1
 870        done
 871        # jjh: we got the address ok, and seemed to start the debuggee
 872        address=`echo $lastLine | sed -e 's@.*: *@@'`
 873     else
 874        mydojdbCmds | $jdb $jdbOptions -listen $address | tee $jdbOutFile &
 875     fi
 876     #echo address = $address
 877 
 878 
 879     # this gets the pid of tee, at least it does on solaris
 880     jdbpid=$!
 881 
 882     # This fails on linux because there is an entry for each thread in jdb
 883     # so we get a list of numbers in jdbpid
 884     # jdbpid=`$psCmd | $grep -v grep | $grep ${orphanKeyword}_JDB | awk '{print $1}'  | tr '\n\r' '  '`
 885 }
 886 
 887 startDebuggee()
 888 {
 889     args="$TESTVMOPTS $TESTJAVAOPTS"
 890 
 891     if [ ! -z "$args" ] ; then
 892        echo "--Starting debuggee with args from TESTVMOPTS and/or TESTJAVAOPTS: $args"
 893     else
 894        echo "--Starting debuggee"
 895     fi
 896 
 897     debuggeepid=
 898     waitForJdbMsg Listening 4
 899 
 900     beOption="-agentlib:jdwp=transport=$transport,address=$address,server=n,suspend=y" 
 901 #   beOption="-Xdebug -Xrunjdwp:transport=$transport,address=$address,server=n,suspend=y"
 902 
 903     thecmd="$jdk/bin/$java $mode -classpath $tmpFileDir $baseArgs $args \
 904             -Djtreg.classDir=$TESTCLASSES \
 905             -showversion \
 906              $beOption \
 907              $pkgDot$classname"
 908     echo "Cmd: $thecmd"
 909 
 910     sh -c "$thecmd | tee $debuggeeOutFile" &
 911 
 912     # Note that the java cmd and the tee cmd will be children of
 913     # the sh process.  We can use that to find them to kill them.
 914     debuggeepid=$!
 915 
 916     # Save this in a place where the jdb process can find it.
 917     # Note that it is possible for the java cmd to abort during startup
 918     # due to a bad classpath or whatever.
 919     echo $debuggeepid > $debuggeepidFile
 920 }
 921 
 922 dojstack()
 923 {
 924     if [ -r "$jdk/bin/$jstack" ] ; then
 925         # If jstack exists, so will jps
 926         # Show stack traces of jdb and debuggee as a possible debugging aid.
 927         jdbCmd=`$jdk/bin/jps -v | $grep $jdbKeyword`
 928         realJdbPid=`echo "$jdbCmd" | sed -e 's@ .*@@'`
 929         if [ ! -z "$realJdbPid" ] ; then
 930             echo "-- jdb process info ----------------------" >&2
 931             echo "      $jdbCmd"                              >&2
 932             echo "-- jdb threads: jstack $realJdbPid"         >&2
 933             $jdk/bin/$jstack $realJdbPid                      >&2
 934             echo "------------------------------------------" >&2
 935             echo                                              >&2
 936         fi
 937         debuggeeCmd=`$jdk/bin/jps -v | $grep $debuggeeKeyword`
 938         realDebuggeePid=`echo "$debuggeeCmd" | sed -e 's@ .*@@'`
 939         if [ ! -z "$realDebuggeePid" ] ; then
 940             echo "-- debuggee process info ----------------------" >&2
 941             echo "      $debuggeeCmd"                              >&2
 942             echo "-- debuggee threads: jstack $moption $realDebuggeePid" >&2
 943             $jdk/bin/$jstack $realDebuggeePid                      >&2
 944             echo "============================================="   >&2
 945             echo                                                   >&2
 946         fi
 947     fi
 948 }
 949 
 950 waitForFinish()
 951 {
 952     # This is the main process
 953     # Wait for the jdb process to finish, or some error to occur
 954 
 955     while [ 1 = 1 ] ; do
 956         findPid $jdbpid
 957         if [ $? != 0 ] ; then
 958             break
 959         fi
 960 
 961         # (Don't use jdbFailIfPresent here since it is not safe 
 962         # to call from different processes)
 963         $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1
 964         if [ $? = 0 ] ; then
 965             dofail "jdb input stream closed prematurely"
 966         fi
 967 
 968         # If a failure has occured, quit
 969         if [ -r "$failFile" ] ; then
 970             break
 971         fi
 972 
 973         sleep ${sleep_seconds}
 974     done
 975 
 976     # jdb exited because its input stream closed prematurely
 977     # (Don't use jdbFailIfPresent here since it is not safe 
 978     # to call from different processes)
 979     $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1
 980     if [ $? = 0 ] ; then
 981         dofail "jdb input stream closed prematurely"
 982     fi
 983 
 984     # It is necessary here to avoid the situation when JDB exited but
 985     # mydojdbCmds() didn't finish because it waits for JDB message
 986     # in waitForJdbMsg(), at the same time main process will finish
 987     # the execution with no errors.
 988     # To avoid that, wait for spawned processes to finish
 989     case "$osname" in
 990         SunOS)
 991             # `wait` function doesn't work in Solaris shell as in bash,
 992             # so create replacement that finds mydojdbCmds() shell process
 993             # and waits for its finish
 994             cmdsPid=
 995             # get list of processes except main process with $topPid
 996             processes=`$psCmd | $grep -v "$grep" | $grep -v $topPid | awk '{print $1}'`
 997             for pid in $processes; do
 998                 # for each process grep its full args string for test name $0
 999                 # $0 contains full test name with path
1000                 pargs -l $pid 2>$devnull | $grep "$0" >$devnull 2>&1
1001                 if [ $? = 0 ] ; then
1002                     cmdsPid=$pid
1003                     break
1004                 fi
1005             done
1006             echo "--waitForFinish: Waiting for mydojdbCmds() to finish" >&2
1007             while [ 1 = 1 ] ; do
1008                 findPid $cmdsPid
1009                 if [ $? != 0 ] ; then
1010                     break
1011                 fi
1012                 sleep ${sleep_seconds}
1013             done
1014             ;;
1015         *)
1016             echo "--waitForFinish: Waiting for all processes to finish" >&2
1017             wait
1018             ;;
1019     esac
1020 
1021     if [ -r "$failFile" ] ; then
1022         ls -l "$failFile" >&2
1023         echo "<waitForFinish:_begin_failFile_contents>" >&2
1024         cat "$failFile" >&2
1025         echo "<waitForFinish:_end_failFile_contents>" >&2
1026         exit 1
1027     fi
1028 }
1029 
1030 # $1 is the filename, $2 is the string to look for,
1031 # $3 is the number of lines to search (from the end)
1032 grepForString()
1033 {
1034     if [ -z "$3" ] ; then
1035         theCmd=cat
1036     else
1037         theCmd="tail -$3"
1038     fi
1039 
1040     case "$2" in 
1041     *\>*)
1042         # Target string contains a '>' so we better not ignore it
1043         $theCmd $1 | $grep -s "$2"  > $devnull 2>&1
1044         stat="$?"
1045         ;;
1046     *)
1047         # Target string does not contain a '>'.
1048         # NOTE:  if $1 does not end with a new line, piping it to sed
1049         # doesn't include the chars on the last line.  Detect this
1050         # case, and add a new line.
1051         theFile="$1"
1052         if [ `tail -1 "$theFile" | wc -l | sed -e 's@ @@g'` = 0 ] ; then
1053             # The target file doesn't end with a new line so we have
1054             # add one to a copy of the target file so the sed command
1055             # below can filter that last line.
1056             cp "$theFile" "$theFile.tmp"
1057             theFile="$theFile.tmp"
1058             echo >> "$theFile"
1059         fi
1060 
1061         # See bug 6220903. Sometimes the jdb prompt chars ('> ') can
1062         # get interleaved in the target file which can keep us from
1063         # matching the target string.
1064         $theCmd "$theFile" | sed -e 's@> @@g' -e 's@>@@g' \
1065             | $grep -s "$2" > $devnull 2>&1
1066         stat=$?
1067         if [ "$theFile" != "$1" ]; then
1068             # remove the copy of the target file
1069             rm -f "$theFile"
1070         fi
1071         unset theFile
1072     esac
1073 
1074     return $stat
1075 }
1076 
1077 # $1 is the filename, $2 is the regexp to match and return,
1078 # $3 is the number of lines to search (from the end)
1079 matchRegexp()
1080 {
1081     if [ -z "$3" ] ; then
1082         theCmd=cat
1083     else
1084         theCmd="tail -$3"
1085     fi
1086 
1087     case "$2" in 
1088     *\>*)
1089         # Target string contains a '>' so we better not ignore it
1090         res=`$theCmd $1 | sed -e "$2"`
1091         ;;
1092     *)
1093         # Target string does not contain a '>'.
1094         # NOTE:  if $1 does not end with a new line, piping it to sed
1095         # doesn't include the chars on the last line.  Detect this
1096         # case, and add a new line.
1097         theFile="$1"
1098         if [ `tail -1 "$theFile" | wc -l | sed -e 's@ @@g'` = 0 ] ; then
1099             # The target file doesn't end with a new line so we have
1100             # add one to a copy of the target file so the sed command
1101             # below can filter that last line.
1102             cp "$theFile" "$theFile.tmp"
1103             theFile="$theFile.tmp"
1104             echo >> "$theFile"
1105         fi
1106 
1107         # See bug 6220903. Sometimes the jdb prompt chars ('> ') can
1108         # get interleaved in the target file which can keep us from
1109         # matching the target string.
1110         res=`$theCmd "$theFile" | sed -e 's@> @@g' -e 's@>@@g' \
1111             | sed -e "$2"`
1112         if [ "$theFile" != "$1" ]; then
1113             # remove the copy of the target file
1114             rm -f "$theFile"
1115         fi
1116         unset theFile
1117     esac
1118     return $res
1119 }
1120 
1121 # $1 is the filename, $2 is the string to look for,
1122 # $3 is the number of lines to search (from the end)
1123 failIfPresent()
1124 {
1125     if [ -r "$1" ] ; then
1126         grepForString "$1" "$2" "$3"
1127         if [ $? = 0 ] ; then
1128             dofail "Error output found: \"$2\" in $1" $1
1129         fi
1130     fi
1131 }
1132 
1133 # $1 is the filename, $2 is the string to look for
1134 # $3 is the number of lines to search (from the end)
1135 failIfNotPresent()
1136 {
1137     if [ ! -r "$1" ] ; then
1138         dofail "Required output \"$2\" not found in $1"
1139     fi
1140     grepForString "$1" "$2" "$3"
1141     if [ $? != 0 ] ; then
1142         dofail "Required output \"$2\" not found in $1" $1
1143     fi
1144 
1145 }
1146 
1147 # fail if $1 is not in the jdb output
1148 # $2 is the number of lines to search (from the end)
1149 jdbFailIfNotPresent()
1150 {
1151     failIfNotPresent $jdbOutFile "$1" $2
1152 }
1153 
1154 # fail if $1 is not in the debuggee output
1155 # $2 is the number of lines to search (from the end)
1156 debuggeeFailIfNotPresent()
1157 {
1158     failIfNotPresent $debuggeeOutFile "$1" $2
1159 }
1160 
1161 # fail if $1 is in the jdb output
1162 # $2 is the number of lines to search (from the end)
1163 jdbFailIfPresent()
1164 {
1165     failIfPresent $jdbOutFile "$1" $2
1166 }
1167 
1168 # fail if $1 is in the debuggee output
1169 # $2 is the number of lines to search (from the end)
1170 debuggeeFailIfPresent()
1171 {
1172     failIfPresent $debuggeeOutFile "$1" $2
1173 }
1174 
1175 # match and return the output from the regexp $1 in the debuggee output
1176 # $2 is the number of lines to search (from the end)
1177 debuggeeMatchRegexp()
1178 {
1179     matchRegexp $debuggeeOutFile "$1" $2
1180 }
1181 
1182 
1183 # This should really be named 'done' instead of pass.
1184 pass()
1185 {
1186     if [ ! -r "$failFile" ] ; then
1187         echo
1188         echo "--Done: test passed"
1189         exit 0
1190     else
1191         ls -l "$failFile" >&2
1192         echo "<pass:_begin_failFile_contents>" >&2
1193         cat "$failFile" >&2
1194         echo "<pass:_end_failFile_contents>" >&2
1195     fi
1196 }
1197 
1198 runit()
1199 {
1200     setup
1201     docompile
1202     startJdb
1203     startDebuggee
1204     waitForFinish
1205 
1206     # in hs_err file from 1.3.1
1207     debuggeeFailIfPresent "Virtual Machine Error"
1208 
1209     # in hs_err file from 1.4.2, 1.5:  An unexpected error
1210     debuggeeFailIfPresent "An unexpected error"
1211 
1212     # in hs_err file from 1.4.2, 1.5:  Internal error
1213     debuggeeFailIfPresent "Internal error"
1214 
1215 
1216     # Don't know how this arises
1217     debuggeeFailIfPresent "An unexpected exception"
1218 
1219     # Don't know how this arises
1220     debuggeeFailIfPresent "Internal exception"
1221 }