|
|
1.1 ! root 1: .\" @(#)dbx.ms 6.4 (Berkeley) 5/10/86 ! 2: .\" ! 3: .\" modified by mark seiden in cosmetic ways. ! 4: .\" examples VAXinated by Kevin Dunlap ! 5: .\" dtbl | ditroff -ms ! 6: .OH 'Debugging with dbx''PS1:11-%' ! 7: .EH 'PS1:11-%''Debugging with dbx' ! 8: .de BE ! 9: .DS ! 10: .ft CW ! 11: .ps -1 ! 12: .. ! 13: .de EE ! 14: .ft P ! 15: .ps +1 ! 16: .DE ! 17: .. ! 18: .de UL ! 19: \f(CW\s-1\\$1\fP\s0 ! 20: .. ! 21: .TL ! 22: Debugging with dbx ! 23: .AU ! 24: Bill Tuthill ! 25: .AI ! 26: Sun Microsystems, Inc. ! 27: 2550 Garcia Avenue ! 28: .AU ! 29: Kevin J. Dunlap ! 30: .AI ! 31: Computer Systems Research Group ! 32: University of California ! 33: Berkeley, CA 94720 ! 34: .SH ! 35: Introduction ! 36: .PP ! 37: This short paper discusses ! 38: .I dbx , ! 39: a symbolic debugger that is vastly superior to ! 40: .I adb . ! 41: It may be as good as the debuggers you remember from those ! 42: non- ! 43: .UX ! 44: systems you worked on before. ! 45: The advantage of symbolic debuggers is that they allow you ! 46: to work with the same names (symbols) as in your source code. ! 47: .PP ! 48: Like ! 49: .I adb , ! 50: .I dbx ! 51: is interactive and line-oriented, but ! 52: .I dbx ! 53: is a source-level rather than an assembly-level debugger. ! 54: It allows you to determine where a program crashed, ! 55: to view the values of variables and expressions, ! 56: to set breakpoints in the code, and to run and trace a program. ! 57: Source code may be in C, Fortran, or Pascal. ! 58: .PP ! 59: Mark Linton wrote ! 60: .I dbx ! 61: as his master's thesis at UC Berkeley. ! 62: Along with Eric Schmidt's Berknet, ! 63: .I dbx ! 64: is among the most successful master's theses done on UNIX. Since ! 65: .I dbx ! 66: required changes to the symbol tables ! 67: generated by the various compilers, ! 68: you need to compile programs for debugging with the ! 69: .I \-g ! 70: flag. For example, ! 71: C programs should be compiled as follows: ! 72: .DS ! 73: % cc \-g \fIprogram\fP.c \-o \fIprogram\fP ! 74: .DE ! 75: Programs compiled with the ! 76: .I \-g ! 77: option have good symbol tables, ! 78: while programs compiled without ! 79: .I \-g ! 80: have old-style symbol tables intended for ! 81: .I adb . ! 82: Stripped programs have no symbol tables at all. ! 83: Invoke the debugger as follows, where ! 84: .I program ! 85: is the pathname of the executable file that dumped core: ! 86: .DS ! 87: % dbx \fIprogram\fP ! 88: .DE ! 89: The core image should be in the working directory; ! 90: if it isn't, specify its pathname in the argument after the program name. ! 91: Among the great advances of ! 92: .I dbx ! 93: is that it has a help facility; type the ! 94: .I help ! 95: request to see a list of possible requests. ! 96: You can obtain help on any ! 97: .I dbx ! 98: request by giving its name as an argument to ! 99: .I help . ! 100: .bp ! 101: .SH ! 102: Examining Core Dumps ! 103: .PP ! 104: Much of the time, programmers use ! 105: .I dbx ! 106: to find out why a program dumped core. ! 107: As an example, consider the following program ! 108: .I dumpcore.c , ! 109: which dereferences a NULL pointer. ! 110: This is a legal operation on VAX/UNIX, ! 111: but not on VAX/VMS or on MC68000-based UNIX systems, on one of ! 112: which this example was run: ! 113: .BE ! 114: #include <stdio.h> ! 115: .sp.5 ! 116: #define LIMIT 5 ! 117: .sp.5 ! 118: main() /* print messages and die */ ! 119: { ! 120: int i; ! 121: .sp.5 ! 122: for (i = 1; i <= 10 ; i++) { ! 123: printf("Goodbye world! (%d)\en", i); ! 124: dumpcore(i); ! 125: } ! 126: exit(0); ! 127: } ! 128: .sp.5 ! 129: int *ip; ! 130: .sp.5 ! 131: dumpcore(lim) /* dereference NULL pointer */ ! 132: int lim; ! 133: { ! 134: if (lim >= LIMIT) ! 135: *ip = lim; ! 136: } ! 137: .EE ! 138: The program core dumps because of a ! 139: segmentation violation or memory fault \(em ! 140: on most machines it is illegal to assign to address zero. ! 141: Once the program has produced a core dump, ! 142: here's how you can find out why the program died: ! 143: .DS ! 144: %\c ! 145: .UL " dbx dumpcore" ! 146: dbx version 3.17 of 4/24/86 15:04 (monet.Berkeley.EDU). ! 147: Type 'help' for help. ! 148: reading symbolic information ... ! 149: [using memory image in core] ! 150: (dbx)\c ! 151: .UL " where" ! 152: dumpcore.dumpcore(lim = 5), line 22 in "dumpcore.c" ! 153: main(0x1, 0x7fffe904, 0x7fffe90c), line 11 in "dumpcore.c" ! 154: .DE ! 155: The ! 156: .I where ! 157: request yields a stack trace. ! 158: As you can see, the ! 159: .I dumpcore() ! 160: routine was called from line 11 of the program, with the argument ! 161: .I lim ! 162: equal to 5. ! 163: You can look at the ! 164: .I dumpcore() ! 165: procedure by invoking the ! 166: .I list ! 167: request as follows: ! 168: .DS ! 169: (dbx)\c ! 170: .UL " list dumpcore" ! 171: 18 dumpcore(lim) /* dereference NULL pointer */ ! 172: 19 int lim; ! 173: 20 { ! 174: 21 if (lim >= LIMIT) ! 175: 22 *ip = lim; ! 176: 23 } ! 177: .DE ! 178: We immediately suspect that the program's failure had something to do with ! 179: .I *ip , ! 180: so we use the ! 181: .I print ! 182: request to retrieve the value of the pointer and what it points to: ! 183: .DS ! 184: (dbx)\c ! 185: .UL " print *ip" ! 186: reference through nil pointer ! 187: (dbx)\c ! 188: .UL " print ip" ! 189: (nil) ! 190: .DE ! 191: This tells us the program has dereferenced a null pointer. ! 192: It is possible to run the program again from inside the debugger. ! 193: The first line tells you name of the running program, ! 194: and successive lines give output from the program: ! 195: .DS ! 196: (dbx)\c ! 197: .UL " run" ! 198: Goodbye world! (1) ! 199: Goodbye world! (2) ! 200: Goodbye world! (3) ! 201: Goodbye world! (4) ! 202: Goodbye world! (5) ! 203: .sp.5 ! 204: Bus error in dumpcore.dumpcore at line 22 ! 205: 22 *ip = lim; ! 206: (dbx)\c ! 207: .UL " quit" ! 208: .DE ! 209: In this example the program dies with a Bus error at line 22. ! 210: This method of running the program ! 211: does not produce a core dump, but the ! 212: .I where ! 213: request will still behave properly, ! 214: because the debugger is in the same state ! 215: as if it had just read the core file. ! 216: .SH ! 217: Setting Breakpoints ! 218: .PP ! 219: With ! 220: .I dbx ! 221: you can set breakpoints before each line of a program, ! 222: not just at function and procedure boundaries, as with ! 223: .I adb . ! 224: The ! 225: .I stop ! 226: request sets a breakpoint. ! 227: After setting a breakpoint, use the ! 228: .I run ! 229: request to execute the program. The ! 230: .I cont ! 231: request continues execution from the current stopping point ! 232: until the program finishes or another breakpoint is encountered. The ! 233: .I step ! 234: request executes one source statement, ! 235: following any function calls. The ! 236: .I next ! 237: request executes one source statement, ! 238: but does not stop inside any function calls. The ! 239: .I status ! 240: request lists active breakpoints, while the ! 241: .I delete ! 242: request removes them if required. ! 243: .PP ! 244: The ! 245: .I stop ! 246: request can take a conditional expression ! 247: to avoid needless single-stepping. ! 248: We will use a conditional in our example to make things simpler. ! 249: Of course you can use ! 250: .I print ! 251: and ! 252: .I list ! 253: requests at any time during statement stepping ! 254: if you want to print the value of variables ! 255: or list lines of source code. ! 256: This sample session shows a mixture of requests ! 257: as we verify that the program fails when it tries to assign to ! 258: .I *ip : ! 259: .DS ! 260: (dbx)\c ! 261: .UL " stop at 10 if (i == 5)" ! 262: [1] if i = 5 { stop } at 10 ! 263: (dbx)\c ! 264: .UL " run" ! 265: Goodbye world! (1) ! 266: Goodbye world! (2) ! 267: Goodbye world! (3) ! 268: Goodbye world! (4) ! 269: [1] stopped in main at line 10 ! 270: 10 printf("Goodbye world! (%d)\en", i); ! 271: (dbx)\c ! 272: .UL " next" ! 273: Goodbye world! (5) ! 274: stopped in main at line 11 ! 275: 11 dumpcore(i); ! 276: (dbx)\c ! 277: .UL " step" ! 278: stopped in dumpcore at line 21 ! 279: 21 if (lim >= LIMIT) ! 280: (dbx)\c ! 281: .UL " step" ! 282: stopped in dumpcore at line 22 ! 283: 22 *ip = lim; ! 284: (dbx)\c ! 285: .UL " step" ! 286: Bus error in dumpcore.dumpcore at line 22 ! 287: 22 *ip = lim; ! 288: .DE ! 289: Running the program with breakpoints assures us ! 290: that our intuition was correct. ! 291: We shouldn't be assigning anything to a null pointer \(em ! 292: .I ip ! 293: should have been initialized to point at an object of the proper type. ! 294: To exit from the debugger, use the ! 295: .I quit ! 296: request. ! 297: .PP ! 298: It is possible to set variables from inside ! 299: .I dbx . ! 300: The previous breakpoint session, for example, ! 301: could have gone like this: ! 302: .DS ! 303: %\c ! 304: .UL " dbx dumpcore" ! 305: dbx version 3.17 of 4/24/86 15:04 (monet.Berkeley.EDU). ! 306: Type 'help' for help. ! 307: reading symbolic information ... ! 308: [using memory image in core] ! 309: (dbx)\c ! 310: .UL " stop at 10" ! 311: [1] stop at 10 ! 312: (dbx)\c ! 313: .UL " run" ! 314: Running: dumpcore ! 315: stopped in main at line 10 ! 316: 10 printf("Goodbye world! (%d)\en", i); ! 317: (dbx)\c ! 318: .UL " assign i = 5" ! 319: (dbx)\c ! 320: .UL " next" ! 321: Goodbye world! (5) ! 322: stopped in main at line 11 ! 323: 11 dumpcore(i); ! 324: (dbx)\c ! 325: .UL " next" ! 326: Bus error in dumpcore.dumpcore at line 22 ! 327: 22 *ip = lim; ! 328: .DE ! 329: It is often useful to assign new values to variables ! 330: to draw conclusions about alternative conditions. ! 331: We can't fix the bug in this program, however, ! 332: because there is no declared variable to which ! 333: .I ip ! 334: should point. ! 335: .SH ! 336: Conclusion ! 337: .PP ! 338: Expressions in ! 339: .I dbx ! 340: are similar to those in C, ! 341: except that there is a distinction between ! 342: .I / ! 343: (floating-point division) and ! 344: .I div ! 345: (integer division), as in Pascal. ! 346: The table on the following page shows ! 347: .I dbx ! 348: requests organized by function: ! 349: .PP ! 350: Like ! 351: .I adb , ! 352: .I dbx ! 353: can disassemble object code. ! 354: It can also examine object files ! 355: and print output in various formats; but ! 356: .I dbx ! 357: requires the proper symbol tables, so ! 358: .I adb ! 359: is more useful to examine arbitrary binary files. ! 360: The most important thing ! 361: .I adb ! 362: can do that ! 363: .I dbx ! 364: cannot is to patch binary files \(em ! 365: .I dbx ! 366: has no write option. ! 367: Despite these shortcomings, ! 368: .I dbx ! 369: is much easier to use than ! 370: .I adb , ! 371: so it contributes much more to individual programmer productivity. ! 372: .SH ! 373: Acknowledgements ! 374: .PP ! 375: Material presented in this document was first presented in ! 376: ``C Advisor'', \fIUnix Review 4\fP, 1, pp 78\-85. ! 377: The Regents of the University California expresses their ! 378: gratitude to Unix Review ! 379: for allowing them to reprint this document. ! 380: .PP ! 381: This document is a good starting point for a more thorough tutorial. ! 382: Those with the ambition to expand on this document are encouraged ! 383: to contact the Computer Systems Research Group at ``[email protected].'' ! 384: .KF ! 385: .TS ! 386: center box; ! 387: cf s. ! 388: .sp.2 ! 389: \s+2Groups of \&\fIdbx\fP Requests\s-2 ! 390: .sp.2 ! 391: _ ! 392: .T& ! 393: l lfI ! 394: lp-1fCW l. ! 395: execution and tracing ! 396: _ ! 397: run execute object file ! 398: cont continue execution from where it stopped ! 399: trace display tracing information at specified place ! 400: stop stop execution at specified place ! 401: status display active \&\fItrace\fP and \&\fIstop\fP requests ! 402: delete delete specific \&\fItrace\fP or \&\fIstop\fP requests ! 403: catch start trapping specified signals ! 404: ignore stop trapping specified signals ! 405: step execute the next source line, stepping into functions ! 406: next execute the next source line, even if it's a function ! 407: .T& ! 408: l lfI ! 409: lp-1fCW l. ! 410: _ ! 411: displaying data ! 412: _ ! 413: print print the value of an expression ! 414: whatis print the declaration of a given identifier or type ! 415: which print outer block associated with identifier ! 416: whereis print all symbols matching identifier ! 417: assign set the value of a variable ! 418: .T& ! 419: l lfI ! 420: lp-1fCW l. ! 421: _ ! 422: function and procedure handling ! 423: _ ! 424: where display active procedures and functions on stack ! 425: down move down the stack towards stopping point ! 426: up move up the stack towards \&\fImain\fP ! 427: call call the named function or procedure ! 428: dump display names and values of all local variables ! 429: .T& ! 430: l lfI ! 431: lp-1fCW l. ! 432: _ ! 433: accessing source files and directories ! 434: _ ! 435: edit invoke an editor on current source file ! 436: file change current source file ! 437: func change the current function or procedure ! 438: list display lines of source code ! 439: use set directory list to search for source files ! 440: /.../ search down in file to match regular expression ! 441: ?...? search up in file to match regular expression ! 442: .T& ! 443: l lfI ! 444: lp-1fCW l. ! 445: _ ! 446: miscellaneous commands ! 447: _ ! 448: sh pass command line to the shell ! 449: alias change \&\fIdbx\fP command name ! 450: help explain commands ! 451: source read commands from external file ! 452: quit exit the debugger ! 453: .TE ! 454: .KE ! 455: .bp
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.