This chapter describes how you can use dbx to debug an application that is a mixture of JavaTM code and C JNI (Java Native Interface) code or C++ JNI code.
The chapter is organized into the following sections:
You can use the Sun Studio dbx to debug mixed code (Java code and C code or C++ code) running under the SolarisTM OS and the Linux OS.
You can debug several types of Java applications with dbx (see Starting to Debug a Java Application). Most dbx commands operate similarly on native code and Java code.
dbx has the following limitations when debugging Java code:
dbx cannot tell you the state of a Java application from a core file as it can with native code.
dbx cannot tell you the state of a Java application if the application is hung for some reason and dbx is not able to make procedure calls.
Fix and continue, and runtime checking, do not apply to Java applications.
The following environment variables are specific to debugging a Java application with dbx. You can set the JAVASRCPATH, CLASSPATHX, and jvm_invocation environment variables at a shell prompt before starting dbx. The setting of the jdbx_mode environment variable changes as you are debugging your application. You can change its setting with the jon command (jon Command) and the joff command (see joff Command).
jdbx_mode |
The jdbx_mode environment variable can have the following settings: java, jni, or native. For descriptions of the Java, JNI, and native modes, and how and when the mode changes, see dbx Modes for Debugging Java Code. Default: java. |
JAVASRCPATH |
You can use the JAVASRCPATH environment variable to specify the directories in which dbx should look for Java source files. This variable is useful when the Java sources files are not in the same directory as the .class or .jar files. See Specifying the Location of Your Java Source Files for more information. |
CLASSPATHX |
The CLASSPATHX environment variable lets you specify to dbx a path for Java class files that are loaded by custom class loaders. For more information, see Specifying a Path for Class Files That Use Custom Class Loaders. |
jvm_invocation |
The jvm_invocation environment variable lets you customize the way the JVMTM software is started. (The terms “Java virtual machine” and “JVM” mean a virtual machine for the Java platform.) For more information, see Customizing Startup of the JVM Software. |
You can use dbx to debug the following types of Java applications:
A file with a file name that ends in .class
A file with a file name that ends in .jar
A Java application that is started using a wrapper
A running Java application that was started in debug mode to which you attach dbx
A C application or C++ application that embeds a Java application using the JNI_CreateJavaVM interface
dbx recognizes that it is debugging a Java application in all of these cases.
You can debug a file that uses the .class file name extension using dbx as in the following example.
(dbx) debug myclass.class |
If the class that defines the application is defined in a package, you need to include the package path just as when running the application under the JVM software, as in the following example.
(dbx) debug java.pkg.Toy.class |
You can also use a full path name for the class file. dbx automatically determines the package portion of the class path by looking in the .class file and adds the remaining portion of the full path name to the class path. For example, given the following path name, dbx determines that pkg/Toy.class is the main class name and adds /home/user/java to the class path.
(dbx) debug /home/user/java/pkg/Toy.class |
A Java application can be bundled in a JAR (Java Archive) file. You can debug a JAR file using dbx as in the following example.
(dbx) debug myjar.jar |
When you start debugging a file that has a file name ending in .jar, dbx uses the Main_Class attribute specified in the manifest of this JAR file to determine the main class. (The main class is the class within the JAR file that is your application’s entry point. If you use a full path name or relative path name to specify the JAR file, dbx uses the directory name and prefixes it to the class path in the Main-Class attribute.
If you debug a JAR file that does not have the Main-Class attribute, you can use the JAR URL syntax jar:<url>!/{entry} that is specified in the class JarURLConnection of the Java 2 Platform, Standard Edition to specify the name of the main class, as in the following examples.
(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 |
For each of these examples dbx would do the following:
Treat the class path specified after the ! character as the main class (for example, /myclass.class or /x/y/z.class)
Add the name of the JAR file ./myjar.jar, /a/b/c/d/e.jar, or /a/b/c/d.jar to the class path
Begin debugging the main class
If you have specified a custom startup of the JVM software using the jvm_invocation environment variable (see Customizing Startup of the JVM Software), the file name of the JAR file is not automatically added to the class path. In this case, you must add the file name of the JAR file to the class path when you start debugging.
A Java application usually has a wrapper to set environment variables. If your Java application has a wrapper, you need to tell dbx that a wrapper script is being used by setting the jvm_invocation environment variable (see Customizing Startup of the JVM Software).
You can attach dbx to a running Java application if you specified the options shown in the following example when you started the application. After starting the application, you would use the dbx command (see dbx Command) with the process ID of the running Java process to start debugging.
$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent myclass.class $ dbx - 2345 |
For the JVM software to locate libdbx_agent.so, you need to add the appropriate path to LD_LIBRARY_PATH before running the Java application:
If you are using the 32-bit version of the JVM software on a system running the Solaris OS, add /installation_directory/SUNWspro/lib/libdbx_agent.so
If you are using the 64-bit version of the JVM software on a SPARC based system running the Solaris OS, add /installation_directory/SUNWspro/lib/v9/libdbx_agent.so to LD_LIBRARY_PATH.
If you are using the 64-bit version of the JVM software on an x64 based system running the Linux OS, add/installation_directory/sunstudio12/lib/amd64/libdbx_agent.so to LD_LIBRARY_PATH.
The installation_directory is the location where the Sun Studio software is installed.
When you attach dbx to the running application, dbx starts debugging the application in Java mode.
If your Java application requires 64-bit object libraries, include the -d64 option when you start the application. Then when you attach dbx to the application, dbx will use the 64-bit JVM software on which the application is running.
$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent -d64 myclass.class $ dbx - 2345 |
You can debug a C application or C++ application that embeds a Java application using the JNI_CreateJavaVM interface. The C application or C++ application must start the Java application by specifying the following options to the JVM software:
-Xdebug -Xnoagent -Xrundbx_agent |
For the JVM software to locate libdbx_agent.so, you need to add the appropriate path to LD_LIBRARY_PATH before running the Java application:
If you are using the 32-bit version of the JVM software on a system running the Solaris OS, add/installation_directory/SUNWspro/lib/libdbx_agent.so to LD_LIBRARY_PATH.
If you are using the 64-bit version of the JVM software on a SPARC based system running the Solaris OS, add /installation_directory/SUNWspro/lib/v9/libdbx_agent.so to LD_LIBRARY_PATH.
If you are using the 64-bit version of the JVM software on an x64 based system running the Linux OS, add /installation_directory/sunstudio12/lib/amd64/libdbx_agent.so to LD_LIBRARY_PATH.
The installation_directory is the location where the Sun Studio software is installed.
When you use the run command in Java mode, the arguments you give are passed to the application and not to the JVM software. To pass arguments to the JVM software, see Customizing Startup of the JVM Software.
Sometimes your Java source files are not in the same directory as the .class or .jar files. You can use the $JAVASRCPATH environment variable to specify the directories in which dbx should look for Java source files. For example JAVASRCPATH=.:/mydir/mysrc:/mydir/mylibsrc:/mydir/myutils causes dbx to look in the listed directories for source files that correspond to the class files being debugged.
dbx might not be able to find your C source files or C++ source files in the following circumstances:
If your source files are not in the same location as they were when you compiled them
If you compiled your source files on a different system than the one on which you are running dbx and the compile directory does not have the same path name
In such cases, use the pathmap command (see pathmap Command) to map one path name to another so that dbx can find your files.
An application can have custom class loaders that load class files from locations that might not be part of the regular class path. In such situations dbx cannot locate the class files. The CLASSPATHX environment variable lets you specify to dbx a path for the class files that are loaded by their custom class loaders. For example, CLASSPATHX=.:/myloader/myclass:/mydir/mycustom causes dbx to look in the listed directories when it is trying to locate a class file.
To set a stop breakpoint on a Java method in a class file that has not been loaded by the JVM software, use the full name of the class with a stop in command, or the class name with a stop inmethod command. See the following example.
(dbx) stop in Java.Pkg.Toy.myclass.class.mymethod (dbx) stop inmethod myclass.class.mymethod |
To set a stop breakpoint on a C function or C++ function in a shared library that has not been loaded by the JVM software, preload the symbol table of the shared library before setting the breakpoint. For example, if you have a library named mylibrary.so that contains a function named myfunc, you could preload the library and set a breakpoint on the function as follows:
(dbx) loadobject -load fullpathto/mylibrary.so (dbx> stop in myfunc |
You can also load the symbol tables of all dynamically loaded shared objects by running your application once before beginning to debug it with dbx.
You might need to customize startup of the JVM software from dbx to do the following:
Specify a path name for the JVM software (see Specifying a Path Name for the JVM Software)
Pass some run arguments to the JVM software (see Passing Run Arguments to the JVM Software)
Specify a custom wrapper instead of the default Java wrapper for running Java applications (see Specifying a Custom Wrapper for Your Java Application)
Specify 64-bit JVM software (see Specifying 64-bit JVM Software)
You can customize startup of the JVM software using the jvm_invocation environment variable. By default, when the jvm_invocation environment variable is not defined, dbx starts the JVM software as follows
java -Xdebug -Xnoagent -Xrundbx_agent:syncpid : |
When the jvm_invocation environment variable is defined, dbx uses the value of the variable to start the JVM software.
You must include the -Xdebug option in the definition of the jvm_invocation environment variable. dbx expands -Xdebug into the internal options -Xdebug- Xnoagent -Xrundbxagent::sync.
If you do not include the -Xdebug option in the definition, as in the following example, dbx issues an error message.
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 |
By default, dbx starts the JVM software in your path if you do not specify a path name for the JVM software.
To specify a path name for the JVM software, set the jvm_invocation environment variable to the appropriate path name, as in the following example.
jvm_invocation="/myjava/java -Xdebug" |
This setting causes dbx to start the JVM software as follows:
/myjava/java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync |
To pass run arguments to the JVM software, set the jvm_invocation environment variable to start the JVM software with those arguments, as in the following example.
jvm_invocation="java -Xdebug -Xms512 -Xmx1024 -Xcheck:jni" |
This causes dbx to start the JVM software as follows:
java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync= -Xms512 -Xmx1024 -Xcheck:jni |
A Java application can use a custom wrapper for startup. If your application uses a custom wrapper, you can use the jvm_invocation environment variable to specify the wrapper to be used, as in the following example.
jvm_invocation="/export/siva-a/forte4j/bin/forte4j.sh -J-Xdebug" |
This causes dbx to start the JVM software as follows:
/export/siva-a/forte4j/bin/forte4j.sh - -J-Xdebug -J-Xnoagent -J-Xrundbxagent:sync=process_id |
The following wrapper script (xyz) sets a few environment variables and accepts command line options:
#!/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 |
This script accepts some command line options for the JVM software and the user application. For wrapper scripts of this form, you would set the jvm_invocation environment variable and start dbx as follows:
% jvm_invocation="xyz -J-Xdebug -Jany other java options" % dbx myclass.class -Dide=visual |
The following wrapper script (xyz) sets a few environment variables and starts the JVM software, but does not accept any command line options or a class name:
#!/bin/sh CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH ABC=/mydir/abc; export ABC java <options> myclass |
You could use such a script to debug a wrapper using dbx in one of two ways:
You could modify the script to start dbx from inside the wrapper script itself by adding the definition of the jvm_invocation variable to the script and starting dbx:
#!/bin/sh CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH ABC=/mydir/abc; export ABC jvm_invocation="java -Xdebug <options>"; export jvm_invocation dbx myclass.class |
Once you have made this modification, you could start the debugging session by running the script.
You could modify the script slightly to accept some command line options as follows:
#!/bin/sh CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH ABC=/mydir/abc; export ABC JAVA_OPTIONS="$1 <options>" java $JAVA_OPTIONS $2 |
Once you made this modification, you would set the jvm_invocation environment variable and start dbx as follows:
% jvm_invocation="xyz -Xdebug"; export jvm_invocation % dbx myclass.class |
If you want dbx to start 64-bit JVM software to debug an application that requires 64-bit object libraries, include the -d64 option when you set the jvm_invocation environment variable:
jvm_invocation="/myjava/java -Xdebug -d64" |
When debugging a Java application, dbx is in one of three modes:
Java mode
JNI mode
Native mode
When dbx is Java mode or JNI (Java Native Interface) mode, you can inspect the state of your Java application, including JNI code, and control execution of the code. When dbx is in native mode, you can inspect the state of your C or C++ JNI code. The current mode (java, jni, native) is stored in the environment variable jdbx_mode.
In Java mode, you interact with dbx using Java syntax and dbx uses Java syntax to present information to you. This mode is used for debugging pure Java code, or the Java code in an application that is a mixture of Java code and C JNI code or C++ JNI code.
In JNI mode, dbx commands use native syntax and affect native code, but the output of commands shows Java-related status as well as native status, so JNI mode is a “mixed” mode. This mode is used for debugging the native parts of an application that is a mixture of Java code and C JNI code or C++ JNI code.
In native mode, dbx commands affect only a native program, and all Java-related features are disabled. This mode is used for debugging non-Java related programs.
As you execute your Java application, dbx switches automatically between Java mode and JNI mode as appropriate. For example, when it encounters a Java breakpoint, dbx switches into Java mode, and when you step from Java code into JNI code, it switches into JNI mode.
dbx does not switch automatically into native mode. You can switch explicitly from Java or JNI Mode to native mode with the joff command, and from native mode to Java mode with the jon command.
If you interrupt execution of your Java application (for example, with a control-C), dbx tries to set the mode automatically to Java/JNI mode by bringing the application to a safe state and suspending all threads.
If dbx cannot suspend the application and switch to Java/JNI mode, dbx switches to native mode. You can then use the jon command to switch to Java mode so that you inspect the state of the program.
When you are using dbx to debug a mixture of Java and native code, dbx commands fall into several categories:
Commands that accept the same arguments and operate the same way in Java mode or JNI mode as in native mode (see Commands With Identical Syntax and Functionality in Java Mode and Native Mode).
Commands have arguments that are valid only in Java mode or JNI mode, as well as arguments that are valid only in native mode (see Commands With Different Syntax in Java Mode).
Commands that are valid only in Java mode or JNI mode (see Commands Valid Only in Java Mode).
Any commands not included in one of these categories work only in native mode.
The Java expression evaluator used in most dbx commands supports the following constructs:
All literals
All names and field accesses
this and super
Array accesses
Casts
Conditional binary operations
Method calls
Other unary/binary operations
Assignment to variables or fields
instanceof operator
Array length operator
The Java expression evaluator does not support the following constructs:
Qualified this, for example, <ClassName>.this
Class instance creation expressions
Array creation expressions
String concatenation operator
Conditional operator ? :
Compound assignment operators, for example, x += 3
A particularly useful way of inspecting the state of your Java application is using the display facility in the dbx Debugger.
Depending on precise value semantics in expressions that do more than just inspect data is not recommended.
Much of the information about a Java application is normally available only after the JVM software has started, and is unavailable after the Java application has finished executing. However, when you debug a Java application with dbx, dbx gleans some of the information it needs from class files and JAR files that are part of the system class path and user class path before it starts the JVM software. This allows dbx to do better error checking on breakpoints before you run the application.
Some Java classes and their attributes might not be accessible through the class path. dbx can inspect and step through these classes, and the expression parser can access them, once they are loaded. However, the information it gathers is temporary and is no longer available after the JVM software terminates.
Some information that dbx needs to debug your Java application is not recorded anywhere so dbx skims Java source files to derive this information as it is debugging your code.
The following dbx commands have the same syntax and perform the same operations in Java mode as in native mode.
Command |
Functionality |
---|---|
attach |
Attaches dbx to a running process, stopping execution and putting the program under debugging control |
cont |
Causes the process to continue execution |
dbxenv |
List or set dbx environment variables |
delete |
Deletes breakpoints and other events |
down |
Moves down the call stack (away from main) |
dump |
Prints all variables local to a procedure or method |
file |
Lists or changes the current file |
frame |
Lists or changes the current stack frame number |
handler |
Modifies event handlers (breakpoints) |
import |
Import commands from a dbx command library |
line |
Lists or changes the current line number |
list |
Lists or changes the current line number |
next |
Steps one source line (steps over calls) |
pathmap |
Maps one path name to another for finding source files, etc. |
proc |
Displays the status of the current process |
prog |
Manages programs being debugged and their attributes |
quit |
Exits dbx |
rerun |
Runs the program with no arguments |
runargs |
Changes the arguments of the target process |
status |
Lists the event handlers (breakpoints) |
step up |
Steps up and out of the current function or method |
stepi |
Steps one machine instruction (steps into calls) |
up |
Moves up the call stack (toward main) |
whereami |
Displays the current source line |
The following dbx commands have different syntax for Java debugging than for native code debugging, and operate differently in Java mode than in native mode.
Command |
Native Mode Functionality |
Java Mode Functionality |
---|---|---|
assign |
Assigns a new value to a program variable |
Assigns a new value to a local variable or parameter |
call |
Calls a procedure |
Calls a method |
dbx |
Starts dbx |
Starts dbx |
debug |
Loads the specified application and begins debugging the application |
Loads the specified Java application, checks for the existence of the class file, and begins debugging the application |
detach |
Releases the target process from dbx’s control |
Releases the target process from dbx’s control |
display |
Evaluates and prints expressions at every stopping point. |
Evaluates and prints expressions, local variables, or parameters at every stopping point |
files |
Lists file names that match a regular expression |
Lists all of the Java source files known to dbx |
func |
Lists or changes the current function |
Lists or changes the current method |
next |
Steps one source line (stepping over calls) |
Steps one source line (stepping over calls) |
|
Prints the value of an expression |
Prints the value of an expression, local variable, or parameter. |
run |
Runs the program with arguments |
Runs the program with arguments |
step |
Steps one source line or statement (stepping into calls) |
Steps one source line or statement (stepping into calls) |
stop |
Sets a source-level breakpoint |
Sets a source-level breakpoint |
thread |
Lists or changes the current thread |
Lists or changes the current thread |
threads |
Lists all threads |
Lists all threads |
trace |
Shows executed source lines, function calls, or variable changes |
Shows executed source lines, function calls, or variable changes |
undisplay |
Undoes display commands |
Undoes display commands |
whatis |
Prints the type of expression or declaration of type |
Prints the declaration of an identifier |
when |
Executes commands when a specified event occurs |
Executes commands when a specified event occurs |
where |
Prints the call stack |
Prints the call stack |
The following dbx commands are valid only in Java mode or JNI mode.
Command |
Functionality |
---|---|
java |
Used when dbx is in JNI mode to indicate that the Java version of a specified command is to be executed |
javaclasses |
Prints the names of all Java classes known to dbx when you give the command |
joff |
Switches dbx from Java mode or JNI mode to native mode |
jon |
Switches dbx from native mode to Java mode |
jpkgs |
Prints the names of all Java packages known to dbx when you give the command |
native |
Used when dbx is in Java mode to indicate that the native version of a specified command is to be executed |