我是靠谱客的博主 神勇便当,最近开发中收集的这篇文章主要介绍《HotSpot实战》—— 1.3 实战:在HotSpot内调试HelloWorldThis is the name of the gdb binary to useThis is the name of the gdb binary to useThis is the name of the Valgrind binary to useThis is the name of Emacs for running GUDFind out the absolute path to this scri,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本节书摘来异步社区《HotSpot实战》一书中的第1章,第1.3节,作者:陈涛,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.3 实战:在HotSpot内调试HelloWorld

本节讲解的是Java入门程序HelloWorld在HotSpot上的执行过程。我们通过一个普通Java程序的运行过程,能够以点带面地讲解到涉及HotSpot内部实现的基础概念。

虽然是调试简单的HelloWorld程序,但在这个过程中会涉及HotSpot的基本数据结构以及环境准备等内容。理解这些,一方面使读者对HotSpot项目有个感性认识,其实调试HotSpot没有想象的那么困难,这利于我们增强驾驭HotSpot的自信心;另一方面,让我们正式接触到HotSpot的基本代码,并掌握HotSpot项目的基本调试方法。

调试准备过程如图1-6所示,具体步骤如下。

(1)选择调试器。

(2)配置GDB工作目录的绝对路径。

(3)配置JDK和动态链接库路径。

(4)定位Launcher。

(5)运行GDB初始化脚本,准备GDB运行环境。

(6)设置HotSpot项目断点。

(7)启动调试脚本。

(8)虚拟机运行HelloWorld程序,在断点处暂停。

(9)利用GDB命令调试HotSpot虚拟机程序的运行。

b722890a422ecdf303574529a11dfe1875fc8f60

接下来,我们先了解一下如何使用GDB调试程序,然后开启我们的调试之旅。

1.3.1 认识GDB

本地程序(C/C++)的调试,一般使用GDB命令。对于Java程序员来说,GDB有些陌生,其实我们只需要掌握一些基本的调试命令,便足够应付HotSpot的调试任务了。

下面附上一些常用的GDB命令,包括断点、执行、查看代码、查看栈帧、查看数据等,如清单1-16所示。

清单1-16
断点:

break InitializeJVM:在InitializeJVM函数入口处设置断点
break java.c:JavaMain:在源文件java.c的InitializeJVM函数入口处设置断点
break os_linux.cpp:4380:在源文件os_linux.cpp的第4380行处设置断点
break *0x8048000:在地址为0x8048000的地址处设置断点
delete 1:删除断点1
delete:删除所有断点
执行:
step:执行1条语句,会进入函数
step n:执行n条语句,会进入函数
next:与step类似,但是不进入函数
next n:与step n类似,但是不进入函数
continue:继续运行
finish:运行至当前函数返回后退出
查看代码:
list n:查看当前源文件中第n行的代码
list InitializeJVM:查看InitializeJVM函数开始位置的代码
list:查看更多的行
list -:查看上次查看的代码行数之前的代码
默认,GDB打印10行。若需要调整,可使用:
set listsize n:调整打印行数为n行
查看栈帧:
frame n:从当前栈帧移动到#n栈帧
up n:从当前栈帧向上移动n个栈帧
down n:从当前栈帧向下移动n个栈帧
select-frame:查看更多的行
backstrace:查看整个调用栈
backstrace n:与backstrace类似,只不过只查看4个栈帧
backstrace full:查看整个调用栈,另外还打印出局部变量和参数
info args:查看函数参数
info locals:查看局部变量
查看数据:
print expr:查看expr的值,其中expr是源文件中的表达式
print /f expr n:以f指定的格式查看expr的值。其中f表示的格式可以为:
x:十六进制整数
d:有符号整数
u:无符号整数
o:八进制整数
t:二进制整数
c:字符常量
f:浮点数
s:字符串
r:原始格式
a:地址
x 0xbfffd034:查看内存地址为0xbfffd34的值
disassemble:查看汇编代码,反汇编当前函数
info registers:查看所有寄存器的值
print $eax:以十进制形式查看寄存器%eax的值
print /x $eax:以十六进制形式查看寄存器%eax的值

更多GDB的信息,可以参考GDB的官方教程1。

1.3.2 准备调试脚本

在HotSpot编译完成后,会在Jvmg目录下生成一个名为hotspot的脚本文件,如清单1-17所示。使用脚本可以替代大量重复性的输入,并且可以帮助我们准备好调试环境,为我们轻松调试系统创造了良好的环境。我们可以在此脚本文件的基础上调试HotSpot项目。

在启动调试之前,了解调试脚本究竟做了哪些工作是十分有益的,这有助于我们掌握独立分析和解决问题的能力,在出现问题时不致于手忙脚乱,可以利用自身所学知识解决问题。

清单1-17
来源:hotspot/src/os/posix/launcher/launcher.script
描述:调试脚本

#!/bin/bash```
首先是对传入的调试器名称参数进行转换,以便于定位到指定的调试器,支持的调试器包括GDB、GUD、DBX和VALGRIND等。

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”、“-gud”、“-dbx”或“-valgrind”。

# Make sure the paths are fully specified, i.e. they must begin with /.
SCRIPT=$(cd $(dirname $0) && pwd)/$(basename $0)
RUNDIR=$(pwd)
# 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```
${MYDIR}是配置脚本的绝对路径:

Find out the absolute path to this script

MYDIR=$(cd $(dirname $SCRIPT) && pwd)`
${JDK}用来配置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
# 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=i386
# Find out the absolute path to this script
MYDIR=$(cd $(dirname $SCRIPT) && pwd)
SBP=${MYDIR}:${JRE}/lib/${ARCH}
# 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
export LD_LIBRARY_PATH
export JAVA_HOME
JPARMS="$@ $JAVA_ARGS";```
${LAUNCHER}用作定位Launcher。关于Launcher,我们会在下一章中展开探讨。这里只需要知道它是虚拟机启动器程序便可:

Locate the gamma development launcher

LAUNCHER=${MYDIR}/gamma
if [ ! -x $LAUNCHER ] ; then

echo Error: Cannot find the gamma development launcher "$LAUNCHER"
exit 1

fi`
接下来是进行GDB自身初始化工作,包括配置工作路径以及信号等工作:

GDBSRCDIR=$MYDIR
BASEDIR=$(cd $MYDIR/../../.. && pwd)
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```
在这里,可以设置断点。选择你感兴趣的HotSpot项目源代码位置,如JVM初始化模块“InitializeJVM”函数入口。接下来,便可以利用GDB的break命令设置断点,如:

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
}`
剩余配置代码我们可以不做调整:

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```
至此,调试脚本已经准备就绪,接下来,让我们开始HotSpot的调试吧。输入命令:

sh hotspot –gdb HelloWorld`
启动调试,将出现如图1-7所示的界面。

a9573cb040673fa1930ef9e579d6f96b59f1c4d8

HotSpot运行在断点1(InitializeJVM)上停止下来,这时就可以利用前面提到的GDB命令尽情地控制HotSpot的运行了!

如果想让程序继续执行,输入continue命令使虚拟机正常运行下去,可以看到程序输出“Hello hotspot”并正常退出。感兴趣的读者可以亲自动手尝试一下。

建议读者结合源代码,利用GDB命令来跟踪调试HotSpot,查看系统运行时的内部数据和状态。这有两个好处:一方面,这能帮助我们将枯燥的阅读源码任务转换成有趣的虚拟机调试工作;另一方面,也能促进我们加深对HotSpot的理解。

最后

以上就是神勇便当为你收集整理的《HotSpot实战》—— 1.3 实战:在HotSpot内调试HelloWorldThis is the name of the gdb binary to useThis is the name of the gdb binary to useThis is the name of the Valgrind binary to useThis is the name of Emacs for running GUDFind out the absolute path to this scri的全部内容,希望文章能够帮你解决《HotSpot实战》—— 1.3 实战:在HotSpot内调试HelloWorldThis is the name of the gdb binary to useThis is the name of the gdb binary to useThis is the name of the Valgrind binary to useThis is the name of Emacs for running GUDFind out the absolute path to this scri所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部