java 按步骤执行模式,第 17 章 使用 dbx 调试 Java 应用程序 (Sun Studio 12 Update 1:使用 dbx 调试程序)...

第 17 章 使用 dbx 调试 Java 应用程序

本章说明如何使用 dbx 来调试使用 JavaTM 代码和 C JNI(Java Native Interface,Java 本地接口)代码或 C++ JNI 代码混合编写的应用程序。

本章由以下部分组成:

使用 dbx 调试 Java 代码

可以使用 Sun Studio dbx 调试运行在 SolarisTM OS 和 Linux OS 下的混合代码(Java 代码和 C 代码或 C++ 代码)。

使用 dbx 调试 Java 代码的功能

使用 dbx 可以调试几种类型的 Java 应用程序(请参见开始调试 Java 应用程序)。在调试本地代码和 Java 代码时,大多数 dbx 命令的使用方式都类似。

使用 dbx 调试 Java 代码的限制

dbx 在调试 Java 代码时有以下限制:

dbx 无法像对待本机代码那样通过核心转储文件来指明 Java 应用程序的状态。

如果 Java 应用程序由于某种原因挂起,dbx 无法指示该应用程序的状态,且 dbx 也不能进行过程调用。

修复并继续以及运行时检查不适用于 Java 应用程序。

Java 调试的环境变量

以下环境变量专门用于使用 dbx 调试 Java 应用程序。您可以在启动 dbx 之前在 shell 提示符下设置 JAVASRCPATH、CLASSPATHX 和 jvm_invocation 环境变量,也可以通过 dbx 命令行设置这些环境变量。jdbx_mode 环境变量的设置会在调试应用程序的过程中发生更改。可以使用 jon 命令(请参见jon 命令)和 joff 命令(请参见joff 命令)更改其设置。

jdbx_modejdbx_mode 环境变量的设置如下:java、jni 或 native。有关 Java、JNI 和本地模式的说明以及模式变化的方式和时机,请参见调试 Java 代码的 dbx 模式。缺省值: java.

JAVASRCPATH可以使用 JAVASRCPATH 环境变量指定 dbx 从中查找 Java 源文件的目录。Java 源文件与 .class 或 .jar 文件不在同一目录中时,此变量很有用。有关更多信息,请参见指定 Java 源文件的位置。

CLASSPATHX使用 CLASSPATHX 环境变量可以为 dbx 指定由定制类加载器装入的 Java 类文件的路径。有关更多信息,请参见为使用自定义类加载器的类文件指定路径。

jvm_invocation使用 jvm_invocation 环境变量可以定制 JVMTM 软件的启动方式。(术语“Java 虚拟机”和 "JVM" 表示用于 Java 平台的虚拟机。)有关更多信息,请参见定制 JVM 软件的启动。

开始调试 Java 应用程序

可以使用 dbx 调试以下类型的 Java 应用程序:

文件名以 .class 结尾的文件

文件名以 .jar 结尾的文件

使用包装器启动的 Java 应用程序

在调试模式下启动并连接了 dbx 的运行的 Java 应用程序

使用 JNI_CreateJavaVM 接口嵌入 Java 应用程序的 C 应用程序或 C++ 应用程序

在上述所有情况下,dbx 均可识别其正在调试的是 Java 应用程序。

调试类文件

可以使用 dbx 调试文件扩展名为 .class 的文件,如下例所示。

(dbx) debug myclass.class

如果定义应用程序的类在包中定义,便需要如同在 JVM 软件上运行应用程序那样加入包的路径,如下例所示。

(dbx) debug java.pkg.Toy.class

也可以使用类文件的全路径名。dbx 通过在 .class 文件中进行查找来自动确定类路径的软件包部分,然后将全路径名的剩余部分添加到类路径中。例如,假定有以下路径名,dbx 会确定 pkg/Toy.class 是主类名,然后将 /home/user/java 添加到类路径中。

(dbx) debug /home/user/java/pkg/Toy.class

调试 JAR 文件

Java 应用程序可以使用 JAR(Java 归档)文件打包。可以使用 dbx 调试 JAR 文件,如下例所示。

(dbx) debug myjar.jar

开始调试文件名以 .jar 结尾的文件时,dbx 会使用在此 JAR 文件的清单中指定的 Main_Class 属性来确定主类。(主类是 JAR 文件内作为应用程序入口点的类。)如果使用全路径名或相对路径名来指定 JAR 文件,dbx 会使用目录名,并在 Main-Class 属性中将其作为类路径的前缀。

如果调试无 Main-Class 属性的 JAR 文件,可以使用 JAR URL 语法 jar:!/{entry}(在 Java 2 平台标准版的 JarURLConnection 类中指定)来指定主类的名称,如以下示例所示。

(dbx) debug jar:myjar.jar!/myclass.class

(dbx) debug jar:/a/b/c/d/e.jar!/x/y/z.class

(dbx) debug jar:file:/a/b/c/d.jar!/myclass.class

对于这些示例中的每一个示例,dbx 都会执行以下操作:

将 ! 字符后指定的类路径作为主类(例如,/myclass.class 或 /x/y/z.class)来处理

将 JAR 文件名 ./myjar.jar、/a/b/c/d/e.jar 或 /a/b/c/d.jar 添加到类路径中

开始调试主类

注 –

如果使用 jvm_invocation 环境变量指定了 JVM 软件的定制启动(请参见定制 JVM 软件的启动),则不会将 JAR 文件名自动添加到类路径中。在这种情况下,必须在开始调试时将 JAR 文件名添加到类路径中。

调试有包装器的 Java 应用程序

Java 应用程序通常有一个用于设置环境变量的包装器。如果 Java 应用程序有包装器,需要通过设置 jvm_invocation 环境变量将要使用包装器脚本这一情况告知 dbx(请参见定制 JVM 软件的启动)。

将 dbx 连接到正在运行的 Java 应用程序

可以将 dbx 连接到正在运行的 Java 应用程序,前提是在启动该应用程序时指定了下例所示的选项。启动应用程序后,可以将 dbx 命令(请参见dbx 命令) 与正在运行的 Java 进程的进程 ID 结合使用以开始调试。

$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent myclass.class

$ dbx - 2345

为了使 JVM 软件能够找到 libdbx_agent.so,需要在运行 Java 应用程序前将适当路径添加到 LD_LIBRARY_PATH 中:

如果在运行 Solaris OS 的系统上使用 32 位版本的 JVM 软件,则添加 /installation_directory/SUNWspro/lib/libdbx_agent.so。

如果在运行 Solaris OS 且基于 SPARC 的系统上使用 64 位版本的 JVM 软件,则将 /installation_directory/SUNWspro/lib/v9/libdbx_agent.so 添加至 LD_LIBRARY_PATH。

如果在运行 Linux OS 且基于 x64 的系统上使用 64 位版本的 JVM 软件,则将 /installation_directory/sunstudio12/lib/amd64/libdbx_agent.so 添加至 LD_LIBRARY_PATH。

installation_directory 是

Sun Studio 软件的安装位置。

将 dbx 连接到正在运行的应用程序时,dbx 会以 Java 模式开始调试应用程序。

如果 Java 应用程序需要 64 位目标库,请在启动应用程序时包括 -d64 选项。之后,将 dbx 连接到应用程序时,dbx 将使用运行该应用程序的 64 位 JVM 软件。

$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent -d64 myclass.class

$ dbx - 2345

调试内嵌 Java 应用程序的 C 应用程序或 C++ 应用程序

可以使用 JNI_CreateJavaVM 接口调试内嵌 Java 应用程序的 C 应用程序或 C++ 应用程序。C 应用程序或 C++ 应用程序必须通过为 JVM 软件指定以下选项,才能启动 Java 应用程序:

-Xdebug -Xnoagent -Xrundbx_agent

为了使 JVM 软件能够找到 libdbx_agent.so,需要在运行 Java 应用程序前将适当路径添加到 LD_LIBRARY_PATH 中:

如果在运行 Solaris OS 的系统上使用 32 位版本的 JVM 软件,则将 /installation_directory/SUNWspro/lib/libdbx_agent.so 添加至 LD_LIBRARY_PATH。

如果在运行 Solaris OS 且基于 SPARC 的系统上使用 64 位版本的 JVM 软件,则将 /installation_directory/SUNWspro/lib/v9/libdbx_agent.so 添加至 LD_LIBRARY_PATH。

如果在运行 Linux OS 且基于 x64 的系统上使用 64 位版本的 JVM 软件,则将 /installation_directory/sunstudio12/lib/amd64/libdbx_agent.so 添加至 LD_LIBRARY_PATH。

installation_directory 是

Sun Studio 软件的安装位置。

将参数传递给 JVM 软件

在 Java 模式下使用 run 命令时,会将提供的参数传递给应用程序,而非 JVM 软件。要将参数传递给 JVM 软件,请参见定制 JVM 软件的启动。

指定 Java 源文件的位置

有时 Java 源文件与 .class 或 .jar 文件不在同一目录中。可以使用 $JAVASRCPATH 环境变量指定 dbx 查找 Java 源文件的目录。例如,JAVASRCPATH=.:/mydir/mysrc:/mydir/mylibsrc:/mydir/myutils 会使 dbx 在与正被调试的类文件对应的源文件的列出目录中查找。

指定 C 源文件或 C++ 源文件的位置

在以下情况下,dbx 可能找不到 C 源文件或 C++ 源文件:

如果源文件不在编译时所在的位置

如果编译源文件的系统与运行 dbx 的系统不同,而且编译目录的路径名不同

在此类情况下,请使用 pathmap 命令(请参见pathmap 命令)将一个路径名映射到另一个路径名,以便 dbx 可以找到您的文件。

为使用自定义类加载器的类文件指定路径

应用程序可以有从可能不属于常规类路径的位置装入类文件的定制类加载器。在这种情况下,dbx 找不到类文件。使用环境变量 CLASSPATHX 可以为 dbx 指定由定制类加载器装入的类文件的路径。例如,CLASSPATHX=.:/myloader/myclass:/mydir/mycustom 会使 dbx 在尝试查找类文件时到列出的目录中查找。

在 Java 方法中设置断点

与本地应用程序不同,Java 应用程序不包含便于访问的名称索引。因此不能简单地键入:

(dbx) stop in myMethod

而是需要使用方法的完整路径:

(dbx) stop in com.any.library.MyClass.myMethod

使用 MyClass 的某个方法停止时是一种例外情况,在这种情况下,使用 myMethod 就应足可以了。

避免包含该方法的完整路径的一种方式是,使用 stop inmethod:

(dbx) stop inmethod myMethod

但是这样做可能会导致在多个方法名称 myMethod 中停止。

在本地 (JNI) 代码中设置断点

包含 JNI C 或 C++ 代码的共享库由 JVM 动态装入,在这些库中设置断点需要一些其他步骤。有关更多信息,请参见在动态装入的库中设置断点。

定制 JVM 软件的启动

可能需要通过 dbx 定制 JVM 软件的启动,以便执行以下操作:

为 JVM 软件指定路径名(请参见指定 JVM 软件的路径名)

将一些运行参数传递到 JVM 软件(请参见将运行参数传递给 JVM 软件)

指定定制包装器而不是缺省的 Java 包装器,供运行 Java 应用程序时使用(请参见指定 Java 应用程序的自定义包装器)

指定 64 位 JVM 软件(请参见指定 64 位 JVM 软件)

可以使用环境变量 jvm_invocation 定制 JVM 软件的启动。缺省情况下,环境变量 jvm_invocation 未定义时,dbx 将按以下方式启动 JVM 软件

java -Xdebug -Xnoagent -Xrundbx_agent:syncpid

定义环境变量 jvm_invocation 后,dbx 会使用该变量的值来启动 JVM 软件。

必须在环境变量 jvm_invocation 的定义中包括 -Xdebug 选项。dbx 会将 -Xdebug 扩展为内部选项 -Xdebug- Xnoagent -Xrundbxagent::sync。

如果不在定义中包括 -Xdebug 选项,如下例所示,dbx 会显示错误消息。

jvm_invocation="/set/java/javasoft/sparc-S2/jdk1.2/bin/java"dbx: Value of `$jvm_invocation’ must include an option to invoke the VM in debug mode

指定 JVM 软件的路径名

缺省情况下,如果不指定 JVM 软件的路径名,dbx 将在您的路径中启动 JVM 软件。

要指定 JVM 软件的路径名,请将环境变量 jvm_invocation 设置为相应的路径名,如下例所示。

jvm_invocation="/myjava/java -Xdebug"

此设置会使 dbx 按以下方式启动 JVM 软件:

/myjava/java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync

将运行参数传递给 JVM 软件

要将运行参数传递给 JVM 软件,请对环境变量 jvm_invocation 进行设置,以使用那些参数启动 JVM 软件,如下例所示。

jvm_invocation="java -Xdebug -Xms512 -Xmx1024 -Xcheck:jni"

这将使 dbx 按以下方式启动 JVM 软件:

java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync= -Xms512 -Xmx1024 -Xcheck:jni

指定 Java 应用程序的自定义包装器

Java 应用程序可以使用定制包装器来启动。如果应用程序使用定制包装器,便可以使用环境变量 jvm_invocation 来指定要使用的包装器,如下例所示。

jvm_invocation="/export/siva-a/forte4j/bin/forte4j.sh -J-Xdebug"

这将使 dbx 按以下方式启动 JVM 软件:

/export/siva-a/forte4j/bin/forte4j.sh - -J-Xdebug -J-Xnoagent -J-Xrundbxagent:sync=process_id

使用接受命令行选项的自定义包装器

以下包装器脚本 (xyz) 会设置几个环境变量并接受命令行选项:

#!/bin/sh

CPATH=/mydir/myclass:/mydir/myjar.jar; export CPATH

JARGS="-verbose:gc -verbose:jni -DXYZ=/mydir/xyz"

ARGS=

while [ $# -gt 0 ] ; do

case "$1" in

-userdir) shift; if [ $# -gt 0 ]

; then userdir=$1; fi;;

-J*) jopt=`expr $1 : ’-J<.>’`

; JARGS="$JARGS ’$jopt’";;

*) ARGS="$ARGS ’$1’" ;;

esac

shift

done

java $JARGS -cp $CPATH $ARGS

此脚本接受 JVM 软件和用户应用程序的某些命令行选项。对于这种形式的包装器脚本,可设置环境变量 jvm_invocation 并按以下方式启动 dbx:

% jvm_invocation="xyz -J-Xdebug -Jany other java options"

% dbx myclass.class -Dide=visual

使用不接受命令行选项的自定义包装器

以下包装器脚本 (xyz) 会设置几个环境变量并启动 JVM 软件,但不接受任何命令行选项或类名:

#!/bin/sh

CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH

ABC=/mydir/abc; export ABC

java myclass

可以通过 dbx 并采用以下两种方法之一,使用此类脚本来调试包装器:

可以对脚本进行修改,即将变量 jvm_invocation 的定义添加到脚本中并启动 dbx,以从包装器脚本内部启动 dbx:

#!/bin/sh

CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH

ABC=/mydir/abc; export ABC

jvm_invocation="java -Xdebug "; export jvm_invocation

dbx myclass.class

修改后,便可运行脚本来启动调试会话。

可以略微修改脚本来接受某些命令行选项,如下所示:

#!/bin/sh

CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH

ABC=/mydir/abc; export ABC

JAVA_OPTIONS="$1 "

java $JAVA_OPTIONS $2

修改后,便可设置环境变量 jvm_invocation,并按以下方式启动 dbx:

% jvm_invocation="xyz -Xdebug"; export jvm_invocation

% dbx myclass.class

指定 64 位 JVM 软件

如果希望 dbx 启动 64 位 JVM 软件来调试需要 64 位对象库的应用程序,请在设置环境变量 jvm_invocation 时包含 -d64 选项:

jvm_invocation="/myjava/java -Xdebug -d64"

调试 Java 代码的 dbx 模式

调试 Java 应用程序时,dbx 处于以下三种模式之一:

Java 模式

JNI 模式

本地模式

当 dbx 处于 Java 模式或 JNI(Java Native Interface,Java 本地接口)模式下时,可以检查 Java 应用程序(包括 JNI 代码)的状态,并控制代码的执行。当 dbx 处于本地模式下时,可以检查 C 或 C++ JNI 代码的状态。当前模式(java、jni、native)存储在环境变量 jdbx_mode 中。

在 Java 模式下,可以使用 Java 语法与 dbx 交互,dbx 会使用 Java 语法显示信息。此模式用于调试纯 Java 代码或使用 Java 代码、C JNI 代码或 C++ JNI 代码混合编写的应用程序中的 Java 代码。

在 JNI 模式下,dbx 命令使用本地语法并会影响本地代码,但命令的输出既显示与 Java 有关的状态,也显示本地状态,所以 JNI 模式是一种“混合”模式。此模式用于调试使用 Java 代码、C JNI 代码或 C++ JNI 代码混合编写的应用程序的本地部分。

在本地模式下,dbx 命令只影响本地程序,所有与 Java 有关的功能都会被禁用。此模式用于调试与 Java 无关的程序。

在执行 Java 应用程序的过程中,dbx 会根据情况自动在 Java 模式和 JNI 模式间切换。例如,遇到 Java 断点时,dbx 会自动切换到 Java 模式,而当您从 Java 代码步入 JNI 代码时,它又会切换到 JNI 模式。

从 Java 或 JNI 模式切换到本地模式

dbx 不会自动切换到本地模式。可以使用 joff 命令显式从 Java 模式或 JNI 模式切换到本地模式,也可以使用 jon 命令从本地模式切换到 Java 模式。

中断执行时切换模式

如果中断执行 Java 应用程序(例如,使用 Ctrl-C),dbx 会尝试通过将应用程序置于安全状态并挂起所有线程将模式自动设置为 Java/JNI 模式。

如果 dbx 无法挂起应用程序并切换到 Java/JNI 模式,dbx 便会切换到本地模式。然后,您可以使用 jon 命令切换到 Java 模式来检查程序的状态。

在 Java 模式下使用 dbx 命令

使用 dbx 调试由 Java 代码和本地代码组成的混合型代码时,dbx 命令分为以下几类:

第一类命令:接受相同的参数,而且在 Java 模式或 JNI 模式下的运行方式与本地模式下相同(请参见在 Java 模式和本地模式下具有完全相同语法和功能的命令)。

第二类命令:具有仅在 Java 模式或 JNI 模式下有效的参数,或者仅在本地模式下有效的参数(请参见在 Java 模式下有不同语法的命令))。

第三类命令:仅在 Java 模式或 JNI 模式下有效(请参见只在 Java 模式下有效的命令)。

未包括在上述任一类别的命令只在本地模式下有效。

dbx 命令中的 Java 表达式求值

在大多数 dbx 命令中使用的 Java 表达式计算器支持以下构造:

所有文字

所有名称和字段访问

this 和 super

数组访问

类型转换

条件二进制运算

方法调用

其他一元/二进制运算

对变量或字段赋值

instanceof 操作符

数组长度操作符

Java 表达式计算器不支持以下构造:

限定的 this,例如 .this

类实例创建表达式

数组创建表达式

字符串并置操作符

条件操作符 ?:

复合赋值操作符,例如 x += 3

一种特别有用的检查 Java 应用程序状态的方式是在 IDE 或 dbxtool 中使用监视功能。

建议不要依赖表达式中作用不限于检查数据的精确值语义。

dbx 命令使用的静态和动态信息

只有在 JVM 软件启动后,有关 Java 应用程序的许多信息才可正常使用,并且执行完 Java 应用程序后,这些信息将不再使用。但是,使用 dbx 调试 Java 应用程序时,dbx 会在启动 JVM 软件前从属于系统类路径和用户类路径的类文件和 JAR 文件中收集其需要的一些信息。这样 dbx 便可在您运行应用程序前更好地对断点进行错误检查。

有些 Java 类及其属性可能无法通过类路径进行访问。dbx 可以检查并逐步执行这些类,这些类被装入后,表达式解析器便可以访问它们。但它收集的信息是临时性的,JVM 软件终止后便不再可用。

dbx 调试 Java 应用程序所需的某些信息在任何地方均无记录,因此,dbx 会在调试代码期间浏览 Java 源文件来取得这些信息。

在 Java 模式和本地模式下具有完全相同语法和功能的命令

以下 dbx 命令在 Java 模式下和本地模式下具有相同的语法并执行相同的操作。

命令功能

attach将 dbx 连接到正在运行的进程,从而停止执行并将程序置于调试控制之下

cont使进程继续执行

dbxenv列出或设置 dbx 环境变量

delete删除断点和其他事件

down将调用栈下移(远离 main)

dump打印过程或方法的所有局部变量

file列出或更改当前文件

frame列出或更改当前栈帧号

handler修改事件处理程序(断点)

import从 dbx 命令库中导入命令

line列出或更改当前行号

list列出或更改当前行号

next单步执行一个源代码行(步过调用)

pathmap将一个路径名映射至另一个路径名,以查找源文件等

proc显示当前进程的状态

prog管理正被调试的程序和它们的属性

quit退出 dbx

rerun不带参数运行程序

runargs更改目标进程的参数

status列出事件处理程序(断点)

step up向上单步执行并步出当前函数或方法

stepi单步执行一个机器指令(步入调用)

up将调用栈上移(靠近 main)

whereami显示当前源代码行

在 Java 模式下有不同语法的命令

以下 dbx 命令在进行 Java 调试时所用的语法与进行本地代码调试时所用的语法不同,而且在 Java 模式下的运行方式也与本地模式下的运行方式不同。

命令本地模式功能Java 模式功能

assign为程序变量赋新值为局部变量或参数赋新值

call调用过程调用方法

dbx启动 dbx启动 dbx

debug装入指定应用程序,然后开始调试该应用程序装入指定 Java 应用程序,接着检查类文件是否存在,然后开始调试应用程序

detach使目标进程脱离 dbx 的控制使目标进程脱离 dbx 的控制

display在每个停止点对表达式求值并打印。在每个停止点对表达式、局部变量或参数求值并打印

files列出与某个正规表达式匹配的文件名列出 dbx 已知的所有 Java 源文件

func列出或更改当前函数列出或更改当前方法

next单步执行一个源代码行(步过调用)单步执行一个源代码行(步过调用)

print打印表达式的值打印表达式、局部变量或参数的值。

run带参数运行程序带参数运行程序

step单步执行一个源代码行或语句(正在步入调用)单步执行一个源代码行或语句(正在步入调用)

stop设置源码级断点设置源码级断点

thread列出或更改当前线程列出或更改当前线程

threads列出所有线程列出所有线程

trace显示执行的源代码行、函数调用或变量更改显示执行的源代码行、函数调用或变量更改

undisplay撤消 display 命令撤消 display 命令

whatis打印表达式类型或类型声明打印标识符声明

when指定事件发生时执行命令指定事件发生时执行命令

where打印调用栈打印调用栈

只在 Java 模式下有效的命令

以下 dbx 命令仅在 Java 模式或 JNI 模式下有效。

命令功能

java当 dbx 处于 JNI 模式下时,用于指示将执行的是 Java 版本的指定命令

javaclasses发出该命令后,打印 dbx 已知的所有 Java 类的名称

joff将 dbx 从 Java 模式或 JNI 模式切换到本地模式

jon将 dbx 从本地模式切换到 Java 模式

jpkgs发出该命令后,打印 dbx 已知的所有 Java 程序包的名称

native当 dbx 处于 Java 模式下时,用于指示将执行的是本地版本的指定命令

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值