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