.\" @(#)dbx.ms 6.4 (Berkeley) 05/10/86 .\" .\" modified by mark seiden in cosmetic ways. .\" examples VAXinated by Kevin Dunlap .\" dtbl | ditroff -ms .OH 'Debugging with dbx''PS1:11-%' .EH 'PS1:11-%''Debugging with dbx' .de BE .DS .ft CW .ps -1 .. .de EE .ft P .ps +1 .DE .. .de UL \f(CW\s-1\\$1\fP\s0 .. .TL Debugging with dbx .AU Bill Tuthill .AI Sun Microsystems, Inc. 2550 Garcia Avenue .AU Kevin J. Dunlap .AI Computer Systems Research Group University of California Berkeley, CA 94720 .SH Introduction .PP This short paper discusses .I dbx , a symbolic debugger that is vastly superior to .I adb . It may be as good as the debuggers you remember from those non- .UX systems you worked on before. The advantage of symbolic debuggers is that they allow you to work with the same names (symbols) as in your source code. .PP Like .I adb , .I dbx is interactive and line-oriented, but .I dbx is a source-level rather than an assembly-level debugger. It allows you to determine where a program crashed, to view the values of variables and expressions, to set breakpoints in the code, and to run and trace a program. Source code may be in C, Fortran, or Pascal. .PP Mark Linton wrote .I dbx as his master's thesis at UC Berkeley. Along with Eric Schmidt's Berknet, .I dbx is among the most successful master's theses done on UNIX. Since .I dbx required changes to the symbol tables generated by the various compilers, you need to compile programs for debugging with the .I \-g flag. For example, C programs should be compiled as follows: .DS % cc \-g \fIprogram\fP.c \-o \fIprogram\fP .DE Programs compiled with the .I \-g option have good symbol tables, while programs compiled without .I \-g have old-style symbol tables intended for .I adb . Stripped programs have no symbol tables at all. Invoke the debugger as follows, where .I program is the pathname of the executable file that dumped core: .DS % dbx \fIprogram\fP .DE The core image should be in the working directory; if it isn't, specify its pathname in the argument after the program name. Among the great advances of .I dbx is that it has a help facility; type the .I help request to see a list of possible requests. You can obtain help on any .I dbx request by giving its name as an argument to .I help . .bp .SH Examining Core Dumps .PP Much of the time, programmers use .I dbx to find out why a program dumped core. As an example, consider the following program .I dumpcore.c , which dereferences a NULL pointer. This is a legal operation on VAX/UNIX, but not on VAX/VMS or on MC68000-based UNIX systems, on one of which this example was run: .BE #include .sp.5 #define LIMIT 5 .sp.5 main() /* print messages and die */ { int i; .sp.5 for (i = 1; i <= 10 ; i++) { printf("Goodbye world! (%d)\en", i); dumpcore(i); } exit(0); } .sp.5 int *ip; .sp.5 dumpcore(lim) /* dereference NULL pointer */ int lim; { if (lim >= LIMIT) *ip = lim; } .EE The program core dumps because of a segmentation violation or memory fault \(em on most machines it is illegal to assign to address zero. Once the program has produced a core dump, here's how you can find out why the program died: .DS %\c .UL " dbx dumpcore" dbx version 3.17 of 4/24/86 15:04 (monet.Berkeley.EDU). Type 'help' for help. reading symbolic information ... [using memory image in core] (dbx)\c .UL " where" dumpcore.dumpcore(lim = 5), line 22 in "dumpcore.c" main(0x1, 0x7fffe904, 0x7fffe90c), line 11 in "dumpcore.c" .DE The .I where request yields a stack trace. As you can see, the .I dumpcore() routine was called from line 11 of the program, with the argument .I lim equal to 5. You can look at the .I dumpcore() procedure by invoking the .I list request as follows: .DS (dbx)\c .UL " list dumpcore" 18 dumpcore(lim) /* dereference NULL pointer */ 19 int lim; 20 { 21 if (lim >= LIMIT) 22 *ip = lim; 23 } .DE We immediately suspect that the program's failure had something to do with .I *ip , so we use the .I print request to retrieve the value of the pointer and what it points to: .DS (dbx)\c .UL " print *ip" reference through nil pointer (dbx)\c .UL " print ip" (nil) .DE This tells us the program has dereferenced a null pointer. It is possible to run the program again from inside the debugger. The first line tells you name of the running program, and successive lines give output from the program: .DS (dbx)\c .UL " run" Goodbye world! (1) Goodbye world! (2) Goodbye world! (3) Goodbye world! (4) Goodbye world! (5) .sp.5 Bus error in dumpcore.dumpcore at line 22 22 *ip = lim; (dbx)\c .UL " quit" .DE In this example the program dies with a Bus error at line 22. This method of running the program does not produce a core dump, but the .I where request will still behave properly, because the debugger is in the same state as if it had just read the core file. .SH Setting Breakpoints .PP With .I dbx you can set breakpoints before each line of a program, not just at function and procedure boundaries, as with .I adb . The .I stop request sets a breakpoint. After setting a breakpoint, use the .I run request to execute the program. The .I cont request continues execution from the current stopping point until the program finishes or another breakpoint is encountered. The .I step request executes one source statement, following any function calls. The .I next request executes one source statement, but does not stop inside any function calls. The .I status request lists active breakpoints, while the .I delete request removes them if required. .PP The .I stop request can take a conditional expression to avoid needless single-stepping. We will use a conditional in our example to make things simpler. Of course you can use .I print and .I list requests at any time during statement stepping if you want to print the value of variables or list lines of source code. This sample session shows a mixture of requests as we verify that the program fails when it tries to assign to .I *ip : .DS (dbx)\c .UL " stop at 10 if (i == 5)" [1] if i = 5 { stop } at 10 (dbx)\c .UL " run" Goodbye world! (1) Goodbye world! (2) Goodbye world! (3) Goodbye world! (4) [1] stopped in main at line 10 10 printf("Goodbye world! (%d)\en", i); (dbx)\c .UL " next" Goodbye world! (5) stopped in main at line 11 11 dumpcore(i); (dbx)\c .UL " step" stopped in dumpcore at line 21 21 if (lim >= LIMIT) (dbx)\c .UL " step" stopped in dumpcore at line 22 22 *ip = lim; (dbx)\c .UL " step" Bus error in dumpcore.dumpcore at line 22 22 *ip = lim; .DE Running the program with breakpoints assures us that our intuition was correct. We shouldn't be assigning anything to a null pointer \(em .I ip should have been initialized to point at an object of the proper type. To exit from the debugger, use the .I quit request. .PP It is possible to set variables from inside .I dbx . The previous breakpoint session, for example, could have gone like this: .DS %\c .UL " dbx dumpcore" dbx version 3.17 of 4/24/86 15:04 (monet.Berkeley.EDU). Type 'help' for help. reading symbolic information ... [using memory image in core] (dbx)\c .UL " stop at 10" [1] stop at 10 (dbx)\c .UL " run" Running: dumpcore stopped in main at line 10 10 printf("Goodbye world! (%d)\en", i); (dbx)\c .UL " assign i = 5" (dbx)\c .UL " next" Goodbye world! (5) stopped in main at line 11 11 dumpcore(i); (dbx)\c .UL " next" Bus error in dumpcore.dumpcore at line 22 22 *ip = lim; .DE It is often useful to assign new values to variables to draw conclusions about alternative conditions. We can't fix the bug in this program, however, because there is no declared variable to which .I ip should point. .SH Conclusion .PP Expressions in .I dbx are similar to those in C, except that there is a distinction between .I / (floating-point division) and .I div (integer division), as in Pascal. The table on the following page shows .I dbx requests organized by function: .PP Like .I adb , .I dbx can disassemble object code. It can also examine object files and print output in various formats; but .I dbx requires the proper symbol tables, so .I adb is more useful to examine arbitrary binary files. The most important thing .I adb can do that .I dbx cannot is to patch binary files \(em .I dbx has no write option. Despite these shortcomings, .I dbx is much easier to use than .I adb , so it contributes much more to individual programmer productivity. .SH Acknowledgements .PP Material presented in this document was first presented in ``C Advisor'', \fIUnix Review 4\fP, 1, pp 78\-85. The Regents of the University California expresses their gratitude to Unix Review for allowing them to reprint this document. .PP This document is a good starting point for a more thorough tutorial. Those with the ambition to expand on this document are encouraged to contact the Computer Systems Research Group at ``4bsd-ideas@Berkeley.Edu.'' .KF .TS center box; cf s. .sp.2 \s+2Groups of \&\fIdbx\fP Requests\s-2 .sp.2 _ .T& l lfI lp-1fCW l. execution and tracing _ run execute object file cont continue execution from where it stopped trace display tracing information at specified place stop stop execution at specified place status display active \&\fItrace\fP and \&\fIstop\fP requests delete delete specific \&\fItrace\fP or \&\fIstop\fP requests catch start trapping specified signals ignore stop trapping specified signals step execute the next source line, stepping into functions next execute the next source line, even if it's a function .T& l lfI lp-1fCW l. _ displaying data _ print print the value of an expression whatis print the declaration of a given identifier or type which print outer block associated with identifier whereis print all symbols matching identifier assign set the value of a variable .T& l lfI lp-1fCW l. _ function and procedure handling _ where display active procedures and functions on stack down move down the stack towards stopping point up move up the stack towards \&\fImain\fP call call the named function or procedure dump display names and values of all local variables .T& l lfI lp-1fCW l. _ accessing source files and directories _ edit invoke an editor on current source file file change current source file func change the current function or procedure list display lines of source code use set directory list to search for source files /.../ search down in file to match regular expression ?...? search up in file to match regular expression .T& l lfI lp-1fCW l. _ miscellaneous commands _ sh pass command line to the shell alias change \&\fIdbx\fP command name help explain commands source read commands from external file quit exit the debugger .TE .KE .bp