閱讀943 返回首頁    go 小米 go 小米6


編繹調試HotSpot JVM及在Eclipse裏調試

編繹整個OpenJDK要很久,而且有很多東西是不需要的。研究HotSpot的話,其實隻要下HotSpot部分的代碼就可以了。

下麵簡單記錄下編繹調試HotSpot一些步驟。

一、編繹

進入hotsopt的make目錄下:

cd code/cpp/openjdk/hotspot/make/

用make help可以看到有很多有用的信息。當然查看Makefile文件,裏麵也有很多有用的注釋。

make help會輸出當前的一些環境變量的設置,如果不對,自然編繹不過去。

設置環境變量:

unset JAVA_HOME
export ARCH_DATA_MODEL=64
export JDK_IMPORT_PATH=/usr/lib/jvm/java-7-oracle
export ALT_BOOTDIR=/usr/lib/jvm/java-7-oracle
export ZIP_DEBUGINFO_FILES=0                      //這個貌似不起作用。。這些變量的定義貌似都在def.make文件裏。還有一個這樣的參數:FULL_DEBUG_SYMBOLS
用make all_beug來編繹。

編繹後好,到目錄下openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg,執行 unzip libjvm.diz,解壓得到調試信息文件

這個算是個坑,默認情況下,會壓縮調試信息文件,這樣用gdb調試時,就會出現下麵的提示:

no debugging symbols found

從編繹的輸出信息來看,是有一個ZIP_DEBUGINFO_FILES的參數,但是設置了環境變量卻不起效。

二、調試

在openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg目錄下,有一個hotspot的腳本,隻要執行這個腳本,就可以啟動Java進程了。

用 ./hotspot -gdb 就會自動進入gdb調試,並停在main函數入口。

後麵還可以加一些jvm的啟動參數等。


這個./hotsopt 腳本是怎麼工作的?

用 sh -x ./hotspot 來查看這個腳本的執行過程,可以發現實際上是設置了 LD_LIBRARY_PATH的環境變量,再調用了一個./gamma 的程序。

+ LD_LIBRARY_PATH=/home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg:/usr/lib/jvm/java-7-oracle/jre/lib/amd64
+ export LD_LIBRARY_PATH
+ JPARMS= 
+ LAUNCHER=/home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/gamma
+ [ ! -x /home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/gamma ]
+ GDBSRCDIR=/home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg
+ cd /home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/../../..
+ pwd
+ BASEDIR=/home/hengyunabc/code/cpp/openjdk/hotspot/build
+ LD_PRELOAD= exec /home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/gamma

實際上是通過設置LD_LIBRARY_PATH 環境變量,去優先加載編繹好的libjvm.so。hotsopt jvm的代碼都編繹鏈接在libjvm.so這個文件裏。

查看./hotspot裏的這個函數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
}

所以,其實也可以這樣開始調試:

export LD_LIBRARY_PATH=/home/hengyunabc/code/cpp/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg:/usr/lib/jvm/java-7-oracle/jre/lib/amd64
gdb
在gdb裏執行file ./gamma,然後就可以調試了。


三、使用Eclipse來調試

盡管gdb功能強大,命令豐富,但是在查看調試的變量時,十分的不方便。特別是hotsopt裏,很多東西都是用指針來存放的,有時要跳轉好幾層才能查看到想要的信息。

下載Eclipse的CDT版,或者安裝CDT的插件。

導入Eclipse工程:

"File", "Import", "C/C++", "Existing Code as Makefile Project":


先擇Linux GCC:


然後,就可以把項目導到Eclipse裏了。會有很多錯誤提示,但是不影響我們的調試。


在Eclipse裏調試:

首先,要設置要調試的文件的路徑:


設置LD_LIBRARY_PATH:


然後就可以調試了。還有一個地方比較重要:

想在運行時輸入gdb指令,可以在console view,在右邊的下拉裏,可以發現有一個gbd的console,還有一個gdb trace的console。 


四、一些有用的東東

jvmg1目錄下是O1優化下的,fastdebug目錄下是O3優化的。

java 進程的main入口在:openjdk/hotspot/src/share/tools/launcher/java.c 文件裏。

在gdb裏,用info sharedlibrary 命令查看實際使用到的是哪些so文件。

用file命令來判斷一個可執行文件,so是32位的還是64位的。

查看一個so文件是否包含調試信息,可以用readelf -S xxx.so 命令來查看是否有debug相關的段。這個方法不一定準確,因為調試信息有可能放在外部文件裏。

最後更新:2017-04-03 12:53:42

  上一篇:go JLINK 10針J和20針JTAG接口連接方法
  下一篇:go [LeetCode]7.Reverse Integer