jdk中gamma启动器脚本详解

解析

本文是基于jdk1.6进行解析的,在HotSpot中存在两种启动器,一种是通用启动器(java/javaw),另一种是调试版启动器(gamma).

在对openjdk编译后,会在jvmg 目录下生成hotSpot脚本,这个启动器入口位于hotspot/src/share/tools/luncher/java.c. 本文就来看一下该脚本

#解析

该脚本中首先是设置gdb,dbx,valgrind,emacs等参数.如下:

#
# User changeable parameters ------------------------------------------------
#

# This is the name of the gdb binary to use
if [ ! "$GDB" ]
then 
    GDB=gdb
fi

# This is the name of the gdb binary to use
if [ ! "$DBX" ]
then 
    DBX=dbx
fi

# This is the name of the Valgrind binary to use
if [ ! "$VALGRIND" ]
then 
    VALGRIND=valgrind
fi

# This is the name of Emacs for running GUD
EMACS=emacs

其中,gdb是linux环境中的调试工具,可通过官方文档进行了解,dbx是uninx中的调试工具,可通过该文档进行了解, valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。emacs则是著名的集成开发环境和文本编辑器。Emacs被公认为是最受专业程序员喜爱的代码编辑器之一,另外一个是vim。

接下来时获得当前脚本中和当前脚本所在的目录:

# Make sure the paths are fully specified, i.e. they must begin with /.
SCRIPT=$(cd $(dirname $0) && pwd)/$(basename $0)
RUNDIR=$(pwd)

这里针对$dirname $0等做一些说明:

特殊变量列表
变量含义
$0当前脚本的文件名
$n传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$#传递给脚本或函数的参数个数。
$*传递给脚本或函数的所有参数。
$@传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。
$?上个命令的退出状态,或函数的返回值。
$$当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
$dirname取指定路径所在的目录
$basename去除目录后剩下的名字

关于这部分的内容可以参考如下链接:

关于shell中的basename

Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数

接下来,匹配运行模式,默认情况下是run,如下:

# Look whether the user wants to run inside gdb
case "$1" in
    -gdb)
        MODE=gdb
        shift
        ;;
    -gud)
        MODE=gud
        shift
        ;;
    -dbx)
        MODE=dbx
        shift
        ;;
    -valgrind)
        MODE=valgrind
        shift
        ;;
    *)
        MODE=run
        ;;
esac

接下来,是获得该脚本的目录的绝对路径

#Find out the absolute path to this script
MYDIR=$(cd $(dirname $SCRIPT) && pwd)

接下来时设置jdk:

JDK=
if [ "${ALT_JAVA_HOME}" = "" ]; then
    source ${MYDIR}/jdkpath.sh
else 
    JDK=${ALT_JAVA_HOME%%/jre};
fi

if [ "${JDK}" = "" ]; then
    echo Failed to find JDK. ALT_JAVA_HOME is not set or ./jdkpath.sh is empty or not found.
    exit 1
fi

如果没有设置ALT_JAVA_HOME环境变量的话,则执行${MYDIR}/jdkpath.sh 设置环境变量,否则,jdk指向ALT_JAVA_HOME/jre. 其中,jdkpath.sh的内容如下:

# Generated by /usr/local/openjdk-6/hotspot/make/linux/makefiles/buildtree.make
JDK=/usr/java/jdk1.6.0_45

该文件中的内容依赖于你本机中编译的情况

接下来设置JRE,JAVA,ARCH,MYDIR,SBP等变量:

# We will set the LD_LIBRARY_PATH as follows:
#     o		$JVMPATH (directory portion only)
#     o		$JRE/lib/$ARCH
# followed by the user's previous effective LD_LIBRARY_PATH, if
# any.
JRE=$JDK/jre
JAVA_HOME=$JDK
ARCH=@@LIBARCH@@

# Find out the absolute path to this script
MYDIR=$(cd $(dirname $SCRIPT) && pwd)

SBP=${MYDIR}:${JRE}/lib/${ARCH}

设置LD_LIBRARY_PATH:

# Set up a suitable LD_LIBRARY_PATH

if [ -z "$LD_LIBRARY_PATH" ]
then
    LD_LIBRARY_PATH="$SBP"
else
    LD_LIBRARY_PATH="$SBP:$LD_LIBRARY_PATH"
fi

接下来,设置JAVA_HOME, LD_LIBRARY_PATH等环境变量:

export LD_LIBRARY_PATH
export JAVA_HOME

设置参数:

JPARMS="$@ $JAVA_ARGS";

因此,我们可以通过JAVA_ARGS环境变量来进行设置参数

获取gamma调试器:

# Locate the gamma development launcher
LAUNCHER=${MYDIR}/gamma
if [ ! -x $LAUNCHER ] ; then
    echo Error: Cannot find the gamma development launcher \"$LAUNCHER\"
    exit 1
fi

设置GDBSRCDIR, BASEDIR等变量:

GDBSRCDIR=$MYDIR
BASEDIR=$(cd $MYDIR/../../.. && pwd)

声明了init_gdb函数,该函数会在gdb模式下用到:

init_gdb() {
# Create a gdb script in case we should run inside gdb
    GDBSCR=/tmp/hsl.$$
    rm -f $GDBSCR
    cat >>$GDBSCR <<EOF
cd `pwd`
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
set args $JPARMS
file $LAUNCHER
directory $GDBSRCDIR
# Get us to a point where we can set breakpoints in libjvm.so
break InitializeJVM
run
# Stop in InitializeJVM
delete 1
# We can now set breakpoints wherever we like
EOF
}

这里做些解释:

  1. cat >>$GDBSCR <<EOF --> 是创建/tmp/hsl.当前Shell进程ID 的文件,其内容是EOF之前的内容.

  2. handle --> 在GDB中定义一个信号处理。信号可以以SIG开头或不以 SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO, SIGIOT,SIGKILL三个信号),也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB停住,以 供调试。

  3. SIGUSR1/SIGUSR2 --> 用户自定义信号,关于这个,可以参考如下链接:

    利用Linux信号SIGUSR1调试嵌入式程序

    Linux的SIGUSR1和SIGUSR2信号

    Linux信号(signal) 机制分析

    linux系统下信号详解2

  4. nostop --> 当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。

  5. noprint -->当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。

  6. set args --> 指定运行时参数。

  7. file --> 设置要执行的程序

  8. directory --> 设置源文件的目录

  9. break InitializeJVM --> 在InitializeJVM函数入口处设置断点

  10. delete 1 --> 删除断点1

关于gdb的使用可以参数如下链接:

gdb调试问题汇总

GDB常用命令使用说明(一)

gdb中忽略信号处理

接下来,就会针对不同的模式进行处理:

case "$MODE" in
    gdb)
	init_gdb
        $GDB -x $GDBSCR
	rm -f $GDBSCR
        ;;
    gud)
	init_gdb
# First find out what emacs version we're using, so that we can
# use the new pretty GDB mode if emacs -version >= 22.1
	case $($EMACS -version 2> /dev/null) in
	    *GNU\ Emacs\ 2[23]*)
	    emacs_gud_cmd="gdba"
	    emacs_gud_args="--annotate=3"
	    ;;
	    *)
		emacs_gud_cmd="gdb"
		emacs_gud_args=
		;;
	esac
        $EMACS --eval "($emacs_gud_cmd \"$GDB $emacs_gud_args -x $GDBSCR\")";
	rm -f $GDBSCR
        ;;
    dbx)
        $DBX -s $MYDIR/.dbxrc $LAUNCHER $JPARAMS
        ;;
    valgrind)
        echo Warning: Defaulting to 16Mb heap to make Valgrind run faster, use -Xmx for larger heap
        echo
        $VALGRIND --tool=memcheck --leak-check=yes --num-callers=50 $LAUNCHER -Xmx16m $JPARMS
        ;;
    run)
        LD_PRELOAD=$PRELOADING exec $LAUNCHER $JPARMS
        ;;
    *)
        echo Error: Internal error, unknown launch mode \"$MODE\"
        exit 1
        ;;
esac
RETVAL=$?
exit $RETVAL

如果是gdb模式的话,则会创建/tmp/hsl.当前Shell进程ID 的文件,然后执行 gdb -x $GDBSCR 命令进行调试,调试结束后,删除临时文件.

这里对–annotate=3(emacs中的gdb参数)做如下解释:

  • annotate = 0是最基本的模式和在命令行使用gdb完全一样
  • annotate = 1是单步调试模式,出现上下两个窗口,上面是gdb运行的buffer,下面是你代码的buffer,会在代码 buffer中,同步指示当前运行的语句的位置.
  • annotate = 2是产生注解的模式。
  • annotate = 3是信息最完整的模式。此时的 Emacs 分5个 buffer,从上到下、从左到右依次是:gdb 调试窗口、变量实时变化显示窗口、源代码窗口、栈窗口、断点信息.

关于这部分内容,可以参考:

emacs编译和调试程序

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值