Debugging Tools Manual Part Number: 800-3849-10 Revision A of 27 March, 1990 Trademarks Sun Workstation® is a trademark of Sun Microsystems, Incorporated. Copyright © 1990 Sun Microsystems, Inc. - Printed in U.S.A. All rights reserved. No part of this work covered by copyright hereon may be reproduced in any form or by any means - graphic, electronic, or mechanical - including photocopying, recording, taping, or storage in an information retrieval system, without the prior written permission of the copyright owner. Restricted rights legend: use, duplication, or disclosure by the U.S. government is subject to restrictions set forth in subparagraph (c)(l)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 52.227-7013 and in similar clauses in the FAR and NASA FAR Supplement. The Sun Graphical User Interface was developed by Sun Microsystems, Inc. for its users and licensees. Sun ack- nowledges the pioneering efforts of Xerox in researching and developing the concept of visual or graphical user inter- faces for the computer industry. Sun holds a non-exclusive license from Xerox to the Xerox Graphical User Interface, which license also covers Sun’s licensees. This product is protected by one or more of the following U.S. patents: 4,777,485 4,688,190 4,527,232 4,745,407 4,679,014 4,435,792 4,719,569 4,550,368 in addition to foreign patents and applications pending. Contents Chapter 1 Introduction 1 1.1. Three Debuggers 1 dbx 1 dbxtool 1 adb 1 Chapter 2 dbx and dbxtool Compared 3 2.1. Debugging Modes of dbx and dbxtool 3 2.2. Common Features of dbx and dbxtool 3 Filenames 4 Expressions 4 dbx Scope Rules 5 Chapter 3 dbxtool 7 3.1. dbxtool Options 8 3.2. dbxtool Subwindows 8 3.3. Scrolling 9 3.4. The Source Window 9 3.5. Constructing Commands 10 3.6. Command Buttons 10 3.7. The Display Window 1 1 3.8. Editing in the Source Window 12 3.9. Controlling the Environment 12 3.10. Other Aspects of dbxtool 12 - iii- Contents — Continued 3.11. Bugs 14 Chapter 4 dbx 15 4.1. Preparing Files for dbx 16 4.2. Invoking dbx 16 4.3. dbx Options 17 The .dbxinitFile 18 4.4. Listing Source Code 18 4.5. Listing Active and Post-Mortem Procedures 19 4.6. Naming and Displaying Data 19 4.7. Setting Breakpoints 21 4.8. Running and Tracing Programs 22 4.9. Accessing Source Files and Directories 24 4.10. Machine-Level Commands 25 4.11. Miscellaneous Commands 28 4.12. Debugging Large Programs 30 Running Out of Swap Space with Large Files 32 4.13. Debugging Child Processes 33 4.14. dbx FPA Support 35 4.15. Example of FPA Disassembly 36 4.16. Examples of FPA Register Use 37 Chapter 5 Debugging Tips for Programmers 39 5.1. dbx and FORTRAN 40 5.2. A Sample dbx Session 40 Calling a Function 42 Structures and Pointers 42 Parameters 45 Uppercase 45 Parts of Large Arrays 46 Passing Arguments to a Main Program 47 Where Exception Occurred 47 Print in Hex 48 - iv - Contents — Continued 5.3. Using adb with FORTRAN 49 Chapter 6 adb Tutorial 53 6.1. A Quick Survey 53 Starting adb 53 Current Address 54 Formats 54 General Command Meanings 55 6.2. Debugging C Programs 56 Debugging A Core Image 56 Setting Breakpoints 59 Advanced Breakpoint Usage 62 Other Breakpoint Facilities 63 6.3. File Maps 65 407 Executable Files 65 410 Executable Files 66 413 Executable Files 67 Variables 67 6.4. Advanced Usage 68 Formatted Dump 68 Accounting File Dump 70 Converting Values 70 6.5. Patching 70 6.6. Anomalies 72 Chapter 7 Sun386t adb Tutorial 73 7.1. A Quick Survey 73 Starting adb 73 Current Address 74 Formats 74 General Request Meanings 75 7.2. Debugging C Programs on Sun386t 75 Debugging A Core Image 75 Contents — Continued Setting Breakpoints 78 Advanced Breakpoint Usage 82 Other Breakpoint Facilities 83 7.3. File Maps 85 407 Executable Files 85 410 Executable Files 86 413 Executable Files 87 Variables 88 7.4. Advanced Usage 88 Formatted Dump 88 Accounting File Dump 90 Converting Values 90 7.5. Patching 91 7.6. Anomalies 92 Chapter 8 adb Reference 93 8.1. adb Options 93 8.2. Using adb 93 8.3. adb Expressions 94 Unary Operators 95 Binary Operators 95 8.4. adb Variables 96 8.5. adb Commands 96 adb Verbs 96 ?, /, @, and = Modifiers 97 ? and / Modifiers 99 : Modifiers 99 $ Modifiers 100 8 . 6 . adb Address Mapping 102 8.7. See Also 102 8 . 8 . Diagnostic Messages from adb 102 8.9. Bugs 103 8.10. Sun-3 FPA Support in adb 103 - vi- Contents — Continued 8.11. Examples of FPA Disassembly 104 Chapter 9 Debugging SunOS Kernels with adb 107 9.1. Introduction 107 Getting Started 107 Establishing Context 108 9.2. adb Command Scripts 108 Extended Formatting Facilities 108 Traversing Data Structures 1 12 Supplying Parameters 1 13 Standard Scripts 114 9.3. Generating adb Scripts with adbgen 115 Chapter 10 Generating adb Scripts with adbgen 117 10.1. Example of adbgen 11 S 10.2. Diagnostic Messages from adbgen 118 10.3. Bugs in adbgen 118 Index 119 - vii - Tables Table 2-1 Operators Recognized by dbx 4 Table 2-2 Operator Precedence and Associativity 5 Table 3-1 Attribute-Value Pairs for dbxtool 13 Table 4-1 dbx Functions 15 Table 4-2 Tracing and its Effects 23 Table 6-1 Some adb Format Letters 55 Table 6-2 Some adb Commands 55 Table 7-1 Some adb Format Letters 74 Table 7-2 Some adb Commands 75 Table 9-1 Standard Command Scripts 114 - ix — Figures Figure 3-1 Five dbxtool Subwindows 9 Figure 6-1 Executable File Type 407 65 Figure 6-2 Executable File Type 410 66 Figure 6-3 Executable File Type 413 67 Figure 7-1 Executable File Type 407 85 Figure 7-2 Executable File Type 410 86 Figure 7-3 Executable File Type 413 87 - xi- 1.1. Three Debuggers dbx dbxtool adb Introduction This manual describes three debuggers available on Sun Workstations™: dbx, dbxtool, and adb. This document is intended for C, assembler, FORTRAN, Modula-2, and Pascal programmers. dbx is an interactive, line-oriented, source-level, symbolic debugger. It lets you determine where a program crashed, view the values of variables and expres- sions, set breakpoints in the code, and run and trace a program. In addition, machine-level and other commands are available to help you debug code. A detailed description of how to use dbx is found in Chapter 4 . dbxtool is a window-based interface to dbx. Debugging is easier because you can use the mouse to enter most commands from redefinable buttons on the screen. You can use any of the standard dbx commands in the command win- dow. A detailed description of how to use dbxtool is found in Chapter 3 . adb is an interactive, line-oriented, assembly-level debugger. It can be used to examine core files to determine why they crashed, and provides a controlled environment for program execution. Since it dates back to UNIXj Version 7, it is likely to be available on UNIX systems everywhere. Chapters 6 and 7 are tutorial introductions to adb for the Sun-3 and the Sun386/, respectively, and Chapter 8 is a reference manual for it. This manual begins with material about the debuggers of choice, dbxtool and dbx. They are much easier to use than adb, and are sufficient for almost all debugging tasks, adb is most useful for interactive examination of binary files without symbols, patching binary files or object code, debugging programs when the source code is not at hand, and debugging the kernel. Some programs produce core dumps when an internal bug causes a system fault. You can usually produce a core dump by typing [CTRL-M while a process is run- ning. If a process is running in the background, or originated from a different process group, you can get it to dump core by using the gcore(l) utility. t UNIX is a registered trademark of AT&T. sun microsystems Revision A of 6 March 1990 2 Debugging Tools Revision A of 6 March 1990 2 dbx and dbxtool Compared 2.1. Debugging Modes of Both dbx and dbxtool support three distinct types of debugging: post-mortem, dbx and dbxtool live-process, and multiple-process. References to dbx below apply to dbxtool as well. You can do post-mortem debugging on a program that has created a core file. Using the core file as its image of the program, dbx retrieves the values of variables from it. The most useful operations in post-mortem debugging are get- ting a stack trace with where, and examining the values of variables with print. Operations such as setting breakpoints, suspending and continuing exe- cution, and calling procedures, are not supported with post-mortem debugging. In live-process debugging, a process’s execution is controlled by dbx. From there, the user can: □ set the process’ starting point □ set and clear breakpoints □ restart a stopped process. The most useful operations are getting a stack trace with where, examining the values of variables with print and display, setting breakpoints with stop, and continuing execution with next, step, and cont. Multiple-process debugging is most useful when debugging the interaction between two tightly coupled programs. For example, in a networking situation it is common to have server and client processes that use some style of inter- process communication (remote procedure calls, for example). To debug both the client and the server simultaneously, each process must have its own instance of dbx. When using dbx for multiple-process debugging, it is advisable to begin each dbx in a separate window. This gives you a way to debug one pro- cess without losing the context of the other debugging session. NOTE This does not mean that either dbx or dbxtool supports remote debugging. You can debug only processes running on your machine. 2.2. Common Features of dbx and dbxtool The following symbols and conventions apply to both dbx and dbxtool; as before, references to dbx apply to dbxtool as well. #sun microsystems 3 Revision A of 6 March 1990 4 Debugging Tools Filenames Expressions Filenames within dbx may include shell metacharacters. The shell used for pat- tern matching is determined by the SHELL environment variable. Expressions in dbx are combinations of variables, constants, procedure calls, and operators. Hexadecimal constants begin with “Ox” and octal constants with “0”. Character constants must be enclosed in single quotes. Expressions cannot involve literal strings, structures, or arrays, although elements of structures and arrays may be used. However, the print and display commands do accept structures or arrays as arguments and, in these cases, print the entire contents of the structure or array. The call command accepts literal strings as arguments, and passes them according to the calling conventions of the language of the rou- tine being called. Table 2-1 Operators Recognized by dbx Operators Recognized by dbx + add - subtract * multiply / divide div integer divide o, "o remainder « left shift » right shift & bitwise and 1 bitwise or - exclusive or ~ bitwise complement & address of * contents of < less than > greater than <= less than or equal to >= greater than or equal to == equal to i = not equal to i not && logical and 1 1 logical or sizeof size of a variable or type (type) type cast . structure field reference -> pointer to structure field reference The operator can be used with pointers to records, as well as with records themselves, making the C operator unnecessary (though it is supported). Precedence and associativity of operators are the same as in C, and are described in Table 2-2 below. Parentheses can be used for grouping. Revision A of 6 March 1990 cfbx Scope Rules Chapter 2 — dbx and dbxtool Compared 5 T able 2-2 Operator Precedence and Associativity Operator Associativity Precedence . -> left to right highest ! (type) * & sizeof right to left * / % div left to right + - left to right A A V V left to right II A A II V V left to right == ! = left to right & left to right - left to right 1 left to right && left to right 1 1 left to right 9 : right to left lowest Of course, if the program being debugged is not active and there is no core file, you may only use expressions containing constants. Procedure calls also require that the program be active. dbx uses two variables to resolve scope conflicts: file and f unc (see Section 4.8 ). The values of file and func change automatically as files and routines are entered and exited during execution of the user program. They can also be changed by the user. Changing func also changes the value of file; however, changing file does not change func. The func variable is used for name resolution, as in the command print grab where grab may be defined in two different routines. The search order is: 1) Search for grab in the routine named by func. 2) If grab is not found in the routine named by func, search the file contain- ing the routine named by func. 3) Finally, search the outer levels — the whole program in the case of C and FORTRAN, and the outer lexical levels (in order outward) in the case of Pas- cal — for grab. Clearly, if grab is local to a different routine than the one named by func, or is a static variable in a different file than is the routine named by func, it won’t be found. Note, however, that print a 'grab is allowed, as long as routine a has been entered but not yet exited. Note that the file containing the routine a might have to be specified when the file name (minus its suffix) is the same as a routine name. For example, if routine a is found in module a . c, then print a 'grab would not be enough — you would have to use print a 'a 'grab. If in doubt as to how to specify a name, use the whereis command, as in sun microsystems Revision A of 6 March 1990 6 Debugging Tools whereis grab to display the full qualifications of all instances of the specified name — in this case grab. The variable file is used to: 1) Resolve conflicts when setting f unc — for example, when a C program has two static routines with the same name. 2) Determine which file to use for commands that take only a source line number — for example, stop at 55. 3) Determine which file to use for commands such as edit, which has optional arguments or no arguments at all. When dbx begins execution, the initial values of file and f unc are deter- mined by the presence or absence of a core file or process ID. If there is a core file or process ID, f ile and f unc are set to the point of interruption. If there is no core file or process ID, f unc is set to main (or MAIN for FORTRAN) and file is set to the file containing main or ( MAIN). Note that changing f unc doesn’t affect the place where dbx continues execu- tion when the program is restarted. microsystems Revision A of 6 March 1990 3 dbxtool dbxtool [ -kdb ] [ -I dir ] [ objectfile [ corefile I processID ] ] dbxtool is a source-level debugger with a window and mouse-based user inter- face, accepting dbx’s commands with a more convenient user interface. Using the mouse, one can set breakpoints, examine variable values, control execution, browse source files, and so on. There are subwindows for viewing source code, entering commands, and several other uses. This debugger functions in the sun- tools(l) environment, so that the standard tool manager actions, such as mov- ing, resizing, moving to the front or back, and so on can be applied to it. For more information on dbxtool, see the dbxtool ( 1 ) man page. In the usage above, objectfile is an object file produced by cc, f 7 7, pc, or Modula-2 or a combination thereof, with the -g flag specified to produce the appropriate symbol information. If no objectfile is specified, one may use the debugger’s debug command to specify the program to be debugged. The object file contains a symbol table which includes the names of all the source files translated by the compiler to create it. These files are available for perusal while using the debugger, and can be seen with the modules command. NOTE Every stage of the compilation process, including the linking and loading phases, must include the -g option. dbxtool can be used to examine the state of the program when it faulted if a file named core exists in the current directory, or a corefile is specified on the command line or in the debug command. Giving a processID instead of a corefile, halts that process and begins debugging it. Detaching the debugger from the process allows that process to continue to execute. 7 Revision A of 6 March 1990 8 Debugging Tools 3.1. dbxtool Options -kdb Debugs a program that sets the keyboard into up-down translation mode. This flag is necessary if you are debugging a program that uses up-down decoding. -I dir Add dir to the list of directories searched when looking for a source file. Normally dbxtool looks for source files in the directory where objectfile is located, and if the source files can’t be found there or in the current direc- tory, the user must tell dbxtool where to find the source files; either by means of the -I option or else by setting the directory search path by means of the use command. Multiple -I options may be given. 3.2. dbxt oo 1 Subwindows A dbxtool window consists of five subwindows. From top to bottom they are: status Gives the overall status of debugging, including the location where execution is currently stopped, and a description of lines displayed in the source subwindow. source Displays source text of the program being debugged, and allows you to move around in the source file. buttons Contains buttons for frequently used commands; picking a button with the mouse invokes the corresponding command. command Provides a typing interface to supplement the buttons subwindow. Also, most command output appears in this subwindow. display Display output appears here. #sun microsystems Revision A of 6 March 1990 Chapter 3 — dbxtool 9 Figure 3-1 Five dbxtool Subwindows Awaiting Execution File Displayed: . /example. c Lines: 13-32 */ struct few feu2 = { 3, 4, NULL, "world" } ; struct few fewl - { 1, 2, &few2, "hello" } ; * write a main program to use the structures V main() £ r * declare the variable *fewp * to p[oint to a few-type structure */ struct few *fewp; /* * print out a message V f for (fewp - &fewl; fewp !- NULL; nrawa = fewp -> next) { printf("7.s ", fewp -> message); [ print ][print *][ next ][ step~)[stop at][ cont ][stop in][ cleaT~][ where [ UP DC down ][ run ) Reading symbolic information... Read 155 symbols (dbxtool) run Running: example hel lo world execution completed, exit code is 0 program exited with 0 (dbxtool) stop at "example ,c" : 29 (2) stop at "example .c" :29 (dbxtool) print fewp "fewp" is not active (dbxtool ) 3.3. Scrolling The source, command, and display windows have scroll bars to facilitate brows- ing their contents. The scroll bar is at the left edge of each window. See the SunView User’s Guide for a more complete description of scroll bars. 3.4. The Source Window The source window displays the text of the program being debugged. Initially, it displays text from either the main routine, if there is no core file, or the point at which execution stopped, if there is a core file. Whenever execution stops during a debugging session, it displays the point at which it stopped. The file com- mand can be used to switch the source window to another file; the focus of atten- tion moves to the beginning of the new file. Similarly, the f unc command can be used to switch the source window to another function; the new focus of atten- tion is the first executable line in the function. Breakpoints are indicated in the source window by a solid stop sign at the begin- ning of the line. The point at which execution is currently stopped is marked by a rightward pointing outlined or hollow arrow. microsystems Revision A of 6 March 1990 10 Debugging Tools One can either type commands to dbxtool, in the command window or con- struct commands with the selection and button mechanism (if a button is pro- vided for the command), but typing and buttons cannot be combined to build a command. The command window is a text subwindow and so uses the text selection facility described in the SunView User’s Guide. The software buttons operate in a postfix manner. That is, one first selects the argument, and then clicks the software button with the left mouse button. Each command interprets the selection as appropriate for that command. There are five ways that dbxtool may interpret a selection: literal A selection may be interpreted as exactly representing selected material. expand A selection may be interpreted as exactly representing selected material, except that it is expanded if either the first or last character of the selection is an alphanumeric character or underscore. It is expanded to the longest enclosing sequence of alphanumeric charac- ters or underscores. Selections made outside of dbxtool cannot be expanded and are interpreted as exactly the selected text. lineno A selection in the source window may be interpreted as representing the (line number of the) first source line containing all or some of the selection. command A selection in the command window may be interpreted as represent- ing the command containing the selection. ignore Buttons may ignore a selection. 3.6. Command Buttons The standard set of command buttons in the buttons window is as follows: print Print the value of a variable or expression. Since this button expands the selection, identifiers can be printed by selecting only one charac- ter. print * Print the value at the address represented by the selected variable or expression. next Execute one source statement and then stop execution, except that if the statement contains a procedure or function call, execute through the called routine before stopping. The next button ignores the selection. step Execute one source line and then stop execution again. If the current source line contains a procedure or function call, stop at the first exe- cutable line within the procedure or function. The step button ignores the selection. stop at Set a breakpoint at a given source line. Interpret a selection in the source window as representing the line number associated with the first line of the selection. 3.5. Constructing Commands Revision A of 6 March 1990 Chapter 3 — dbxtool 1 1 The Button Command cont Resume execution from the point where it is currently stopped. The cont button ignores the selection. stop in Set a breakpoint at the first line of a given function or procedure. Since this button expands the selection, identifiers may be printed by selecting only one character. clear Clear all breakpoints at the currently selected point. clear clears all breakpoints at the specified line number. where Prints a procedure traceback. where prints number top procedures in the traceback. up Moves up the call stack one level. up moves the call stack up number levels. down Moves the call stack down one level. down moves the call stack down number levels. run Begins execution of the program. run begins execution of the program with new arguments. The button command defines buttons in the buttons window. It can be used in . dbxinit to define buttons not otherwise displayed, or during a debugging ses- sion to add new buttons. The first argument to button is the selection interpre- tation for the button, and the remainder is the command associated with it. The default set of buttons can be replicated by the following sequence: f \ button expand print button expand print * button ignore next button ignore step button lineno stop at button ignore cont button expand stop in button ignore clear button ignore where button ignore up button ignore down button ignore run V j The unbutton command may be used in . dbxinit to remove a default but- ton from the buttons window, or during a debugging session to remove an exist- ing button. The argument to unbutton is the name of the command associated with the button. 3.7. The Display Window The display window provides continual feedback of the values of selected vari- ables. The display command specifies variables to appear in the display win- dow, and undisplay removes them. Each time execution of the program being debugged stops, the values of the displayed variables are updated. micros yslems Revision A of 6 March 1990 12 Debugging Tools 3.8. Editing in the Source The source window is a standard text subwindow (see SunView User’s Guide for Window details). Initially dbxt ool puts the source subwindow in browse mode, mean- ing that editing capabilities are suppressed, dbxtool adds a “start editing” entry to the standard text subwindow menu in the source window. When this menu item is selected, the file in the source window becomes editable, the menu item changes to “stop editing”, and any annotations (stop signs and arrows) are removed. The “stop editing” menu item is a pull-right menu with two options: “save changes” and “ignore changes”. Selecting either of these menu items dis- ables editing, changes the menu item back to “start editing”, and causes the anno- tations to return. After editing a source file, it is advisable to rebuild the program, as the source file no longer reflects the executable program. 3.9. Controlling the The toolenv command provides control over several facets of dbxtool ’s Environment window environment, including the font, the vertical size of the source, com- mand, and display windows, the horizontal size of the tool, and the minimum number of lines between the top or bottom of the source window and the arrow. These are chiefly useful in the . dbxinit file to control initialization of the tool, but may be issued at any time. 3.10. Other Aspects of The commands, expression syntax, scope rules, etc. of dbxtool are identical to dbxtool those of dbx. Three of the commands, toolenv, button, and unbutton affect only dbxtool, so they are described below. See Chapter 4 for descrip- tions of the others. toolenv toolenv [ attribute value ] microsystems Revision A of 6 March 1990 Chapter 3 — dbxtool 1 3 button unbutton menu Set or print attributes of the dbxtool window. This command has no effect in dbx. The possible attribute-value pairs and their interpretations are as follows: Table 3-1 Attribute-Value Pairs for dbxtool Attribute-Value Description font fontfile change the font to that found in fontfile', default is taken from the DEFAULT_FONT shell variable. width nchars change the width of the tool window to nchars charac- ters; default is 80 characters. srclines nlines make the source subwindow nlines high; default is 20 lines. cmdlines nlines make the command subwindow nlines high; default is 12 lines. di splines nlines make the display subwindow nlines high; default is 3 lines. topmargin nlines keep the line with the arrow at least nlines from the top of the source subwindow; default is 3 lines. botmargin nlines keep the line with the arrow on it at least nlines from the bottom of the source subwindow; default is 3 lines. The toolenv command with no arguments prints the current values of all the attributes. button selection command-name Associate a button in the buttons window with a command in dbxtool. This command has no effect in dbx. The argument selection may be any of literal, expand, lineno, command and ignore, as described in Section 3.5 . The commandjiame argument may be any sequence of words correspond- ing to a dbxtool command. unbutton command-name Remove a button from the buttons window. The first button with a matching command-name is removed. The menu command defines the menu list in the buttons window. It can be used in . dbxinit to define menu items not otherwise displayed, or during a debug- ging session to add new menu items. The first argument to menu is the selection interpretation for the menu, and the remainder is the command associated with it. The default set of menu items can be replicated by the following sequence: Revision A of 6 March 1990 14 Debugging Tools menu expand display menu expand undisplay menu expand file menu expand func menu ignore status menu lineno cont at menu ignore make menu ignore kill menu expand list menu ignore help unmenu 3.11. Bugs The unmenu command may be used in . dbxinit to remove a default menu item from the menu, associated with the buttons window or, during a debugging session, to remove an existing menu item. The argument to unmenu is the menu item to be removed. The interaction between scrolling in the source subwindow and dbx’s regular expression search commands is wrong. Scrolling should affect where the next search begins, but it does not. microsystems Revision A of 6 March 1990 dbx dbx [ -r ] [ -kbd ] [ -I dir ] [ objectfile [ corefile I processID ] ] dbx is a tool for source-level debugging and execution of programs, that accepts the same commands as dbxtool, but has a line-oriented user interface, which does not use the window system. It is useful when you can’t run SunView. (See also the dbx(l) man page.) Table 4-1 dbx Functions dbx Functions Function Commands list active procedures down, up, where name, display, and set variables assign, display, dump, print, set, set 81 , undisplay, whatis, whereis, which set breakpoints catch, clear, delete, ignore, status, stop, when run and trace program call, cont, next, rerun, run, step, trace access source files & directories cd, edit, file, func, list, pwd, use, /, ? machine-level commands nexti, stepi, stopi, tracei, address, + miscellaneous commands alias, dbxenv, debug, detach, help, kill, make, modules, quit, sh, source, setenv Although dbx provides a wide variety of commands, there are a few that you will execute most often. You will probably want to □ find out where an error occurred, ®sun microsystems 15 Revision A of 6 March 1990 1 6 Debugging T ools □ display and change the values of variables, □ display the values of constants, □ set breakpoints, □ and run and trace your program. When compiling programs with cc, f 77, or pc, you must specify the -g option on the command line, so that symbolic information is produced in the object file. Every step of compilation (including linking and loading) must include this option. In the past, many dbx users have compiled, with the -g option, only those modules suspected of containing a bug that they wanted to fix, as this was an efficient means of debugging large programs. Those modules compiled without -g were accessible by just a few dbx commands, such as stop in , trace , and print . However, dbx now contains the modules command, which is expressly designed to aid in the debugging of large programs. The modules command allows you to specify those modules for which dbx should read source level debugging information. Therefore, it is recommended that most, if not all, modules be compiled with the -g option, and the modules command used to debug the resulting program. For more information on the modules command, see Section 4.12, "Debugging Large Programs." NOTE The following list contains a few notes you may want to keep in mind while using dbx: □ dbx won’t correctly debug library modules whose names are more than 14 characters long. While ar emits a warning at the time the library is being created that the name of the file is being truncated, dbx will offer no warn- ing that there is a problem, other than not working correctly as you attempt to debug the offending module. □ If you use Id’s -r option when compiling your program, attempts to debug the final load module with dbx will often fail. This is because Id -r modifies the symbol table and the resultant load module. □ dbx may not work on programs using shared libraries, especially user- defined shared libraries. Therefore, for best results, compile and link your programs statically, on the command line, with the -Bstatic option. 4.2. Invoking dbx To invoke dbx, type: / demo% dbx options objfile core ) ile I processid — ~ N V NOTE All the arguments are optional. 4.1. Preparing Files for dbx microsystems Revision A of 6 March 1990 Chapter 4 — dbx 1 7 dbx begins execution by printing: r Reading symbolic information... Read nnn symbols (dbx) v J To exit dbx and return to the command level, type: ( (dbx) quit demo% J For additional information and assistance, see Debugging Tips for Programmers in Chapter 5 where a sample FORTRAN program and several examples are pro- vided. With a few changes and modifications to the examples this chapter may also be useful for C programmers. 4.3. dbx Options The options to dbx are: -r Execute objfile immediately. Arguments to the program being debugged follow the object filename (redirection is handled properly). If the program terminates successfully, dbx exits. Otherwise, dbx reports the reason for termination and waits for your response. When -r is specified and standard input is not a terminal, dbx reads from /dev/ tty. -kdb Debugs a program that sets the keyboard into up-down translation mode. This flag is necessary if a program uses up-down decoding. -I dir Add dir to the list of directories searched when looking for a source file. Normally, dbx looks for source files in the directory where objfile is located, and if the source files can’t be found there or in the current directory, the user must tell dbx where to find the source files; either by specifying the -I option or by setting the directory search path with the use command. The objfile contains compiled object code. If it is not specified, one can use dbx’ s debug command to specify the program to be debugged. The object file contains a symbol table, which includes the names of all the source files the com- piler translated with -g. These files are available for perusal while using the debugger. If a file named core exists in the current directory, or a corefile is specified, dbx can be used to examine the state of the program when it faulted. If a pro- cessID is given instead, dbx halts that process and begins debugging it. If you later detach the debugger from it, the process continues to execute. #sun microsystems Revision A of 6 March 1990 1 8 Debugging Tools The . dbxinit File Users of prior releases of dbx may have grown used to setting breakpoints in their . dbxinit file. The addition of the modules command has caused . dbxinit to be read BEFORE the symbol table information rather than AFTERWARDS as in previous versions. Hence, setting breakpoints in a . dbxinit file no longer works. To work around this difficulty, you may define an alias in your . dbxinit file which will source another file of dbx commands; you can then set up this addi- tional file to contain the breakpoint-setting commands. Once you have set up this second file with the breakpoint commands, all you need do is invoke the alias immediately after you invoke dbx . The last line in . dbxinit may look something like this: alias moredbx source .dbxinit2 The contents of . dbx in it 2 may look something like this : stop in main stop in initial Once you have properly set up the . dbxinit file with the above alias, the first command you issue is: moredbx 4.4. Listing Source Code If you invoked dbx on an objfile, you can list portions of your program, and associated line numbers in the program’s source files. For example, consider the program example . c, which you can see by typing: ( (dbx) list 1,12 1 #include 2 3 main ( ) 4 { 5 printf ("goodbye world! \n"); 6 dumpcore ( ) ; 7 } 8 9 dumpcore ( ) 10 ( 11 abort ( ) ; 12 } V y If the range of lines starts past the end of file, dbx will tell you the program has only so many lines; if the range of lines goes past the end of file, dbx will print as many lines as it can, without complaining. You can also list just a single pro- cedure by typing its name instead of a range of lines; for example list main prints ten lines starting near the top of the main ( ) procedure. Asun microsystems Revision A of 6 March 1990 Chapter 4 — dbx 19 4.5. Listing Active and Post-Mortem Procedures 4.6. Naming and Displaying Data If your program fails to execute properly, you probably want to find out the pro- cedures that were active when the program crashed. Use the where command, like this: r \ where [ n ] k y where displays a list of the top n active procedures and functions on the stack, and associated sourcefile line numbers (if available). If n is not specified, all active procedures are displayed. When debugging a post-mortem dump of the example . c program above, dbx prints the following: ' ■ — > demo% dbx example core Reading symbolic information. . . Read 41 symbols program terminated by signal ABRT (abort) (dbx) (dbx) where abort ( ) at 0x80e5 dumpcoreO, line 12 in "example, c" main(0xl, 0xfffd84, 0xfffd8c) , line 7 in "example. c" (dbx) ^ , Two other commands useful for viewing the stack are: up [ n ] Move up the call stack (towards main) n levels. If n is not specified, the default is one. This command allows you to examine the local variables in functions other than the current one. down [n] Move down the call stack (towards the current stopping point) n levels. If n is not specified, the default is one. You can name and display your data with the following commands: print expression [, expression ...] Print the values of specified expressions. An expression may involve func- tion calls if you are debugging an active process. If execution of a function encounters a breakpoint, execution halts and the dbx command level is re- entered. A stack trace with the where command shows that the call ori- ginated from the dbx command level. Variables having the same name as one in the current function may be refer- enced as f unc name ‘ variable, or filename ‘ func name ‘ variable. The filename is required \ifuncname occurs in several files or is identical to a filename. For example, to access variable i inside routine a, which is declared inside module a . c, you would have to use print a 'a ' i to make the name a unambiguous. Use whereis to determine the fully qualified name of an identifier. For more details, see dbx Scope Rules in Chapter 5. Revision A of 6 March 1990 Hexadecimal numbers can be printed using the alias command in con- junction with machine-level commands. For more information, see Print in Hex in Chapter 5. di splay [ expression [, expression ...] ] Display the values of the expressions each time execution of the debugged program stops. The name qualification rules for print apply to display as well. With no arguments, the display command prints a list of the expressions currently being displayed, and a display number associated with each expression. In dbxtool, the variable names and values are shown in the display subwindow; in dbx they are printed automatically whenever execution stops. undisplay expression [, expression ...] Stop displaying the expressions and their values each time execution of the program being debugged stops. The name qualification rules for print apply to undisplay as well. A numeric expression is interpreted as a display number and the corresponding expression is deleted from the display. what is identifier what is type Print the declaration of the given identifier or type. The identifier may be qualified with block names as above. The type argument is useful to print all the members of a structure, union, or enumerated type. which identifier Print the fully qualified form of the given identifier; that is, the outer blocks with which the identifier is associated. whereis identifier Print the fully qualified form of all symbols whose names match the given identifier. The order in which the symbols are displayed is not meaningful. assign variable = expression set variable = expression Assign the value of the expression to the variable. Currently no type conver- sion takes place if the operands are of different types. set 8 1 fpreg = wordl word2 word3 Treat the 96-bit value gotten by concatenating wordl, word2, and word3 as an IEEE floating-point value, and assign it to the named MC68881 floating- point register fpreg. Note that MC6888 1 registers can also be set with the set command, but that the value is treated as double-precision and con- verted to extended precision. This command applies to Sun-3 systems only. dump [func ] Display the names and values of all the local variables and parameters in func. If not specified, the current function is used. sun Revision A of 6 March 1990 microsystems Chapter 4 — dbx 2 1 4.7. Setting Breakpoints Breakpoints are set with the stop and when commands, which have the follow- ing forms: stop at source-line-number [if condition ] Stop execution at the given line number whenever the condition is true. If condition is not specified, stop every time the line is reached. stop in procedure/function [if condition ] Stop execution at the first line of the given procedure or function whenever the condition is true. If condition is not specified, stop every time the pro- cedure or function is entered. stop variable [if condition ] Stop execution whenever the value of variable changes and condition is true. If condition is not specified, stop every time the value of variable changes. This command performs interpretive execution, and thus is significantly slower than most other dbx commands. stop if condition Stop execution whenever condition becomes true. This command performs interpretive execution, and thus is significantly slower than most other dbx commands. when in procedur elf unction { command; ... } Execute the given dbx commandfs) whenever the specified procedure or function is entered. when at source-line-number { command; ... } Execute the given dbx command(s) whenever the specified source-line- number is reached. when condition { command; ... } Execute the given dbx command(s) whenever the condition is true before a statement is executed. This command performs interpretive execution, and thus is significantly slower than most other dbx commands. NOTE In the when commands, the braces and the semicolons between commands are required. The following commands can be used to view and change breakpoints: status [ > filename ] Display the currently active trace, stop, and when commands. A command-number is listed for each command. The filename argument causes the output of status to be sent to that file. delete command-number [[ ,] command-number . . . ] delete all Remove the trace, when, and/or stop commands corresponding to the given command-numbers, or all of them. The status command explained above displays the numbers associated with these commands. clear [source-line-number] Clear all breakpoints at the given source line number. If no source-line- number is given, the current stopping point is used. Revision A of 6 March 1990 22 Debugging Tools Two additional commands can be used to set a breakpoint when a signal is detected by the program, rather than a condition or location. catch [ number [[ , ]number . . . ] ] Start trapping the signals with the given numbers) before they are sent to the program being debugged. This is useful when a program handles signals such as interrupts. Initially all signals are trapped except SIGHUP, SIGEMT, SIGFPE, SIGCONT, SIGCHLD, SIGALRM, SIGKILL, SlGTSTP.and SIGWINCH. If no number is given, list the signals being caught. ignore [ number [[ ,] number . . . ] ] Stop trapping the signals with the given numbers) before they are sent to the program being debugged. This is useful when a program handles signals such as interrupts. If no number is given, list the signals being ignored. You can run and trace your code using the following commands: run [ args ] [ > filename I » filename ] Start executing objfile, specified on the dbx command line (or with the most recent debug command), passing args as command-line arguments; <, >, and » can be used to redirect input or output in the usual manner. Other- wise, all characters in args are passed through unchanged. If no arguments are specified, the argument list from the last run command (if any) is used. If objfile has been written since the last time the symbolic information was read in, dbx reads the new information before beginning execution. For more information, see Passing Arguments to a Main Program in Chapter 5 rerun [ args ] [ > filename I » filename ] Identical to run, except in the case where no arguments are specified. In that case run runs the program with the same arguments as on the last invo- cation, whereas rerun runs it with no arguments at all. cont [at source-line-number] [sig sig-number ] Continue execution from where it stopped, or, if the clause at source-line- number is given, at that line number. The sig-number causes execution to continue as if that signal had occurred. The source-line-number is evaluated relative to the current file and must be within the current procedure/function. Execution cannot be continued if the process has finished (that is, has called the standard procedure _exit). dbx captures control when the process attempts to exit, thereby letting the user examine the program state. trace source-line-number [if condition ] trace procedure/ function [if condition ] trace [in procedure/function ] [if condition ] trace expression at source-line-number [if condition ] trace variable [in procedure/function ] [if condition ] Display tracing information when the program is executed. A number is associated with the trace command, and can be used to turn the tracing off (see the delete command). 4.8. Running and Tracing Programs Revision A of 6 March 1990 Chapter 4 — dbx 23 If no argument is specified, each source line is displayed before it is exe- cuted. Execution is substantially slower during this form of tracing. The clause in procedure/function restricts tracing information to be displayed only while executing inside the given procedure or function. Note that the procedure/function traced must be visible in the scope in which the trace command is issued — see the f unc command. The condition is a Boolean expression evaluated before displaying the trac- ing information; the information is displayed only if condition is true. The first argument describes what is to be traced. The effects of different kinds of arguments are described below: Table 4-2 Tracing and its Effects source-line-number Display the line immediately before executing it. Source line numbers in a file other than the current one must be preceded by the name of the file in quotes and a colon, for example, "mumble .p" : 17. procedure/function Every time the procedure or function is called, display information telling what routine called it, and what parameters were passed to it. In addi- tion, its return is noted, and if it is a function, the return value is also displayed. expression The value of the expression is displayed whenever the identified source line is reached. variable The name and value of the variable are displayed whenever the value changes. Execution is sub- stantially slower during this form of tracing. Tracing is turned off whenever the function in which it was turned on is exited. For instance, if the program is stopped inside some procedure and tracing is invoked, the tracing will end when the procedure is exited. To trace the whole program, tracing must be invoked before a run command is issued. When using conditions with trace, stop, and when, remember that variable names are resolved with respect to the scope current at the time the command is issued (not the scope of the expression inside the trace, stop, or when com- mand). For example, if you are currently stopped in function f oo () and you issue the command r stop in bar if x==5 V the variable x refers to the x in function f oo ( ) , not in bar ( ) . The f unc com- mand can be used to change the scope before issuing a trace, stop, or when command, or the name can be qualified, for example, bar . x==5. microsystems Revision A of 6 March 1990 24 Debugging Tools Step [«] Execute through the next n source lines and then stop. If n is not specified, it is taken to be one. Step into procedures and functions. next [ n ] Execute through the next n source lines and then stop, counting functions as single statements. call procedure ( parameters ) Execute the named procedure (or function), with the given parameters. If any breakpoints are encountered, execution halts and the dbx command level is reentered. A stack trace with the where command shows that the call originated from the dbx command level. If the source file in which the routine is defined was compiled with the -g flag, the number of arguments is checked and warnings are issued. You must ensure that arguments of the appropriate type are passed. If C routines are called that are not compiled with the -g flag, dbx does NOT check the number of parameters. The parameters are simply pushed on the stack as given in the parameter list. Currently, FORTRAN alternate return points may not pass properly. 4.9. Accessing Source Files These commands let you access source files and directories without exiting dbx: and Directories edit [filename] edit procedure/function Invoke an editor on filename (or on the current source file if none is specified). If a procedure or function name is specified, the editor is invoked on the file that contains it. The default editor invoked is vi. Set the environment variable EDITOR to the name of a preferred editor to override the default. For dbxtool, the editor comes up in a new window. file [filename] Change the current source file to filename, or print the name of the current source file if no filename is specified. f unc [ procedure / function ] Change the current function, or print the name of the current function if none is specified. Changing the current function implicitly changes the current source file displayed by file to the one that contains the function; it also changes the current scope used for name resolution. list [ source-line-number [ , source-line-number ] ] list procedure/function List the lines in the current source file from the first line number through the second. If no lines are specified, the next 10 lines are listed. If the name of a procedure or function is given, lines n-5 to n+5 are listed, where n is the first statement in the procedure or function. If the list command’s argu- ment is a procedure or function, the scope for further listing is changed to that routine — use the file command to change it back. In dbxtool, the Note: The FPA register names $fpaO . . $fpa31 can be used in arithmetic expressions and in set commands on machines with a FPA. This extension only applies on a machine with an FPA. Note that if an FPA register is used in an expression or assignment, its type is assumed to be double precision. FPA registers can be displayed in single precision using the /f display format. Double-precision values are displayed using the /F. &sun microsystems Revision A of 6 March 1990 Chapter 4 — dbx 25 region of the file is shown in the source window and extends from the first line number to the end of the window. use [ directory ... ] Set the list of directories to search when looking for source files. If no direc- tory is given, print the current list of directories. Supplying a list of direc- tories replaces the current (possibly default) list. The list is searched from left to right. cd [ dirname ] Change dbx’s notion of the current directory to dirname. With no argu- ment, use the value of the HOME environment variable. pwd Print dbx’s notion of the current directory. /string[/] Search downward in the current file for the regular expression string. The search begins with the line immediately after the current line and, if neces- sary, continues until the end of the file. The matching line becomes the current line. lstring[l] Search upward in the current file for the regular expression string. The search begins with the line immediately before the current line and, if neces- sary, continues until the top of the file. The matching line becomes the current line. When dbx searches for a source file, the value of file and the use directory search path are used. The value of file is appended to each directory in the use search path until a matching file is found. This file becomes the current file. dbx knows the same filenames as were given to the compilers. For instance, if a file is compiled with the command f \ % cc -c -g . /mip/ scan . c v then dbx knows the filename . . /mip/ scan . c, but not scan . c. 4.10. Machine-Level These commands are used to debug code at the machine level: Commands . r , , tracei [ address ] [if cond ] tracei [ variable ] [at address ] [if cond ] Turn on tracing of individual machine instructions. stopi [variable] [if cond ] stopi [at address ] [if cond] Set a breakpoint at the address of a machine instruction. stepi nexti Single step as in step or next, but do a single machine instruction rather than a line of source. Revision A of 6 March 1990 26 Debugging Tools address, address / [ mode ] address / [ count ] [ mode ] +/ [ count ] [ mode ] Display the contents of memory starting at the first address and continuing up to the second address, or until count items have been displayed. If a + is specified, the address following the one displayed most recently is used. The mode specifies how memory is displayed; if omitted, the last specified mode is used. The initial mode is X. The following modes are supported: Mode Does i display as a machine instruction d display as a halfword in decimal D display as a word in decimal o display as a halfword in octal 0 display as a word in octal X display as a halfword in hexadecimal X display as a word in hexadecimal b display as a byte in octal c display a byte as a character s display as a string of characters terminated by a null byte f display as a single-precision real number F display as a double-precision real number E display as an extended-precision real number Symbolic addresses used in this context are specified by preceding a name with an ampersand &. Registers are denoted by preceding a name with a dollar sign $. Here is a list of MC680x0 register names: Register Name $d0-$d7 data registers $a0-$a7 address registers $fp frame pointer (same as $a6) $sp stack pointer (same as $a7) $pc program counter $ps program status The following registers apply only to Sun-3 workstations: Register Name $fp0-$fp7 MC6888 1 data registers $fpc MC6888 1 control register $fps MC6888 1 status register $fpi MC6888 1 instruction address register $fpf MC6888 1 flags (unused, idle, busy) $fpg MC6888 1 floating-point signal type For example, to print the contents of the data and address registers in hex on a Sun-3, type &$d0 /16X or &$d0 , &$a7/X. To print the contents of register dO, type print $d0 (one cannot specify a range with print). Addresses microsystems Revision A of 6 March 1990 Chapter 4 — dbx 27 may be expressions made up of other addresses and the operators + (plus), - (minus), * (multiply), and indirection (unary *). The address may be a + alone, which causes the next location to be displayed. See the SPARC Architecture Reference Manual and the Sun-4 Assembly Language Reference Manual for information about Sun-4 registers and address- ing. Here is the list of Sun386t registers: Register Name $ss stack segment register $ef lags flags $cs code segment register $eip instruction pointer $eax general register $ebx general register $ecx general register $edx general register $esp stack pointer $ebp frame pointer $esi source index register $edi destination index register $ds data segment register $es alternate data segment register $f s alternate data segment register $gs alternate data segment register On the Sun386/, to print the contents of the data and address registers in hex, type &$eax/10X or &$eax,&$eip/X. Data segment registers are always printed together, so &$cs/X is the same as &$cs,&$gs/X. The print command can also be as in print $eax. You can also access parts of the Sun386/ registers. Specifically, the lower halves (16 bits) of these registers have separate names, as follows: Register Name $ax general register $cx general register $dx general register $bx general register $sp stack pointer $bp frame pointer $si source index register $di destination index register $ip instruction pointer, lower 16 bits $f lags flags, lower 16 bits microsystems Revision A of 6 March 1990 28 Debugging Tools Furthermore, the first four of these 16 bit registers can be split into two 8-bit parts, as follows: Register Name $al lower (right) half of register $ax $ah higher (left) half of register $ax $cl lower (right) half of register $cx $ch higher (left) half of register $cx $dl lower (right) half of register $dx $dh higher (left) half of register $dx $bl lower (right) half of register $bx $bh higher (left) half of register $bx The registers for the Sun386/ math coprocessor are the following: Register Name $f Ctrl $f stat $ftag $f ip $f cs $f opof f $f opsel $st0 - $st7 control register status register tag register instruction pointer offset code segment selector operand pointer offset operand pointer selector data registers 4.11. Miscellaneous sh [command-line] Commands Pass the SunOS command line to the shell for execution. The SHELL environment variable determines which shell is used. alias new- command-name character-sequence Respond to new-command-name as though it were character-sequence. Spe- cial characters occurring in character-sequence must be enclosed in double quotation marks. Alias substitution as in the C shell also occurs. For exam- ple, ! : 1 refers to the first argument. The command — alias mem "print ( ! : 1) ->meml->mem2" V- creates a mem command that takes an argument, evaluates its meml->mem2 field, and prints the result. help [ command ] help Print a short message explaining command. If no argument is given, display a synopsis of all dbx commands. source filename Read dbx commands from the giv en filename. This is especially useful fsun microsystems Revision A of 6 March 1990 Chapter 4 — dbx 29 Note \All FPA instructions are disassembled by the off option, not just those used in conjunction with the fpaasm subcommand. when that file was created by redirecting a status command from an ear- lier debugging session. quit Exit dbx. dbxenv Set dbx attributes. The dbxenv command with no argument prints the attributes and their current values. dbxenv case sensitive | insensitive The keyword case controls whether upper and lowercase letters are con- sidered different. The default is sensitive; insensitive is most use- ful for debugging FORTRAN programs. dbxenv fpaasm on | off Controls the disassembly of FPA instructions. If you specify off with the dbxenv fpaasm command, FPA instructions are disassembled as move instructions. If you specify on, FPA instructions are disassembled by means of FPA assembler mnemonics. On a machine with an FPA, fpaasm is on by default. On machines without FPA, fpaasm is off by default. dbxenv fpabase a[ 0-7] I off Designates an MC68020 address register for FPA instructions that use base- plus-short-displacement addressing to address the FPA. If the value is on, long move instructions that use the designated address register in base-plus-short-displacement mode are assumed to address the FPA, and are disassembled using FPA assembler mnemonics. If the value is off, all based-mode FPA instructions are disassembled and single-stepped as move instructions. The default value of fpabase is off. dbxenv makeargs args The keyword makeargs defines which arguments will be passed to make when it is invoked from dbx. dbxenv speed seconds The keyword speed determines the interval between execution of source statements during tracing (default 0.5 seconds). dbxenv stringlen num The keyword stringlen controls the maximum number of characters printed for a char * variable in a C program (default 512). debug [ objfile [ corefile / process-id ] ] Terminate debugging of the current program (if any), and begin debugging the one found in objfile with the given corefile or live process, without incur- ring the overhead of reinitializing dbx. If no arguments are specified, the name of the program currently being debugged and its arguments are printed. You must have both the objfile and corefile or live process available to perform debugging. #sun microsystems Revision A of 6 March 1990 30 Debugging Tools kill Terminate debugging of the current process and kill the process, but leave dbx ready to debug another. This can eliminate remains of a window pro- gram you were debugging without exiting the debugger, or allow the object file to be removed and remade without incurring a “text file busy” error mes- sage. modules Used to debug large programs. For more information see "Debugging Large Programs ," below. detach Detach a process from dbx and let it continue to execute. The process is no longer under the control of dbx. setenv name string Set the environment variable name to the value of string. (See csh(l)). 4.12. Debugging Large The modules command within dbx helps you debug very large programs by Programs selecting what parts of the available debugging information you want to use the next time dbx reads in the object file. NOTE To debug programs with the modules command, you must include main ( ) . The modules command controls and displays the amount of source level debugging information available to dbx. Usage: modules modules SELECT [ ALL I objname ] [ objname ].. modules APPEND [ objname ] [ objname ].. modules with no arguments displays the set of object files for which source level debugging information is currently available to the debugger, including the pathnames of any associated source files. If the debugger cannot access a source file for which it has debugging information, its name is followed by ‘ ( ? ) ’. Example: r ( dbx ) debug a . out (dbx) modules object file (a. out) source files a . o ../src/a.c ../src/a.y b. o . . / src/b. c (dbx) V Source file pathnames reflect the current search path as set by USE commands or the -I option. The modules command followed by the keyword SELECT sets or displays the modules selection list. This list is used to control whether the debugger reads source level debugging information for a particular object file. You can use this microsystems Revision A of 6 March 1990 Chapter 4 — dbx 3 1 to control the size of the dbx internal symbol tables when debugging large programs. If the modules selection list is set and a particular object file of the executable file is not included in the list, the debugger will ignore debugging information for that file. The effect is the same as if the file had not been compiled with the -g flag. Set the modules selection list to include specified object files with this command. ' modules SELECT objname [ objname ] ... 1 Display the current list with the command. modules SELECT *\ 7 Before reading debugging information for a particular object file, the debugger checks whether the modules selection list is set. If it is set, the debugger compares the name of the object file against the modules selection list. If the name appears, its debugging information is read, otherwise it is ignored. Disable the selection list with this command. f \ modules SELECT ALL v 7 Once you set a modules selection list, all subsequent DEBUG commands will interrogate it. Change the list with additional ( modules SELECT objname [ objname ] ... V commands. #sun microsystems Revision A of 6 March 1990 32 Debugging Tools Running Out of Swap Space with Large Files Example: / v demo% dbx (dbx) debug a. out Reading symbolic information... Read 1600 symbols (dbx) modules object file (a. out) source files a. o ../src/a.c ../src/a.y b. o . ./src/b.c (dbx) modules select b.o (dbx) debug a. out Reading symbolic information. . . Read 1600 symbols (1 of 2 files selected) (dbx) modules object file (a. out) source files b.o . . /src/b.c (dbx) J Add the named files to the modules selection list with this command. ' modules APPEND objname [ objname ] ... \ V J If the modules selection list includes any object files which do not appear in the executable being debugged, dbx prints a warning. The set of object files read from an executable file may be larger than the set specified in the modules select list. To compress debugging symbols, the loader eliminates any debugging information which is redundantly defined in multiple include files (see symbol type N_EXCL in ). If some symbols of an object file were excluded, the object file(s) where those symbols were first defined must also be read. Object files which were not selected but which were implied in this way are flagged by ‘ ( * ) ’ in the output from the modules command. If you debug large programs and do not use the modules command, you may run out of swap space. If so, address the problem by doing one of the following things: □ Increase the limit for the stacksize by inserting the line “limit stacksize 8 megabytes” into your . cshrc file. If8isn’t enough, you may need 16, or even 32. But don’t over do it. Start with 8. □ Make a bigger swap file. For help see the mkf ile(8) and swapon(8) man pages. Example: Login as superuser, use the command pstat-s to verify your swap space usage, make the file, and tell the system to use it, as shown in the example on the following page. #sun microsystems Revision A of 6 March 1990 Chapter 4 — dbx 33 4.13. Debugging Child Processes Do not press I Return I yet. f ; > — n demo# pstat -s 6584k allocated + 512k reserved = 7096k used, 22136k available demo# xnkfile -nv 20m /home /swapf ile /home/swapf ile 20971520 bytes demo# /usr/etc/swapon /home/ swapf ile k l You may find that debugging programs with dbx or dbxtool is difficult when the program does a fork ( ) and thereby creates child processes. Debugging can be done, but it does not fit into dbx nicely. You will have to change the source code during debugging. Use the steps below and either dbx or dbxtool to debug programs that create child processes. 1 . Insert asleep(20) or a similar call in the child process path of the code which was started by the fork () . This delays the child code execution. There are many alternatives that can be used. You could also use get char ( ) or an infinite loop that can be broken by the dbx command set. 2. On SunOS releases prior to 4.0, link with the -N flag. This ensures that after the fork (), the child and parent processes have their own copies of the text segment for the process, rather than sharing the segment. Beginning with SunOS 4.0, this flag is not necessary due to the copy-on-write capability provided by the virtual memory subsystem. 3. Start dbx on the parent process. Put a break point in the parent process code as needed. Be sure to put a break in the execution path of the parent process right after the fork ( ) point, in order to obtain the child process PID. Do not put any breakpoints in the child process at this point. 4. Start another copy of dbx, or dbxtool, and enter the first part of a command as shown below. , > demo % dbx executable Jilename 5. Start parent process code execution in the first dbx. Obtain the child process PID number after reaching the breakpoint set in step 3 above. We will use “1234” as the PID in this example. 6. Now complete the command as shown below. f demo% dbx executable Jilename 1234 Reading symbolic information. . . V This command starts a second dbx process to debug the child process suspended earlier by the sleep (2 0) or functional! y-equivalent command m microsystems Revision A of 6 March 1990 34 Debugging Tools or loop. A step command now allows you to debug the child process 20 seconds after the fork ( ) call. 7. You may want to trace one of the exec ( ) calls executed by most child processes. The PID remains the same, but the executable image changes. A sleep (20) command in the process which was started by exec ( ) will slow it down so that a dbx can attach to it. Use the following commands from the dbx of the child process in this case. Note that the child process will now execute at full speed. You can now see how useful it is to alter the child process code by adding a sleep ( ) or similar command to trace both fork ( ) and exec ( ) calls. 8. The dbx for the child process should do a detach if it wishes to allow the child process to continue executing with no interference from the debugger. Alternately, a kill command should be used to terminate the process. If neither of these commands is used and a dbx quit command is used, the child process will be left in a suspended state. demo% dbx a. out Reading symbolic information Read 42 symbols (dbx) list 1,15 1 #include 2 main() pid = fork ( ) ; printf ("pid is switch (pid) (dbx) stop at 14 (2) stop at "child. c":15 ( dbx ) run Running: a. out pid is 0 pid is 1537 stopped in main at line 15 in file "child. c (dbx) • sun microsystems Revision A of 6 March 1990 Chapter 4 — dbx 35 In another commandtool or shelltool use the pid and read in the child process as shown in the following example (1537 is the pid of the sample process): demo% dbx a. out 1537 Reading symbolic information. . . Read 42 symbols (dbx) list 13 sleep (20); 14 } 15 } 16 (dbx) v > 4.14. dbx FPA Support 1. The f pa asm debugger variable controls disassembly of FPA instructions. This variable may be set or displayed by means of the dbxenv command. The syntax of the command is: . >. dbxenv fpaasm V j If the value of fpaasm is off, all FPA instructions are disassembled as move instructions. If the value is on, FPA instructions are disassembled with FPA assembler mnemonics. Defaults: on a machine with an FPA, fpaasm is initially set to on; on machines without an FPA, it is initially set to off. 2. The fpabase debugger variable designates a 68020 address register for FPA instructions that use base-plus-short-displacement addressing to address the FPA. The syntax is: * -N. dbxenv fpabase V , If FPA disassembly is disabled (if fpaasm is off), its value is ignored. Otherwise, its value is interpreted as follows: value in [a0 . . a7]: Long move instructions that use the designated address register in base- plus-short-displacement mode are assumed to address the FPA, and are disassembled using FPA assembler mnemonics. Note that this is independent of the actual run-time value of the register. value = off: All based-mode FPA instructions are disassembled and single-stepped as move instructions. The default value of fpabase is of f , which designates no FPA base regis- ter. \r microsystems Revision A of 6 March 1990 36 Debugging Tools 4.15. Example of FPA Disassembly Consider the following simple FORTRAN program: Assume that this program has been compiled with the -g option into the file example. On a Sun-3 with an FPA, we could disassemble the function f as shown below. Note that the FORTRAN intrinsic ATAN is directly supported by the FPA instruction set and the FORTRAN compiler. % dbx a . out (dbx) stop in f (1) stop in f (dbx) run Running: a . out stopped in f at 5 (dbx) &$pc/8i f +0x12 f +0x1 6 f+Oxlc f+0x2 0 f +0x2 6 f +0x2e f+0x36 f+0x4 0 line 5 in file "example. f" f = atan(x/y) movl fpmoves movl fprdivs fpmoves fpmoves fpatans fpmoves a6@ (Oxc) , aO a0@, fpaO a6@ (0x8) , aO a0@ , fpaO fpaO, a6@ (-Oxc) a6@ (-Oxc) , fpal fpal, fpal fpal, a6@ (-0x8) FPA disassembly can be disabled by setting the debugger variable f paasm to off. This causes dbx to disassemble FPA instructions as long moves to addresses on the FPA page: ( (dbx) dbxenv f paasm off (dbx) &f+0xl2/10i f+0xl2 movl a6@ (Oxc) , aO f+0xl6 movl a0@, OxeOOOOcOO : 1 f+Oxlc movl a6@ (0x8) , aO f+0x2 0 movl a0@, 0xe0000600 : 1 f+0x2 6 movl OxeOOOOeOO :l,a6@ (-Oxc) f+0x2e movl a6@ (-Oxc) , 0xe0000c08 : 1 f +0x36 movl #0x41, 0xe0000818 :1 f +0x4 0 v movl 0xe0000e08 : 1, a6@ (-0x8) #sun ^ microsystems Revision A of 6 March 1990 Chapter 4 — dbx 37 When tracing a more complex program, one may occasionally want to step into a routine that has been compiled with optimization on. In such routines, it is often the case that the compiled code addresses the FPA page by using base+short offset addressing. Such code can be difficult to recognize unless it is known ahead of time that a particular address register is being used to address the FPA. This situation can be identified by the presence of an instruction that loads the address of the FPA page (OxeOOOOOOO) into an address register before doing any floating-point arithmetic. For example, here is a disassembly of the beginning of an optimized FORTRAN routine compiled with the -0 and -f fpa options: f A (dbx) fiddot_ _/7i ddot : link a6, #-0x2a0 ddot +0x4: moveml #, sp@ ddot +0x8: lea e0000000:l, a2 ddot +0xe: movl a2@ (0xe2 0) ,a6@ (-0x278) ddot_+0xl4 : movl a2@ (0xe24) ,a6@ (-0x274) ddot_+0xla : movl a2@ ( 0xe2 8 ) ,a6@ (-0x270) ddot_+0x20 : movl a2@ (0xe2c) ,a6@ (-0x26c) V . . J dbx does not know which register (if any) is being used to address the FPA in a given sequence of machine code. However, you may set the dbxenv variable fpabase to designate an MC68020 address register as an FPA base register. In this example, we note that the compiler has loaded the address of the FPA page into register a2, and so we designate a2 as the FPA base register to obtain the following: (dbx) dbxenv fpabase a2 (dbx) fiddot_/7i ddot_: link a6,#-Ox2aO ddot_+0x4: moveml #, sp@ ddot_+0x8: lea eOOOOOOO :l,a2 ddot_+Oxe: fpmoved@2 fpa4 , a6@ (-0x278 ) ddot_+0xla: fpmoved@2 fpa5, a6@ (-0x270) ddot_+0x26: fpmoved@2 204ce:l,fpa5 ddot_+0x36: fpmoved@2 204ce:l,fpa4 4.16. Examples of FPA FPA data registers can be displayed using a syntax similar to that used for the Register Use MC6888 1 co-processor registers. Note that unlike the MC6888 1 registers, FPA registers may contain either single-precision (32-bit) or double-precision (64-bit) values; MC6888 1 registers always contain an extended-precision (96-bit) value. For example, if f paO contains the single-precision value 2.718282, we may display it as follows: r (dbx) &$fpa0/f fpaO V 0x4 02df 855 +2 . 71 82 82e+00 -/ microsystems Revision A of 6 March 1990 Note that the value is displayed in hexadecimal as well as in floating- point nota- tion. A double-precision value may be displayed using the /F format. For example, if fpaO contains the double-precision value 2.718281828, we may display it as follows: ( \ (dbx) &$fpaO/F fpaO 0x4005bf Oa 0x8b04919b +2 . 71828182800000e+00 V / Note that it is important to use the correct display format; attempting to display a double-precision value in single precision (and vice versa) will usually produce meaningless results. FPA registers can also be used in set commands and in arithmetic expressions. Since dbx cannot tell whether the value in an FPA register is single or double precision, dbx provides two sets of names to refer to FPA registers. The names {$fpaO. .$fpa31} always cause the contents of the register to be interpreted as a double-precision value; the names { $fpaOs . . $fpa31s } cause interpre- tation as a single-precision value. Thus, the commands N (dbx) set $fpaOs =1.0 (dbx) set $fpa0 =1.0 v. , cause different bit patterns to be stored in fpaO. microsystems Revision A of 6 March 1990 5 Debugging Tips for Programmers This chapter provides a number of debugging tips. Primarily, the examples presented here are in the FORTRAN language. However, with some minor changes and modifications, the sample program and the examples in this chapter may also be of use to C language programmers. NOTE FORTRAN arrays can be specified using either parentheses () or brackets []. dbx can take both. Sample program The following sample program (with bug) is used in several examples: a3 . £ #sun microsystems 39 Revision A of 6 March 1990 40 Debugging Tools 5.1. dbx and FORTRAN Note the following when using dbx with FORTRAN programs: 1) The main routine is referenced as MAIN (as distinguished from main). All other names in the source file that have upper case letters in them will be lower case in dbx, unless the program was compiled with f 7 7 -U. 2) When referring to the value of a logical type in an expression, use the value 0 or 1 rather than . false . or . true . , respectively. 5.2. A Sample dbx Session A few dbx commands are shown here in examples, using the sample program at the start of this chapter. Throughout a debugging session, dbx defines a procedure and a source file as current. Requests to set breakpoints and to print or set variables are interpreted relative to the current function and file. Thus, “stop at 5” sets one of three different breakpoints depending on whether the current file is al . f , a 2 . f , or a3.f. compile To use dbx or dbxtool, you must compile and load your program with the -g flag. For example: run To run the program under the control of dbx, change to the directory where the sources and programs reside, then type the dbx command and the name of the executable file: quit The -g and -0 options are incompatible. If used together, the -g option cancels the -O option. Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers To quit dbx, enter the command quit To set a breakpoint before the first executable statement, wait for the (dbx) prompt, then type “stop in MAIN”. (dbx) stop in MAIN (2) stop in MAIN (dbx) After the (dbx) prompt appears, type run to begin execution. When the break- point is reached, dbx displays a message showing where it stopped, in this case at line 3 of file al . f . ( dbx ) run Running: silly stopped in MAIN at line 3 in file "al.f" 3 call mkidentity( twobytwo (dbx) print The command “print n” displays 2, since dbx knows about parameters, (dbx) print n (dbx) The command “print twobytwo” displays the entire matrix, one element per line. Note that dbx displays square brackets (not parentheses) when it references array elements. (dbx) print twobytwo twobytwo = [1,1] [ 2 , 1 ] - 1.0 [ 1 , 2 ] - 1.0 [ 2 , 2 ] - 1.0 (dbx) The command “print array” fails because mkidentity is not active at this point. (dbx) print array "array" is not active (dbx) #sun microsystems Revision A of 6 March 1990 42 Debugging Tools Calling a Function Structures and Pointers next The command next advances execution to line 4, and if the command “print twobytwo” is now repeated, it displays the unit matrix. (dbx) next stopped in MAIN at line 4 in file "al.f" 4 print *, determinant! twobytwo ) (dbx) print twobytwo twobytwo = [1,1] 1.0 [ 2 , 1 ] 0.0 [ 1 , 2 ] 0.0 [ 2 , 2 ] 1.0 (dbx) quit demo% v , It is possible to call a subroutine or function in the program at any point when execution has stopped. The effect is exactly as if the source had contained a call at that point. For example if, after the initial “stop in MAIN” described above, you typed “print determinant (twobytwo) ”, dbx displays the value 0.0, since mkidentity would not yet have modified twobytwo. r — X demo% dbx silly Reading symbolic information. . . Read 283 symbols (dbx) stop in MAIN (2) stop in MAIN (dbx) print determinant (twobytwo) determinant (twobytwo) = 0.0 (dbx) V — , This facility is often useful for special-case printing. For example, in a program it might be meaningful to trace the row and column sums of different matrices. A subroutine called mat sum that does this could be compiled into a program and invoked by the user at appropriate breakpoints. The dbx debugger recognizes the Sun FORTRAN items such as structure, record, union, and pointer. The following examples show using dbx with these items. Asun microsystems Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers 43 Compile for dbx using the -g option, load it in dbx, and list it. demo% f77 -o debstr -g debl . f debl . f : MAIN: demo% dbx debstr Reading symbolic information... Read 269 symbols (dbx) list 1,30 1 * debl.f: Show dbx with structures and pointers 2 STRUCTURE /PRODUCT/ 3 INTEGER* 4 ID 4 CHARACTER* 16 NAME 5 CHARACTER* 8 MODEL 6 REAL* 4 COST 7 REAL* 4 PRICE 8 END STRUCTURE RECORD /PRODUCT/ PROD1, PROD 2 POINTER (PRIOR, PRODl ) , (CURR, PROD2 ) 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (dbx) PRIOR = MALLOC ( 36 ) PRODl. ID =82 PRODl. NAME = "Schlepper" PRODl. MODEL = "XL" PRODl .COST =24.0 PRODl. PRICE = 104.0 CURR = MALLOC ( 36 ) PROD 2 = PRODl WRITE ( *, * ) PROD2 . NAME STOP END Set a breakpoint at a specific line number, and run it under dbx. ©sun microsystems Revision A of 6 March 1990 44 Debugging Tools Print and inquire about a record. r (dbx) print prodl A *prodl = ( id = 82 name — "Schlepper " ) (dbx) model = cost = 24.0 price = 104.0 "XL whatis prodl (based variable) structure /product/ prodl (dbx) V - J If you tell dbx to print a record, it displays all fields of the record, including field names. Print a pointer, then quit dbx. If you tell it to print a pointer, it displays the contents of that pointer, which is the address of the variable pointed to. This address could very well be different with every run. Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers 45 Parameters Uppercase The dbx debugger recognizes parameters — the compiler generates pseudo variables for parameters when programs are compiled for dbx with the -g option. The following examples show using dbx with parameters. Compile for dbx using the -g option, load it in dbx and list it. Print some parameters. demo% f77 -o silly -g deb2.f a2.f a3.f deb2 . f : deb2 . f : MAIN silly: a2 . f : a2 . f : mkidentity : a3 . f : a3.f : determinant : Linking: demo% dbx silly Reading symbolic information. . . Read 269 symbols (dbx) list 1,30 1 program silly 2 parameter ( n=2, nn=n*n ) 3 real twobytwo (n, n) 4 data twobytwo /nn *-l / 5 call mkidentity ( twobytwo, n ) 6 print *, determinant (twobytwo) 7 end (dbx) print n 'deb2 'MAIN 'n = 2 (dbx) print nn nn = 4 (dbx) quit demo% If your program has uppercase letters in any identifiers, and you want dbxtool to recognize them, then you need to give dbxtool a specific command, as follows. Once you’ve done the above command, then when dbxtool finds and displays uppercase identifiers, you can select them and dbxtool can find them. Caveat: Once you’ve done the above command, then the command “stop in MAIN” does not work. f#sun T microsystems Revision A of 6 March 1990 46 Debugging Tools Parts of Large Arrays Printing portions of large arrays is often of interest to FORTRAN programmers. For example: ' > demo% dbx a. out Reading symbolic information. . . Read 314 symbols (dbx) list 1,25 1 2 3 4 5 20 6 10 7 8 (dbx) stop at 7 (1) stop at "temp.f":7 (dbx) run Running: a. out stopped in MAIN at line 7 in file "temp.f" 7 stop (dbx) &i(2,3)/12D 0x000214b0 : 23 33 43 53 0x000214c0 : 14 24 34 44 0x000214d0: 54 15 25 35 (dbx) integer *4 i (5, 5) do 10 j = 1,5 do 20 k = 1,5 i ( j, k) = (j * 10) + k continue continue stop end Note that the D in the last dbx command shown in the above example is the mode used to display a longword in decimal format. Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers 47 Passing Arguments to a Main To specify main program arguments correctly within dbx, place them on the Program run command of dbx, as follows: Note that the arguments are passed not on the dbx or dbxtool command line, nor on the debug command line. Where Exception Occurred You can find the source code line where a floating-point exception occurred by using the ieee_handler routine with either dbx or dbxtool. For example: do while ( i .le. m ) call getarg ( i, argv ) write( *, ' ( i2, lx, a ) ' i = i + 1 end do stop end demo % a. out first second last 1 first 2 second 3 last demo% dbx a. out Reading symbolic information. . . Read 292 symbols (dbx) run first second last Running: a. out first second last 1 first 2 second 3 last execution completed, exit code is 0 program exited with 0 (dbx) #sun microsystems Revision A of 6 March 1990 48 Debugging Tools Note the "catch FPE” dbx command. -> Print in Hex demo% cat divide . f external myhandler ieeer = ieee_handler ( ' set' r = 14.2 s = 0 . 0 print *,r/s stop end myhandler); integer function myhandler (sig, code integer sig, code, context (5) call abort () end demo% f77 -g -f 68881 divide. f divide . f : MAIN: myhandler : demo% dbx a. out Reading symbolic information. . . Read 233 symbols (dbx) catch FPE (dbx) run Running: a. out signal FPE (floating point exception) in MAIN at line 5 in file "divide. f 5 print *,r/s (dbx) quit demo% Although you cannot use the print command to display objects in hexadecimal, you can use the alias command with machine-level commands to achieve the same results. The following command creates a new command named mem which requires one argument: an object of type integer *4. It then displays that argument in hexadecimal. For comparison, the example below shows the same value displayed in decimal using the print command. The “1” is the number of words to print. (dbxtool) alias mem "print (void *) (dbxtool) mem i(2,4) (void *) i (2, 4] = 0x18 (dbxtool) print i(2,4) i [2 , 4 ) = 24 (dbxtool) quit demo% Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers 49 Using the following command, you can now set up a button in dbxtool so that the mouse could select the object. ' - — -> (dbxtool) button expand mem V. > 5.3. Using adb with FORTRAN compile revised al.f parameter ( n=2 ) real twobytwo (2 , 2 ) / 4 *-l / external hand i = ieee_handler ( 'set', 'all', hand ) call mk.identity( twobytwo, n ) print *, determinant ( twobytwo ) end integer function hand ( sig, code, context ) integer sig, code, context (5) call abort () end k , This section introduces the use of the adb low-level debugger with the FORTRAN language. The adb debugger can be used to provide a stack traceback at a lower level, adb can be used on any program regardless of whether or not it was compiled with the -g debugging flag. For more information on adb, see adb Tutorial, Chapter 6. The adb program does not display any prompt at all; it just waits for input; except if you enter only a f Return 1 . then it will display the prompt adb. With the same three files as in the first dbx example, if you compile and run, you get NaN (not a number). If you get an abort, you can get an adb low-level trace- back; so force an abort with an exception handler. microsystems Revision A of 6 March 1990 50 Debugging Tools Here is a compile and run, for a Sun-3, with 68881 floating point. demo% f 77 -f68881 -< al.f : al . f : MAIN: hand: a2.f : a2 . f : mkidentity : a3.f : a3.f : determinant Linking : demo% silly abort: called Abort (core dumped) demo% start You can start up adb and display a C backtrace as follows, demo% adb silly core core file = core -- program ' 'silly SIGIOT 6: abort $C _kill (?) DYNAMIC () + 6 _force_abort ( ) + lc _abort_() + 4a _hand_ ( ) +18 _hand_(?) _determinant_(0x20258) + 18 _MAIN_ ( ) + 6e _main (0x1 , Oxeff fd8c, Oxeff fd94 ) + 5a Interpretation (bottom up): □ The startup routine main, called the FORTRAN MAIN routine, □ which in turn called the function determinant, □ which in turn called the function hand, □ which in turn called the function abort. □ which in turn called the function force abort to halt execution. microsystems Revision A of 6 March 1990 Chapter 5 — Debugging Tips for Programmers 5 1 instructions Display, say, 10(hex) machine instructions and their addresses starting from the entry point determinant. f A determinant^ 10 ?ia _determinant : _determinant : linkw a6, #0 _determinant +4: addl OO 1 =#= _determinant_+Oxa : moveml #0, sp@ determinant +0xe: fmovemx , a6@ (-8:1) _determinant +0x18: movl a6@ (8) , aO _determinant_+Oxlc : movl a6@ (8) , al determinant +0x20: fmoves al@, fpO _determinant_+0x24 : fmuls a0@ (Oxc) , fpO _determinant +0x2a: movl a6@ (8) , aO _determinant +0x2e: fmoves a0@ (8) ,fpl determinant +0x34: movl a6@ (8) , aO _determinant_+0x38 : f divs a0@ (4) ,fpl _determinant_+0x3e : f subx fpl , fpO _determinant_+0x42 : fmoves fpO, a6@ (-8) determinant +0x48: nop _determinant_+0x4a : movl a6@ (-8) , dO _determinant +0x4e: _ > quit To quit adb, type $q or $Q or “D. For example: — -N $q demo% blank common Variables can be displayed in a variety of formats, but their addresses must be known. The addresses of some external variables arc easy to determine. For example, to print the first four bytes after the label BLNK , in a decimal format, do this. ( N BLNK „/D V which is equivalent to the dbx command “print n” if n is the first variable in blank common. The addresses of local variables are usually difficult to determine. microsystems Revision A of 6 March 1990 52 Debugging Tools unformatted files As another example, consider this program. f A write (4) 4 end V When executed, this program creates a file named fort . 4 which contains a single unformatted record. An unformatted record includes two count words containing the record length at the beginning and end of the record. You can examine this data file with adb as follows. / — — — 1 . — ; » demo% adb fort. 4 - < Then display the first three words of the data file (start at location 0, for 3 times, in decimal format). 0,3?D 0: 4 4 4 $q demo% A microsystems Revision A of 6 March 1990 6 6.1. A Quick Survey Starting adb adb Tutorial Available on most UNIX systems, adb is a debugger that permits you to examine core files resulting from aborted programs, display output in a variety of formats, patch files, and run programs with embedded breakpoints. This chapter provides examples of the most useful features of adb. The reader is expected to be fami- liar with basic SunOS commands, and with the C language. NOTE This chapter describes adb use on the Sun-3 and Sun-4 only. Chapter 7 describes adb use on the Sun386i. Start adb with a shell command of the form % adb [ objectfile ] [corefile] ] i ' I] where objectfile is an executable SunOS file and corefile is a core dump file. If the object file is named a . out, then the invocation is % adb V 2 : If you place object files into a named program file, then the invocation is f ■!• % adb program A The filename minus (-) means ignore the argument, as in: % adb - core A L — y This is for examining the core file without reference to an object file, adb pro- vides requests for examining locations in either file: ? examines the contents of objectfile, while / examines the contents of corefile. The general form of these requests is: r A address ? format v or r A address / format V microsystems 53 Revision A of 6 March 1990 54 Debugging Tools Current Address Formats adb maintains a current address, called dot. When an address is entered, the current address is set to that location, so that displays 10 decimal numbers starting at dot. Dot ends up referring to the address of the last item displayed. When used with the ? or / requests, the current address can be advanced by typing newline; it can be decremented by typing ~ . Addresses are represented by expressions. Expressions are made up of decimal integers, octal integers, hexadecimal integers, and symbols from the program under test. These may be combined with the operators + (plus), - (minus), * (multiply), % (integer divide), & (bitwise and), | (bitwise inclusive or), # (round up to the next multiple), and " (not). All arithmetic within adb is 32 bits. When typing a symbolic address for a C program, you can type name. On a Sun-3 or Sun-4 you could alternatively type _name; adb recognizes both forms on these systems. To display data, specify a collection of letters and characters to describe the for- mat of the display. Formats are remembered, in the sense that typing a request without a format displays the new output in the previous format. Here are the most commonly used format letters: Revision A of 6 March 1990 Chapter 6 — adb Tutorial 55 Table 6-1 Some adb Format Letters Letter Description b one byte in octal B one byte in hex c one byte as a character o one 16-bit word in octal d one 16-bit word in decimal f one single-precision floating point value i MC68020 instructions on Sun-3, SPARC instruction on Sun-4. s a null-terminated character string a the value of dot u one 16-bit word as an unsigned integer n print a newline r print a blank space backup dot (not really a format) + advance dot (not really a format) Format letters are also available for long values: for example, D for long decimal, and F for double-precision floating point. Since integers are long words on the Sun-3 capital letters are used more often than not. General Command Meanings The general form of a command is: — [address [, count] ] command [ modifier ] which sets dot to address and executes command count times. The following table illustrates some general adb command meanings: Table 6-2 Some adb Commands Some adb Commands Command Meaning ? Print contents from object file / Print contents from core file = Print value of “dot” : Breakpoint control $ Miscellaneous requests / Request separator 1 Escape to shell Since adb catches signals, a user cannot use a quit signal to exit from adb. The request $q or $Q (or [ CTRL-D 1 1 must be used to exit from adb. Revision A of 6 March 1990 5 6 Debugging T ools If you use adb because you are accustomed to it, you will want to compile pro- grams with the -go option, to produce old-style symbol tables. This will make debugging proceed according to expectations. If you don’t compile programs with -go and the -0 option is set, the object code will be optimized, and may not so readily be understood as the same thing that was written in the source file. Debugging A Core Image Consider the C program below, which illustrates a common error made by C pro- grammers. The object of the program is to change the lower case t to an upper case T in the string pointed to by ch, and then write the character string to the file indicated by the first argument. The bug is that the character T is stored in the pointer cp instead of in the string pointed to by cp. Compile the program as follows: Executing the program produces a core dump caused by an illegal memory refer- ence. Now invoke adb by typing: Commonly the first debugging request given is 6.2. Debugging C Programs Revision A of 6 March 1990 Chapter 6 — adb Tutorial 57 which produces a C backtrace through the subroutines called. The output from adb tells us that only one function — main — was called, and the arguments argc and argv have the hexadecimal values 2 and f f f d7c, respectively. Both these values look reasonable — 2 indicates two arguments, and f f f d7c is the stack address of the parameter vector. The next request generates a C backtrace plus an interpretation of all the local variables in each function, and their values in hexadecimal. The value of the variable c looks incorrect since it is outside the ASCII range. The request r $r "N dO 54 f rame+24 dl 77 f rame+47 d2 2 manl d3 0 exp d4 0 exp d5 0 exp d6 0 exp 6.1 0 exp aO 54 f rame+24 al 0 exp a2 0 exp a3 f f fd7c a4 f f fd88 a5 0 exp a6 f f fd64 sp f f fd5c pc 8106 _main+92 ps 0 exp _main+92 : - ??? / displays the registers, including the program counter, and an interpretation of the instruction at that location. The request Revision A of 6 March 1990 58 Debugging Tools displays the values of all external variables. A map exists for each file handled by adb. The map for object files is referenced by ?, whereas the map for core files is referenced by /. Furthermore, a good rule of thumb is to use ? for instructions and / for data when looking at programs. To display information about maps, type: / $m A bl = 2000 el = bOOO fl = 800 b2 = 10000 e2 = 11000 f 2 = 3800 / map 'core' bl = 10000 el = 13000 fl = 1800 b2 = fffOOO v e2 = 1000000 f 2 = 4800 J This produces a report of the contents of the maps. More about these maps later. In our example, we might want to see the contents of the string pointed to by cp. We would want to see the string pointed to by cp in the core file: Because the pointer was set to ' T ' (hex 54) and then incremented, it now equals hex 55. On the Sun-3, there are no symbols below address 2000 (8000 on a Sun-2), so the data address 55 cannot be found. We could also display informa- tion about the arguments to a function. To get the decimal value of the arge argument to main, which is a long integer, type: To display the hex values of the three consecutive cells pointed to by argv in the function main, type: Note that these values are the addresses of the arguments to main. Therefore, #sun Xr microsystems Revision A of 6 March 1990 Chapter 6 — adb Tutorial 59 typing these hex values should yield the command-line arguments: fffdcO/s fffdcO: a . out Setting Breakpoints The request displays the current address (not its contents) in hex, which has been set to the address of the first argument. The current address, dot, is used by adb to remember its current location. It allows the user to reference locations relative to the current address. For example prints the first command-line argument. Set breakpoints in a program with the : b instruction, which has this form: f ' ” address : b [ request ] Consider the C program below, which changes tabs into blanks, and is adapted from Software Tools by Kemighan and Plauger, pp. 18-27. #include Idefine MAXLIN 80 Idefine YES 1 Idefine NO 0 Idefine TABSP 8 int tabs [MAXLIN] ; main ( ) { int *ptab, col, c; ptab = tabs; settab (ptab) ; /* set initial tab stops */ col = 1; while ( (c = getcharO) != EOF) { switch (c) { case ' \t' : while (tabpos(col) != YES) { putchar (' ' ) ; col++; } putchar ( ' ' ) ; col++; m sun microsystems Revision A of 6 March 1990 60 Debugging Tools break; case ' \n' : putchar (' \n' ) ; col = 1; break; default : putchar (c) ; col++; } } exit ( 0) ; } tabpos (col) /* return YES if col is a tab stop, NO if not */ int col; { if (col > MAXLIN) return (YES) ; else return (tabs [col] ) ; ) settab(tabp) /* set initial tab stops every TABSP spaces */ int *tabp; { int i ; for (i = 0; i <= MAXLIN; i++) (i % TABSP) ? (tabs [i] = NO) : (tabs[i] = YES); } v , Run the program under the control of adb, and then set four breakpoints as fol- lows: r % adb a. out - settabrb tabpos : b V / This sets breakpoints at the start of the two functions. Sun compilers generate statement labels only with the -g option, which is incompatible with adb. Therefore it is impossible to plant breakpoints at locations other than function entry points using adb. To display the location of breakpoints, type: f A $b breakpoints count bkpt command 1 _tabpos 1 _settab V J Asun microsystems Revision A of 6 March 1990 Chapter 6 — adb Tutorial 6 1 A breakpoint is bypassed count - 1 times before causing a stop. The command field indicates the adb requests to be executed each time the breakpoint is encountered. In this example no command fields are present. Display the instructions at the beginning of function sett ab ( ) in order to observe that the breakpoint is set after the link assembly instruction: settab, 5?ia _settab: _settab: link a6, #0 _settab: addl #-4,a7 _settab+a: moveml #<>, sp@ _settab+e : clrl a6@ (-4) _settab+12 : cmpl #50, a6@ (-4) _settab+la : V > This request displays five instructions starting at settab with the address of each location displayed. Another variation is / settab, 5?i _settab: _settab : link a6, #0 addl #-4,a7 moveml #<>, sp@ clrl a6@ (-4) cmpl #50, a6@ (-4) V ) which displays the instructions with only the starting address. Note that we accessed the addresses from a . out with the ? command. In general, when ask- ing for a display of multiple items, adb advances the current address the number of bytes necessary to satisfy the request; in the above example, five instructions were displayed and the current address was advanced 26 bytes. To run the program, type: To delete a breakpoint, for instance the entry to the function tabpos ( ) , type: Once the program has stopped, in this case at the breakpoint for settab ( ) , adb requests can be used to display the contents of memory. To display a stack trace, for example, type: r $C settab [8250] (10658) + 4 _main [8074] ( 1 , f f fd84 , f f fd8c) + la \ #sun microsystems Revision A of 6 March 1990 62 Debugging Tools And to display three lines of eight locations each from the array called tabs, type: / \ tabs, 3/8X tabs : tabs : 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 V y At this time (at location settab) the tabs array has not yet been initialized. If you just deleted the breakpoint at tabpos, put it back by typing: To continue execution of the program from the breakpoint type: You will need to give the a . out program a line of data, as in the figure above. Once you do, it will encounter a breakpoint at tabpos+4 and stop again. Examine the tabs array once more: now it is initialized, and has a one set in every eighth location: f A tabs, 3/8X _tabs : tabs : 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 v J You will have to type : c eight more times in order to get your line of output, since there is a breakpoint at every input character. Type I CTRL-D 1 to terminate the running process and to return to the command level of adb. Advanced Breakpoint Usage The quit and interrupt signals act on adb itself, rather than on the program being debugged. If such a signal occurs, then the program being debugged is stopped and control is returned to adb. The signal is saved by adb and passed on to the test program if you type: Now let’s reset the breakpoint at settab ( ) and display the instructions located there when we reach the breakpoint. This is accomplished by: microsystems Revision A of 6 March 1990 Chapter 6 — adb Tutorial 63 \ settab+4 :b settab, 5?ia : r settab: settab: link a6, #0 _settab+4 : addl #-4 , a7 settab+a: moveml #<>, sp@ settab+e: clrl a6@ (-4) _settab+12 : cmpl #50,a6@ (-4) settab+la : breakpoint _settab+4 : addl #-4,a7 It is possible to stop every two breakpoints, if you type , 2 before the breakpoint command. Variables can also be displayed at the breakpoint, as illustrated below. This shows that the local variable col changes from 1 to 2 before the occurrence of the breakpoint. NOTE Setting a breakpoint causes the value of dot to be changed. However, executing the program under adb does not change the value of dot. A breakpoint can be overwritten without first deleting the old breakpoint. For example: r settab+4 :b main.ptab/X; main.c/X : r f f f d68 : 10658 f f fd60 : 0 breakpoint _settab+4 : addl #-4, a7 V A semicolon is used to separate multiple adb requests on a single line. Other Breakpoint Facilities Arguments and redirection of standard input and output are passed to a program as follows. This request kills any existing program under test and starts the object file anew: : r argl arg2 ... outfile V , The program being debugged can be single stepped as follows. If necessary, this request starts up the program being debugged and stops after executing the first instruction: microsystems Revision A of 6 March 1990 64 Debugging Tools This request may also be used for skipping the first n breakpoints when continu- ing a program: The program being debugged runs as a separate process, and can be killed by: Revision A of 6 March 1990 Chapter 6 — adb Tutorial 65 6.3. File Maps SunOS supports several executable file formats. Executable type 407 is gen- erated by the cc (or Id) flag -N. Executable type 410 is generated by the flag -n. An executable type 413 is generated by the flag -z; the default is type 413. adb interprets these different file formats, and provides access to the different segments contained in them through a set of maps. To display the maps, type $m inside adb. 407 Executable Files In 407-format files, instructions and data are intermixed. This makes it impossi- ble for adb to differentiate data from instructions, but adb will display in either format. Furthermore, some displayed symbolic addresses look incorrect (for example, data addresses as offsets from routines). Here is a picture of 407- format files: Figure 6-1 Executable File Type 407 1 ? map 'object' bl = 2000 el = 8f28 fl = 20 b2 = 8000 e2 = 9560 f 2 = 20 / map 'core' bl = 8000 el = b800 fl = 1800 b2 = fffOOO e2 = 1000000 f2 = 5000 $v variables b = 0100000 d = 03070 e = 0407 m = 0407 s = 010000 t = 07450 < s Revision A of 6 March 1990 66 Debugging Tools 410 Executable Files In 410-format files (pure executable), instructions are separate from data. The ? command accesses the data part of the object file, telling adb to use the second part of the map in that file. Accessing data in the core file shows the data after it was modified by the execution of the program. Notice also that the data segment may have grown during program execution. Here is a picture of 410-format files: Figure 6-2 Executable File Type 410 $m ? map 'object' bl = 2000 el = 8f28 fl = 20 b2 = 10000 e2 = 10638 f 2 = f 48 / map 'core' bl = 10000 el = 12800 fl = 1800 b2 = fffOOO $v variables b = 0200000 d = 03070 e = 0410 m = 0410 s = 010000 t = 07450 e2 = 1000000 f 2 = 4000 microsystems Revision A of 6 March 1990 Chapter 6 — adb Tutorial 67 413 Executable Files object core Variables In 413-format flies (pure demand-paged executable) the instructions and data are also separate. However, in this case, since data is contained in separate pages, the base of the data segment is also relative to address zero. In this case, since the addresses overlap, it is necessary to use the ? * operator to access the data space of the object file. In both 410 and 413-format files the corresponding core file does not contain the program text. Here is a picture of 413-format files: Figure 6-3 Executable File Type 413 hdr text data hdr data stack The only difference between a 410 and a 413-format file is that 4 13-format seg- ments are rounded up to page boundaries. Here are the maps and variables for 413-format files: r > $m ? map 'abort' bl = 2000 el = 9000 fl = 800 b2 = 10000 e2 = 10800 f 2 = 1800 / map 'core' bl = 10000 el = 12800 fl = 1800 b2 = fffOOO e2 = 1000000 f 2 = 4000 $v variables b = 0200000 d = 04000 e = 0413 m = 0413 s = 010000 t = 010000 The b, e, and f fields are used to map addresses into file addresses. The f 1 field is the length of the header at the beginning of the file — 020 bytes for an object file and 02000 bytes for a core file. The f 2 field is the displacement from the beginning of the file to the data. For a 407-format file with mixed text and data, this is the same as the length of the header; for 410-format and 413-format files, this is the length of the header plus the size of the text portion. The b and e fields are the starting and ending locations for a segment. Given the address A, the location in the file (either object or core ) is calculated as: f \ blb v J which sets b to octal 2000. These variables are useful to know if the file under examination is an executable or core image file. The adb program reads the header of the core image file to find the values for these variables. If the second file specified does not seem to be a core file, or if it is missing, then the header of the executable file is used instead. One of the uses of adb is to examine object files without symbol tables since dbx cannot handle this kind of task. With adb, you can combine formatting requests to provide elaborate displays. Several examples are given below. The following adb command line displays four octal words followed by their ASCII interpretation from the data space of the core file: ■ — — — . Broken down, the various requests mean: / The bug is that the character T is stored in the pointer cp instead of in the string pointed to by cp. Compile the program as follows: _____ N % cc -go examplel . c % a. out junk Segmentation fault (core dumped) > > Executing the program produces a core dump because of an out-of-bounds memory reference. Now invoice adb by typing: r : - A % adb core file = core — program "a. out" memory fault V J Commonly the first debugging request given is \ $c main[8074] (2,fffd7c,fffd88) + 92 V — — ) which produces a C backtrace through the subroutines called. The output from adb tells us that only one function — main — was called, and the arguments argc and argv have the hexadecimal values 2 and f f f d7c respectively. Both these values look reasonable — 2 indicates two arguments, and f f f d7c equals the stack address of the parameter vector. The next request r \ $c main[8074] (2,fffd7c,fffd88) + 92 fp: 10468 c: 104 v J generates a C backtrace plus an interpretation of all the local variables in each function, and their values in hexadecimal. The value of the variable c looks incorrect since it is outside the ASCII range. The request microsystems Revision A of 6 March 1990 $r gs Oxfbf f 0000 ecx 0x28680 f s Oxfbf f 0000 eax 0x54 es Oxfcf f 0083 retaddr 0xfc06e38e cds 0x83 trapno Oxe edi 0x30890 err 0x4 esi 0x28680 eip 0x120b main+OxlOf ebp Oxfbf ffec8 cs 0x7b esp Oxfcf f 97e0 efl 0x10206 end+0x7202 ebx 0x2a0c0 uesp Oxfbf ffecO edx Oxfbf ffe6a ss 0x83 main+OxlOf: movb (%eax) , %al displays the registers, including the program counter, and an interpretation of the instruction at that location. The request — $e \ cp: 0x55 j _exit_nhandlers : 0x0 exit tnames : 0x35dc ctype : 0x20202000 smbuf : 0x65c0 _iob: 0x0 mallinfo : 0x0 root : 0x0 lbound: 0x0 ubound: 0x0 curbrk: 0x9004 errno : 0x0 environ: Oxfbf f fef 4 end: v. 0x0 — . displays the values of all external variables. A map exists for each file handled by adb. The map for a . out files is refer- enced by ? whereas the map for core files is referenced by /. Furthermore, a good rule of thumb is to use ? for instructions and / for data when looking at programs. To display information about maps, type: — $m bl = 8000 el = bOOO fl = 800 b2 = 10000 e2 = 11000 f 2 = 3800 / map 'core' bl = 10000 el = 13000 fl = 1800 b2 = fffOOO e2 = 1000000 f 2 = 4800 J This produces a report of the contents of the maps. More about these maps later. In our example, we might want to see the contents of the string pointed to by cp. We would want to see the string pointed to by cp in the core file: Revision A of 6 March 1990 78 Debugging Tools Setting Breakpoints c > *cp/s 55: data address not found < J Because the pointer was set to ' T ' (hex 54) and then incremented, it now equals hex 55. On the Sun386f, there is nothing mapped at this address, so the data at address 55 cannot be found. We could also display information about the argu- ments to a function. To get the decimal value of the argc argument to main, which is a long integer, type: • main. argc/D f f fd6c : 2 ■ To display the hex values of the three consecutive cells pointed to by argv in the function main, type: r \ *main . argv, 3/X f f fd7c : fffdcO f f fdc6 0 v J Note that these values are the addresses of the arguments to main. Therefore, typing these hex values should yield the command-line arguments: N fffdcO/s fffdcO : a . out V V The request: N V fffdcO J displays the current address (not its contents) in hex, which has been set to the address of the first argument. The current address, dot, is used by adb to remember its current location. It allows the user to reference locations relative to the current address. For example r . +6/s f f fdc6 : ZZZ V J prints the first command-line argument. You set breakpoints in a program with the : b instruction, which has this form: ^ address : b [ request ] Consider the C program below, which changes tabs into blanks, and is adapted from Software Tools by Kemighan and Plauger, pp. 18-27. microsystems Revision A of 6 March 1990 ♦include ♦define MAXLIN 80 ♦define YES 1 ♦define NO 0 ♦define TABSP 8 int tabs [MAXLIN] ; main ( ) { int *ptab, col, c; ptab = tabs; settab (ptab) ; /* set initial tab stops */ col = 1; while ( (c = getcharO) != EOF) { switch (c) { case ' \t' : while (tabpos(col) != YES) { putchar ( ' ' ) ; col++; } putchar ( ' ' ) ; col++; break; case ' \n' : putchar ( ' \n' ) ; col = 1; break; default : putchar (c) ; col++; ) } exit ( 0 ) ; } tabpos (col) /* return YES if col is a tab stop, NO if not */ int col; { if (col > MAXLIN) return (YES) ; else return (tabs [col] ) ; } settab (tabp) /* set initial tab stops every TABSP spaces */ int *tabp; { int i; for (i = 0; i <= MAXLIN; i++) (i % TABSP) ? (tabs [i] = NO) : b v. J which sets b to octal 2000. These variables are useful to know if the file under examination is an executable or core image file. The adb program reads the header of the core image file to find the values for these variables. If the second file specified does not seem to be a core file, or if it is missing, then the header of the executable file is used instead. One of the uses of adb is to examine object files without symbol tables; dbx cannot handle this kind of task. With adb, you can even combine formatting requests to provide elaborate displays. Several examples are given below. The following adb command line displays four octal words followed by their ASCII interpretation from the data space of the core file: r