# JDEbug User's Guide

## About JDEbug

JDEbug is a Java debugger that comes with the Java Development Environment for Emacs. It permits you to execute a Java program step-by-step and display and modify the program's internal state. JDEbug features include:

- Source-level debugging. JDEbug maintains a source line pointer that moves as you step through a program. You can also set breakpoints in source buffers.
- Automatic local variable display. JDEbug displays the values of local variables as you step through source code and when the target process stops at a breakpoint.
- Object browsing. You can expand the local variable display to show object fields to any depth.
- Stack navigation. At each program step and breakpoint, you can move up or down the stack with a single command. The JDE moves the source cursor to the current line in the current stack frame and displays the local variables in that frame.
- Multiprocess debugging. You can control execution and display the internal state of multiple, independent processes in the same debug session.
- Expression evaluation. You can evaluate any expression that is valid at the current suspension point.
- Method tracing. The debugger optionally lists enties and/or exits from all methods of specified classes. You can define filters to eliminate unwanted traces.
- Exception tracing. The debugger optionally lists all exceptions of specified types. You can define filters to eliminate unwanted traces.

## JDEbug Requirements

JDEBug requires a virtual machine that conforms to the specifications of the Java Debug Platform Architecture (JPDA) defined by Sun Microsystems. The vm shipped with Sun's Java SDK 1.3 for Windows and Solaris conform to the JPDA specification.

In addition, JPDA backward compatibility packages are available for Sun's Java SDK 1.2.2 for Windows and Linux platforms, respectively, and for the Reference Version of the SDK 1.2.2 for the Solaris platform.

Note JPDA does not work reliably with the Production Version of the SDK 1.2.2 for Solaris. For example, attempting to attach to a process on the Production Version results in the following error:

    Error [4] in accept() call!
    err:: Interrupted system call
    Socket transport failed to init.
    dt_socket transport error; accept failed, rc = -1

If you want to use JDEbug on Solaris, you must use it with the Solaris Reference Version of SDK 1.2.2 or with the Solaris version of SDK 1.3.

The SDK 1.2.2 for Linux includes the JPDA components. You must download the JPDA compatibility packages for the Windows and Solaris versions of SDK 1.2.2 from the JPDA website.

Note The JDE also provides a source-level debugging interface to `jdb`, the command-line debugger that comes with all version's of Sun's Java SDK. You can use this interface to debug applications running on Sun vm's that do not support the JPDA specification. See Debugging with jdb for more information.

### JDEbug and HotSpot

JPDA does not run reliably when a vm is operating in HotSpot mode. For example, JPDA sometimes fails to stop the debuggee process at breakpoints and has trouble getting the this object of the method in which the debuggee process is currently suspended. Sun's JPDA development team is aware of this problem and is working to provide a solution. Meanwhile, you can work around the problem by running the vm in "classic" mode. See Launching an Application in Classic Mode for more information.

## Setting Up JDEbug

Setting up JDEbug entails the following tasks:

- Select JDEbug as your debugger.
- Specify the location of the JDK's JPDA libraries.
- Specify the locations of Java source files on your system.

The following sections explain how to perform these tasks.

### Selecting JDEbug As Your Debugger

The JDE is configured by default to serve as a source-level debugger front-end to jdb, the command-line debugger that comes with Sun's Java SDK. To use JDEbug, you must set the value of the JDE customization variable `jde-db-debugger` to specify JDEBug. To do this,

1. Type `M-x customize-variable`.

   Emacs isplays a customization buffer for `jde-db-debugger.`

2. Click the radio button next to JDEbug.
3. Click the State button and select Save for Future Sessions if you want to enable JDEbug for all projects or Set for Current Session if you want to enable JDEbug only for the current project, in which case you should save the setting in your project file.

Select any Java source buffer. The JDEBug menu should appear in the Emacs menubar.

### Specifying the Location of the JPDA Libraries

JDEbug uses class and native code libraries that implement the JPDA specification. You must tell JDEbug where these support libraries live. The way to do this depends on the platform and version of the Sun Java SDK you are using.

#### Sun Java SDK 1.3 for Windows and Solaris

To specify the location of the JPDA support libraries for Sun's Java SDK 1.3:

1. Select JDEbug->Preferences to display a customization buffer for JDEbug variables.
2. Customize the entries for the following variables (see Customizing the JDE).

   Variable | Set to...
   --- | ---
   `jde-bug-vm-includes-jpda-p` | On.
   `jde-bug-jdk-directory` | Directory that contains the Java SDK 1.3. Suppose that the SDK is installed in the directory `d:\jdk-1.3` on your system. Then you would set `jde-bug-jdk-directory` to `d:\jdk-1.3`.

#### Java SDK 1.2.2 for Windows, Linux, and Solaris

To specify the location of the JPDA support libraries for Sun's Java SDK 1.2.2:

1. Select JDEbug->Preferences to display a customization buffer for JDEbug variables.
2. Customize the entries for the following variables (see Customizing the JDE).

   Variable | Set to...
   --- | ---
   `jde-bug-vm-includes-jpda-p` | Off.
   `jde-bug-jpda-directory` | Directory that contains the JPDA package.

3. Include the directory containing the JDPA native code libraries (e.g., `jdwp.dll`) in your system's library load path. The libraries live in different places, depending on the platform:
   - On Windows, the libraries live in the JPDA backward compatibiliy package's `bin` directory. So add the `bin` directory to your system's path environment variable.

     For example, suppose the JPDA directory resides in the directory `c:/jpda` on your Windows 95 system. In this case, you would include the following line in your `autoexec.bat` file:

     `set path=c:/jpda/bin;%path%`

   - On Solaris, the libraries live in the JPDA's `lib/sparc` subdirectory. So add the `lib/sparc` subdirectory to the `LD_LIBRARY_PATH` environment variable of the Emacs process. The easiest way to do this is to include the setting in your `.bashrc` or `.cshrc` file.

     For example, suppose you install the JPDA directory at `/home/me/jpda` on your system. Then you would add the following line to your `.cshrc` file:

     `setenv LD_LIBRARY_PATH /home/me/jpda/lib/sparc:$LD_LIBRARY_PATH`

   - On Linux, the JDPA libraries live in the Java SDK 1.2.2's `lib/sparc` (Sun processor) or `lib/i386` (Intel processor) subdirectory. So for Linux, you would add lines similar to the following to your `.bashrc` file:

     `LD_LIBRARY_PATH = /opt/jdk1.2.2/lib/i386:$LD_LIBRARY_PATH`
     `export LD_LIBRARY_PATH`

     Also make sure that there are symbolic links for libjdwp.so and libdt_socket.so as follows:

     `jdk1.2.2/lib/libjdwp.so` -> `jdk1.2.2/lib/i386/libjdwp.so`
     `jdk1.2.2/lib/libdt_socket.so` -> `jdk1.2.2/lib/i386/libdt_socket.so`

### Specifying the Location of Source Files

To display the current location in the program you are debugging, JDEBug needs to be able to find the source files from which the program was compile. The JDEbug looks for the files in the source directories specified by the JDE variable `jde-db-source-directories`. Therefore, before starting a debugging session, you must ensure that this variable specifies all the source files that you may step through during the debugging session.

To set this variable:

1. Type `M-x customize-variable jde-db-source-directories`

   Emacs displays the customization buffer for the variable.

2. Edit the buffer to reflect the location of Java source files on your system.

   Note You should specify only the root directory of the top-level packages you may need to visit during a debugging session. For example, suppose the top-level packages for your current project reside in `c:/java/projects/prj1/src` and the Java SDK source lives in `c:/java/jdk1.3/src`. Then the customization buffer should appear as follows:

   `jde-db-source-directories: [Hide]`
   `[INS] [DEL] Path: c:/java/projects/prj1/src`
   `[INS] [DEL] Path: c:/java/jdk1.3/src/`
   `[INS]`
   `[State]: you have edited the value as text, but you have not set the option.`
   `List of source directory paths. [More]`
   `Parent groups: [jde-project]`

3. Save the setting in your `.emacs` or `.prj` file (see Customizing the JDE).

## Starting the Debugger

To start the debugger, select Processes->Start Debugger from the JDEbug menu. This command simply starts the debugger. To debug an application, you must either

- launch the application inside the debugger (see Launching a Process)
- attach the debugger to the application if it was started outside the debugger (see Attaching a Process)
- put the debugger in listen mode and start the application outside the debugger (see Listening for a Process)

### Setting the Debug Session Working Directory

The debugger launches all processes from the directory in which it was started. This directory is known as the debug session working directory. By default, the debug session working directory is the directory of the source buffer that was active when you started the debugger. To specify another directory as the working directory for the current debugger session, set the variable `jde-run-working-directory` to the directory's path.

Note You cannot set the working directory on a per-process basis. All processes launched during the current session start in the debug session working directory.

## Exiting the Debugger

To exit the debugger, select Exit Debugger from the JDEbug menu. The JDE terminates any processes (vm's) launched by the debugger and terminates the debugger process (vm) itself.

Note Exiting Emacs itself without first exiting the debugger orphans the debugger vm and any processes (vm's) launched by the debugger. Thus, it is important to exit JDEbug before exiting Emacs.

## Launching a Process

In this guide, a process refers to a running instance of an application. JDEBug provides two commands for launching processes.

- JDEbug->Processes->Launch Process

  This command launches an instance of the application whose main class is specified by the variable `jde-run-application-class`, or, if this variable is `nil`, the application in the current Java source buffer. The debugger suspends the debuggee process before it enters the application's main method. At this point, you should set one or more breakpoints in the application and select the Run command from the JDEbug menu. The process will then run to the first breakpoint at which point you can continue to the next breakpoint or single-step the process.

- JDE->Debug App

  This command performs the following actions:

  1. Starts the debugger, if necessary.
  2. Launches the application.
  3. Sets any breakpoints you have previously specified (see Setting Breakpoints).
  4. Runs the application.

  Note With this command, the application will simply run to completion without stopping, if you have not previously specified any valid breakpoints for the application or none of the breakpoints exist on the main execution path.

Issuing either of these commands cause JDEBug to split your Emacs frame into three windows.

.

The top window displays a Java source buffer. The source buffer displays either the source buffer where you launched the application or, if you used the Debug App command, the source buffer containing the first breakpoint hit after the application was launched.

The middle window displays the application process's local variables buffer. The buffer displays the local variables in the stack frame of the initial breakpoint hit when you launched the application. If your application does not hit a breakpoint at startup, the local variables buffer displays nothing.

The bottom window contains the debugger messages buffer for the process that was just launched. This buffer displays messages regarding the status of the process being debugged.

At this point, if the process was launched successfully and did not run to completion, you can begin debugging your application.

See Also

Working with Process Buffers

Debugging Multiple Processes

### Launching an Application in Classic Mode

Depending on the version of the JDK you are using, the debugger can launch a debuggee process in either of two modes:

- classic

  Uses just-in-time (JIT) compilation of classes to speed up execution of a program. This is the mode used in early versions of the JDK. Hence its name.

- HotSpot

  Speeds up execution by detecting and compiling heavily used fragments of code (hot spots). Unfortunately, the JPDA does not work reliably in this mode (see JDEbug and Hotspot). Therefore, you should use classic mode to launch a debuggee application.

The debugger launches applications in HotSpot mode by default. To launch an application in classic mode, type `M-x customize-variable jde-run-classic-mode-vm` and toggle the variable on.

Note If the JDK's Java Runtime Environment (JRE) is installed on your system, JPDA sometimes uses the vm installed in the JRE's bin directory to launch the debuggee application. (I'm not sure exactly how the JDPA determines which vm to use to launch a debuggee application. It seems to vary from system to system.) Unfortunately, on Windows, at least, the JDK installer installs only the HotSpot vm in the JRE bin directory. If you want to debug applications, you must manually install the classic mode vm in the JRE bin directory itself. To do this, simply copy the classic subdirectory from the jre subdirectory of the JDK to the bin subdirectory of the JRE. After you have done this, the JRE bin directory should look similar to the following:

        - c:\Program Files\
          - JavaSoft
            - bin
                classic
                hotspot
          + lib

## Connecting to External Processes

JDEbug supports two ways of connecting to an application that it does not itself launch: attach mode and listen mode. Each of these modes can be thought of as an interaction between a client and a server. In attach mode, the application vm is the server and JDEbug is the client. In listen mode, JDEbug is the server and the application vm is the client. The advantage of attach mode is that it allows you to connect (and reconnect) to an external process at any time. The advantage of listen mode is that it allows you to debug the startup of an external process.

To use either of these modes, you must start the application vm with certain command line arguments and then issue a JDEbug command to establish the connection. The following sections explain the procedurs for establishing an attach-mode and listen-mode connection, respectively.

### Attaching a Process

JDEbug allows you to attach the debugger to an existing local or remote process that was launched outside the current debugger session. This is useful for debugging servlets and processes that were launched by another application, for example, servelets.

NoteYou can use JDE->Run App to launch the third-party application. Use the JDE variables `jde-run-executable` and `jde-run-executable-args` to cause the Run App command to run a non-Java app that launches a Java subprocess to be debugged.

You can attach the debugger to an existing process via:

- a socket
- shared memory, if both processes run on the same host

The shared memory option is available only on Windows. It is much faster and thus is preferable. In either case the existing process must have been started with the appropriate debug options.

#### Attaching via a Socket

To attach via a socket:

1. Launch the debuggee process with the following vm command line arguments:
   - `-Xdebug`
   - `-Xnoagent`
   - `-Djava.compiler=NONE`
   - `-Xrunjdwp:transport=dt_socket,address=NNNN,server=y,suspend=n`

     where `NNNN` is any unused socket address on the host processor for the debuggee process.

     See `jde-run-option-vm-args` for information on how to specify vm arguments when launching an application from the JDE.

2. Execute JDEbug->Processes->Start Debugger to start the debugger (if necessary).
3. Execute JDEbug->Processes->Attach Process->Local Host or Remote Host to attach the debugger to a local or remote process, respectively.

   In the first case, the JDE prompts you to enter the socket address that you specified in step 1. In the second case, the JDE also prompts you to enter the name of the host on which the remote process is running.

#### Attaching via Shared Memory

To attach via shared memory:

1. Launch the debuggee process with the following vm command line arguments:
   - `-Xdebug`
   - `-Xnoagent`
   - `-Djava.compiler=NONE`
   - `-Xrunjdwp:transport=dt_shmem,address=NAME,server=y,suspend=n`

     where `NAME` is a string identifying the process, e.g., `webserver`.

     See `jde-run-option-vm-args` for information on how to specify vm arguments when launching an application from the JDE.

2. Execute JDEbug->Processes->Start Debugger to start the debugger (if necessary).
3. Execute JDEbug->Processes->Attach Process->Via Shared Memory to attach the debugger to the process started in step 1.

   The JDE prompts you to enter the `NAME` you specified in step 1.

Note You can attach/detach from a running process as many times as you want during a session.

### Listening for a Process

JDEbug's listen mode enables a process that is launched independently of JDEbug to attach itself to JDEbug when the independently launched process starts. Listen mode is useful for debugging the startup code of processes that JDEbug cannot launch itself. Examples of such processes are processes launched by other applications such as a web server or a hybrid C/Java application where a C main program uses an embedded vm to to run Java processes.

NoteYou can use JDE->Run App to launch the third-party application. Use the JDE variables `jde-run-executable` and `jde-run-executable-args` to cause the Run App command to run a non-Java app that launches a Java subprocess to be debugged.

When in listen mode, JDEbug acts as a debug server, listening for debug service requests from independently launched processes. You can cause JDEbug to use either a socket or a shared memory channel (Windows only) to communicate with processes requesting debug services. You must use the socket option, if you want to debug a process running on a remote machine or you are running the debugger under Unix, On Windows, you can use either option to debug processes running on the local machine. However, the shared memory option typically results in faster response to debug commands.

#### Listening on a Socket

1. Execute JDEbug->Processes->Start Debugger to start the debugger (if necessary).
2. Select JDEbug->Processes->Listen on->Socket to put JDEbug in listen mode.

   This command causes the debugger to listen on the socket specified by the JDE variable `jde-bug-server-socket`. The default value is `2112`. You can customize this variable to specify any socket address you choose or to cause JDEbug to prompt you to enter an address. Whatever address you choose, you must enter the same address as an argument of the command that launches the process to be debugged.

3. Launch the debuggee process with the command line arguments required to attach to JDEbug.

   See Listen Mode VM Arguments for more information.

When you launch a Java application with listen mode arguments, the vm halts before running the app's main method and attempts to connect with JDEbug. Once the connection is made, JDEbug is in complete control of the app. For example, the app won't run until the debugger issues a continue command. This means you can set breakpoints in the debuggee app's startup code.

#### Listening on a Shared Memory Channel

Note This option is available only if both the debugger and the debuggee process are running under Windows on the same machine.

1. Execute JDEbug->Processes->Start Debugger to start the debugger (if necessary).
2. Select JDEbug->Processes->Listen on->Shared Memory to put JDEbug in listen mode.

   This command causes the debugger to listen on the shared memory channel specified by the JDE variable `jde-bug-server-shmem-name`. The default value is `jdebug`. You can customize this variable to specify any name you choose or to cause JDEbug to prompt you to enter a name. Whatever name you choose, you must enter the same name as an argument of the command that launches the process to be debugged.

3. Launch the debuggee process with the command line arguments required to attach to JDEbug.

   See Listen Mode VM Arguments for more information.

When you launch a Java application with listen mode arguments, the vm halts before running the app's main method and attempts to connect with JDEbug. Once the connection is made, JDEbug is in complete control of the app. For example, the app won't run until the debugger issues a continue command. This means you can set breakpoints in the debuggee app's startup code.

#### Listen Mode VM Arguments

Use the following vm arguments when launching a process to be debugged in listen mode.

- `-Xdebug`
- `-Xnoagent`
- `-Djava.compiler=NONE`
- `-Xrunjdwp:transport=dt_socket,address=NNNN,server=n,suspend=y`

  where `TRANSPORT` is either `dt_socket` or `dt_shmem` and `NNNN` is any symbolic name you want to use for the shared memory channel or any unused socket address on the host processor for the debuggee process.

- `-Xbootclasspath:JDKHOME/jre/lib/rt.jar;JDKHOME/lib/tools.jar`

  where JDKHOME is the home directory for the JDK.

  Note This option is necessary only if you are using the JDK 1.3 vm to launch the debuggee process.

Here is an example of a typical command line to launch a debuggee client, using JDK1.3:

`java -classpath d:/myapp/myapp.jar -Xdebug -Xnoagent`
`-Xrunjdwp:transport=dt_socket,address=jdebug,server=n,suspend=y`
`-Xbootclasspath:e:/jdk1.3/jre/lib/rt.jar;e:/jdk1.3/lib/tools.jar`
`com.myorg.myapp.Main`

Use the JDE variable `jde-run-option-vm-args` to specify vm arguments when launching an application from the JDE.

## Debugging Multiple Processes

JDEbug allows you to launch and debug multiple debuggee processes during the same debugger session. JDEbug assigns a numeric identification number to each process that it launches or attaches in either attach or listen mode. All JDEbug commands, except those that launch or attach processes, implicitly address a process called the target process. When you launch or attach a process, that process becomes the target process until you specify a different process as the target process.

To specify a different process as the target process, select JDEbug->Processes->Set Target Process, then enter the ID of the target process at the prompt.

## Working with Process Buffers

JDEbug creates a set of buffers for each process that you debug during a debugger session.

Buffer | Description
--- | ---
Process | Displays status messages from the debugger.
Local Variables | Displays the values of local variables and the fields of the object on which the current method was invoked (the implicit this object).
Command Line Interface (CLI) | Allows you to interact with a process that has a command line interface (CLI). The JDE sends lines that you type in this buffer to the process's standard input. The process's standard output also appears in this buffer.
Threads | Displays the current status of all threads created by the debuggee process. The JDEbug->Display->Threads command creates this buffer.
*JDEbug* | Displays the low-level commands sent by Emacs to the Java backend of JDEbug, the backend's responses to those commands, and events detected by the backend. You should always include a copy of this buffer in bug reports as it represents a complete record of your debugs session.

### Displaying the Buffers

JDEbug displays the Process and Locals buffer in windows in the current frame when you launch or attach a process.

- To replace one of these buffers with another, select the buffer from the JDEbug->Show Buffers menu.
- To display a buffer in a separate frame, select the buffer and then select Files->Make New Frame.
- To display the startup window configuration for a process, select JDEbug->Processes->Set Target Process and enter the process's ID number.

### Deleting Buffers

JDEbug does not delete the buffers belonging to a process when it dies. To delete all the buffers created for dead processes, select JDEbug->Processes->Remove Dead Processes. This command removes all traces of the dead processes from the Emacs environment.