Section 5.9. The Java Debugger


5.9. The Java Debugger

How can you stand using the SDK? It doesn't even have a debugger!

Wrong. It has a debugger. It just has an extremely basic command-line debugger. Example 5.16 shows the output of its help.

Again, we are not going to document everything here. That's what the online Sun Microsystems Java SDK documentation is for. Instead, we will use the debugger to step through the execution of our simple application and show you some of the debugger's basic operations.

There are two ways to invoke jdb. One is to attach it to an already running JVM that has been started with remote debugging enabled. See the Java SDK documentation for details on that method. Here we'll show you the simpler case of invoking the program locally by running the application directly under the debugger.

The basic invocation is:

$ jdb

You may optionally name the class whose main() is to be executed under the debugger, but we usually use the run from inside the debugger itself to do this. Remember that if you want to be able to view local variables in the debugger, you must have compiled your class or classes with the -g option of javac.

In the rest of this section, we will examine an actual debug session. We will run our single-class application, FetchURL, and use it to retrieve the index.html file from the Web server on the laptop on which this chapter is being written. To refresh your memory, remember that the source code for FetchURL is at Example 3.30. Example 5.17 is what that file looks like.

Example 5.16. The Java debugger help command output
 $ jdb GetUser Initializing jdb ... > help ** command list ** run [class [args]]        -- start execution of application's main class threads [threadgroup]     -- list threads thread <thread id>        -- set default thread suspend [thread id(s)]    -- suspend threads (default: all) resume [thread id(s)]     -- resume threads (default: all) where [thread id] | all   -- dump a thread's stack wherei [thread id] | all  -- dump a thread's stack, with pc info up [n frames]             -- move up a thread's stack down [n frames]           -- move down a thread's stack kill <thread> <expr>      -- kill a thread with the given exception object interrupt <thread>        -- interrupt a thread print <expr>              -- print value of expression dump <expr>               -- print all object information eval <expr>               -- evaluate expression (same as print) set <lvalue> = <expr>     -- assign new value to field/variable/array element locals                    -- print all local variables in current stack frame classes                   -- list currently known classes class <class id>          -- show details of named class methods <class id>        -- list a class's methods fields <class id>         -- list a class's fields threadgroups              -- list threadgroups threadgroup <name>        -- set current threadgroup stop in <class id>.<method>[(argument_type,...)]                           -- set a breakpoint in a method stop at <class id>:<line> -- set a breakpoint at a line clear <class id>.<method>[(argument_type,...)]                           -- clear a breakpoint in a method clear <class id>:<line>   -- clear a breakpoint at a line clear                     -- list breakpoints catch [uncaught|caught|all] <exception-class id>                           -- break when specified exception occurs ignore [uncaught|caught|all] <exception-class id>                           -- cancel 'catch' for the specified exception watch [access|all] <class id>.<field name>                           -- watch access/modifications to a field unwatch [access|all] <class id>.<field name>                           -- discontinue watching access/modifications to a field trace methods [thread]    -- trace method entry and exit untrace methods [thread]  -- stop tracing method entry and exit step                      -- execute current line step up                   -- execute until the current method returns to its caller stepi                     -- execute current instruction next                      -- step one line (step OVER calls) cont                      -- continue execution from breakpoint list [line number|method] -- print source code use (or sourcepath) [source file path]                           -- display or change the source path exclude [class id ... | "none"]                           -- do not report step or method events for specified classes classpath                 -- print classpath info from target VM monitor <command>         -- execute command each time the program stops monitor                   -- list monitors unmonitor <monitor#>      -- delete a monitor read <filename>           -- read and execute a command file lock <expr>               -- print lock info for an object threadlocks [thread id]   -- print lock info for a thread pop                       -- pop the stack through and including the current frame reenter                   -- same as pop, but current frame is reentered redefine <class id> <class filename>                           -- redefine the code for a class disablegc <expr>          -- prevent garbage collection of an object enablegc <expr>           -- permit garbage collection of an object !!                        -- repeat last command <n> <command>             -- repeat command n times help (or ?)               -- list commands version                   -- print version information exit (or quit)            -- exit debugger <class id> or <exception-class id>: full class name with package qualifiers or a pattern with a leading or trailing wildcard ('*') NOTE: any wildcard pattern will be replaced by at most one full class name matching the pattern. <thread id>: thread number as reported in the 'threads' command <expr>: a Java(tm) Programming Language expression. Most common syntax is supported. Startup commands can be placed in either "jdb.ini" or ".jdbrc" in user.home or user.dir > 

Example 5.17. index.html used in jdb session
 <HTML>   <HEAD>     <TITLE>RedHat Linux Laptop</TITLE>   </HEAD>   <BODY>     <H1>RedHat Linux Laptop</H1>     <P>You have contacted Michael Schwarz's RedHat Linux Laptop.     You would probably rather     <A HREF="http://www.multitool.net/">see his permanent Web     page</A> since this server goes up and down all the time, what     with it being on a laptop.</P>   </BODY> </HTML> 

Example 5.18 is an actual transcript of a real jdb session. It is annotated with explanatory comments. Our goal here is to get you going. The best way to learn jdb, or indeed any of these tools, is to use them.

Obviously, this little session has merely scratched the surface of the Java debugger. You can debug multithreaded applications with commands that can suspend and resume individual threads, list the running threads, switch your "executable view" between threads, and so forth. You can trace method calls. You can monitor variables. You can execute expressions (including assignment expressions, allowing you to force variables to certain values). You can browse classes. You can dump all local variables with a single command. The debugger is quite capable, if a bit limited in user interface.[23] Learn it. Play with it. Step through your favorite Java program with it.

[23] As you know, we do not automatically like IDEs and GUI development tools (see Section 5.2). A debugger is an exception to that rule. When debugging, a well designed UI with a code pane, a stack pane, a data viewer, a class browser, a thread selection pane, and so on is enormously helpful. You need to be able to see all these elements nearly simultaneously; you need to see the whole system as it runs. The command-line debugger makes everything you need available, but with a traditional "glass-teletype" UI that is quite awkward. By all means, learn the CLI debugger, but then find a good Java debugger with a windowed UI of some kind. It is hard to say which compiler UI is the best, but I think we can safely say the command-line debugger UI is the worst! You should know it as a last resort, but use it as a last resort!

Example 5.18. An actual jdb session, with commentary
 $ jdb Initializing jdb ... > stop in FetchURL.main (1) Deferring breakpoint FetchURL.main. It will be set after the class is loaded. > run FetchURL http://localhost run FetchURL http://localhost Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint FetchURL.main Breakpoint hit: "thread=main", FetchURL.main(), line=48 bci=0 48          for (i = 0; i < args.length; i++) main[1] list 44       { 45          int i; 46          FetchURL f; 47 48 => (2)    for (i = 0; i < args.length; i++) 49          { 50             System.out.println(args[i] + ":"); 51             System.out.println(new FetchURL(args[i])); 52          } 53       } main[1] step > Step completed: "thread=main", FetchURL.main(), line=50 bci=5 50             System.out.println(args[i] + ":"); main[1] step > http://localhost: Step completed: "thread=main", FetchURL.main(), line=51 bci=32 51             System.out.println(new FetchURL(args[i])); main[1] step > Step completed: "thread=main", FetchURL.<init>(), line=8 bci=0 8       { main[1] list 4    public class FetchURL { 5       private URL requestedURL; 6 7       public FetchURL(String urlName) 8 =>    { 9          try { 10             requestedURL = new URL(urlName); 11          } catch (Exception e) { 12             e.printStackTrace(); 13          } main[1] step > Step completed: "thread=main", FetchURL.<init>(), line=10 bci=4 10             requestedURL = new URL(urlName); main[1] step (3) > Step completed: "thread=main", FetchURL.<init>(), line=11 bci=16 11          } catch (Exception e) { main[1] step > Step completed: "thread=main", FetchURL.<init>(), line=14 bci=27 14       } main[1] step > Step completed: "thread=main", FetchURL.main(), line=51 bci=45 51             System.out.println(new FetchURL(args[i])); main[1] step > Step completed: "thread=main", FetchURL.toString(), line=19 bci=2 19          String rc = ""; main[1] list 15 16 17       public String toString() 18       { 19 =>       String rc = ""; 20          String line; 21          BufferedReader rdr; 22 23          try { 24             rdr = new BufferedReader( main[1] step > Step completed: "thread=main", FetchURL.toString(), line=24 bci=3 24             rdr = new BufferedReader( main[1] step > Step completed: "thread=main", FetchURL.toString(), line=30 bci=28 30             while ((line = rdr.readLine()) != null) main[1] step > Step completed: "thread=main", FetchURL.toString(), line=32 bci=31 32                rc = rc + line + "\n"; main[1] list 28             ); 29 30             while ((line = rdr.readLine()) != null) 31             { 32 =>             rc = rc + line + "\n"; 33             } 34          } catch (Exception e) { 35             e.printStackTrace(); 36             rc = null; 37          } main[1] step > Step completed: "thread=main", FetchURL.toString(), line=30 bci=55 30             while ((line = rdr.readLine()) != null) main[1] step > Step completed: "thread=main", FetchURL.toString(), line=32 bci=31 32                rc = rc + line + "\n"; main[1] step > Step completed: "thread=main", FetchURL.toString(), line=30 bci=55 30             while ((line = rdr.readLine()) != null) main[1] step > Step completed: "thread=main", FetchURL.toString(), line=32 bci=31 32                rc = rc + line + "\n"; main[1] dump this (4)  this = {     requestedURL: instance of java.net.URL(id=378) } main[1] dump rc   (5)   rc = "<HTML>           <HEAD> " main[1] list 36 32                rc = rc + line + "\n"; 33             } 34          } catch (Exception e) { 35             e.printStackTrace(); 36 =>          rc = null; 37          } 38 39          return rc; 40       } 41 main[1] stop at FetchURL:39     (6) Set breakpoint FetchURL:39 main[1] cont > Breakpoint hit: "thread=main", FetchURL.toString(), line=39 bci=79 39          return rc; main[1] dump rc   rc = "<HTML>           <HEAD>             <TITLE>RedHat Linux Laptop</TITLE>           </HEAD>           <BODY>             <H1>RedHat Linux Laptop</H1>             <P>You have contacted Michael Schwarz's RedHat Linux Laptop.             You would probably rather             <A HREF="http://www.multitool.net/">see his permanent Web             page</A> since this server goes up and down all the time, what             with it being on a laptop.</P>           </BODY>         </HTML> " main[1] step > <HTML>        <HEAD>          <TITLE>RedHat Linux Laptop</TITLE>        </HEAD>        <BODY>          <H1>RedHat Linux Laptop</H1>          <P>You have contacted Michael Schwarz's RedHat Linux Laptop.          You would probably rather          <A HREF="http://www.multitool.net/">see his permanent Web          page</A> since this server goes up and down all the time, what          with it being on a laptop.</P>       </BODY>     </HTML> Step completed: "thread=main", FetchURL.main(), line=48 bci=48 48          for (i = 0; i < args.length; i++) main[1] step > Step completed: "thread=main", FetchURL.main(), line=53 bci=57 53       } main[1] step > The application exited $ 

1.

Here we tell the debugger where to break execution to let us run debugger commands. We do so at the start of the FetchURL class' main() method. If we did not set a breakpoint, the run would have run the program to termination, making it no different from running it with the java command (except perhaps a bit slower).

2.

The list command shows the source line that is about to be executed, along with some more lines to either side. It is a handy way to get a little context. The standard "next line" prompt isn't enough for most of us to get context (unless, of course, we are looking at a line-numbered printout of the source or an editor window at the same time, which we often do).

3.

The step steps execution one "line" (what a line is can be a bit fuzzy when there's a lot of vertical whitespace in the source, or when multiple method calls occur on one line). Note the information in the status message. The name of the thread is given (our sample is single-threaded, so it is always "main"), as is the line number in the source file and the bci. Note that there is a very similar command, next, that advances to the next line in the same stack frame. In other words, it won't step into method calls, it steps over them.

4, 5.

Here we see two uses of the dump command. First, we apply it to this (which is an implicit argument to any nonstatic method call) to dump the currently executing object. The second instance dumps the rc local variable, which is an accumulating string containing the requested Web page. At the moment, it contains only the first few lines.

6.

Here we set a breakpoint on a specific source line number. We then use the cont command to resume "full speed" code execution.




    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net