A Tutorial Introduction to ADB J. F. Maranzano S. R. Bourne Bell Laboratories Murray Hill, New Jersey 07974 _A_B_S_T_R_A_C_T Debugging tools generally provide a wealth of information about the inner workings of programs. These tools have been available on UNIX* to allow users to examine ``core'' files that result from aborted programs. A new debugging program, ADB, provides enhanced capabilities to examine "core" and other program files in a variety of formats, run programs with embedded breakpoints and patch files. ADB is an indispensable but complex tool for debugging crashed systems and/or programs. This document provides an introduction to ADB with examples of its use. It explains the various for- matting options, techniques for debugging C pro- grams, examples of printing file system informa- tion and patching. _1. _I_n_t_r_o_d_u_c_t_i_o_n ADB is a new debugging program that is available on UNIX. It provides capabilities to look at ``core'' files resulting from aborted programs, print output in a variety of formats, patch files, and run programs with embedded breakpoints. This document provides examples of the more useful features of ADB. The reader is expected to be fami- liar with the basic commands on UNIX with the C language, and with References 1, 2 and 3. __________________________ * UNIX is a Trademark of Bell Laboratories. - 2 - _2. _A _Q_u_i_c_k _S_u_r_v_e_y _2._1. _I_n_v_o_c_a_t_i_o_n ADB is invoked as: 9 adb objfile corefile 9where _o_b_j_f_i_l_e is an executable UNIX file and _c_o_r_e_f_i_l_e is a core image file. Many times this will look like: 9 adb a.out core 9or more simply: 9 adb 9where the defaults are _a._o_u_t and _c_o_r_e respectively. The filename minus (-) means ignore this argument as in: 9 adb - core 9 ADB has requests for examining locations in either file. The ? request examines the contents of _o_b_j_f_i_l_e, the / request examines the _c_o_r_e_f_i_l_e. The general form of these requests is: 9 address ? format 9or 9 address / format 9 _2._2. _C_u_r_r_e_n_t _A_d_d_r_e_s_s ADB maintains a current address, called dot, similar in function to the current pointer in the UNIX editor. When an address is entered, the current address is set to that loca- tion, so that: 9 0126?i 9sets dot to octal 126 and prints the instruction at that address. The request: 9 .,10/d 9prints 10 decimal numbers starting at dot. Dot ends up referring to the address of the last item printed. 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 from decimal, octal, and hexadecimal integers, and symbols from the program under test. These may be com- bined with the operators +, -, *, % (integer division), & (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, - 3 - the user can type _n_a_m_e or __n_a_m_e; ADB will recognize both forms. _2._3. _F_o_r_m_a_t_s To print data, a user specifies a collection of letters and characters that describe the format of the printout. Formats are "remembered" in the sense that typing a request without one will cause the new printout to appear in the previous format. The following are the most commonly used format letters. 9 b one byte in octal c one byte as a character o one word in octal d one word in decimal f two words in floating point i PDP 11 instruction s a null terminated character string a the value of dot u one word as unsigned integer n print a newline r print a blank space ^ backup dot 9(Format letters are also available for "long" values, for example, `D' for long decimal, and `F' for double floating point.) For other formats see the ADB manual. _2._4. _G_e_n_e_r_a_l _R_e_q_u_e_s_t _M_e_a_n_i_n_g_s The general form of a request is: 9 address,count command modifier 9which sets `dot' to _a_d_d_r_e_s_s and executes the command _c_o_u_n_t times. The following table illustrates some general ADB com- mand meanings: 9 Command Meaning ? Print contents from _a._o_u_t file / Print contents from _c_o_r_e file = Print value of "dot" : Breakpoint control $ Miscellaneous requests ; Request separator ! Escape to shell 9 ADB catches signals, so a user cannot use a quit signal to exit from ADB. The request $q or $Q (or cntl-D) must be used to exit from ADB. - 4 - _3. _D_e_b_u_g_g_i_n_g _C _P_r_o_g_r_a_m_s _3._1. _D_e_b_u_g_g_i_n_g _A _C_o_r_e _I_m_a_g_e Consider the C program in Figure 1. The program is used to illustrate a common error made by C programmers. The object of the program is to change the lower case "t" to upper case in the string pointed to by _c_h_a_r_p and then write the character string to the file indicated by argument 1. The bug shown is that the character "T" is stored in the pointer _c_h_a_r_p instead of the string pointed to by _c_h_a_r_p. Executing the program produces a core file because of an out of bounds memory reference. ADB is invoked by: 9 adb a.out core 9The first debugging request: 9 $c 9is used to give a C backtrace through the subroutines called. As shown in Figure 2 only one function (_m_a_i_n) was called and the arguments _a_r_g_c and _a_r_g_v have octal values 02 and 0177762 respectively. Both of these values look reason- able; 02 = two arguments, 0177762 = address on stack of parameter vector. The next request: 9 $C 9is used to give a C backtrace plus an interpretation of all the local variables in each function and their values in octal. The value of the variable _c_c looks incorrect since _c_c was declared as a character. The next request: 9 $r 9prints out the registers including the program counter and an interpretation of the instruction at that location. The request: 9 $e 9prints out the values of all external variables. A map exists for each file handled by ADB. The map for the _a._o_u_t file is referenced by ? whereas the map for _c_o_r_e file is referenced by /. Furthermore, a good rule of thumb is to use ? for instructions and / for data when looking at programs. To print out information about the maps type: 9 $m 9This produces a report of the contents of the maps. More about these maps later. - 5 - In our example, it is useful to see the contents of the string pointed to by _c_h_a_r_p. This is done by: 9 *charp/s 9which says use _c_h_a_r_p as a pointer in the _c_o_r_e file and print the information as a character string. This printout clearly shows that the character buffer was incorrectly overwritten and helps identify the error. Printing the locations around _c_h_a_r_p shows that the buffer is unchanged but that the pointer is destroyed. Using ADB similarly, we could print information about the arguments to a function. The request: 9 main.argc/d 9prints the decimal _c_o_r_e image value of the argument _a_r_g_c in the function _m_a_i_n. The request: 9 *main.argv,3/o 9prints the octal values of the three consecutive cells pointed to by _a_r_g_v in the function _m_a_i_n. Note that these values are the addresses of the arguments to main. There- fore: 9 0177770/s 9prints the ASCII value of the first argument. Another way to print this value would have been 9 *"/s 9The " means ditto which remembers the last address typed, in this case _m_a_i_n._a_r_g_c ; the * instructs ADB to use the address field of the _c_o_r_e file as a pointer. The request: 9 .=o 9prints the current address (not its contents) in octal 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: 9 .-10/d 9 _3._2. _M_u_l_t_i_p_l_e _F_u_n_c_t_i_o_n_s Consider the C program illustrated in Figure 3. This program calls functions _f, _g, and _h until the stack is exhausted and a core image is produced. Again you can enter the debugger via: 9 adb 9which assumes the names _a._o_u_t and _c_o_r_e for the executable - 6 - file and core image file respectively. The request: 9 $c 9will fill a page of backtrace references to _f, _g, and _h. Figure 4 shows an abbreviated list (typing _D_E_L will ter- minate the output and bring you back to ADB request level). The request: 9 ,5$C 9prints the five most recent activations. Notice that each function (_f,_g,_h) has a counter of the number of times it was called. The request: 9 fcnt/d 9prints the decimal value of the counter for the function _f. Similarly _g_c_n_t and _h_c_n_t could be printed. To print the value of an automatic variable, for example the decimal value of _x in the last call of the function _h, type: 9 h.x/d 9It is currently not possible in the exported version to print stack frames other than the most recent activation of a function. Therefore, a user can print everything with $C or the occurrence of a variable in the most recent call of a function. It is possible with the $C request, however, to print the stack frame starting at some address as address$C. _3._3. _S_e_t_t_i_n_g _B_r_e_a_k_p_o_i_n_t_s Consider the C program in Figure 5. This program, which changes tabs into blanks, is adapted from _S_o_f_t_w_a_r_e _T_o_o_l_s by Kernighan and Plauger, pp. 18-27. We will run this program under the control of ADB (see Figure 6a) by: 9 adb a.out - 9Breakpoints are set in the program as: 9 address:b [request] 9The requests: 9 settab+4:b fopen+4:b getc+4:b tabpos+4:b 9set breakpoints at the start of these functions. C does not generate statement labels. Therefore it is currently not possible to plant breakpoints at locations other than func- tion entry points without a knowledge of the code generated - 7 - by the C compiler. The above addresses are entered as sym- bol+4 so that they will appear in any C backtrace since the first instruction of each function is a call to the C save routine (_c_s_v). Note that some of the functions are from the C library. To print the location of breakpoints one types: 9 $b 9The display indicates a _c_o_u_n_t field. A breakpoint is bypassed _c_o_u_n_t -_1 times before causing a stop. The _c_o_m_m_a_n_d field indicates the ADB requests to be executed each time the breakpoint is encountered. In our example no _c_o_m_m_a_n_d fields are present. By displaying the original instructions at the function _s_e_t_t_a_b we see that the breakpoint is set after the jsr to the C save routine. We can display the instructions using the ADB request: 9 settab,5?ia 9This request displays five instructions starting at _s_e_t_t_a_b with the addresses of each location displayed. Another variation is: 9 settab,5?i 9which displays the instructions with only the starting address. Notice that we accessed the addresses from the _a._o_u_t file with the ? command. In general when asking for a prin- tout of multiple items, ADB will advance 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 18 (decimal) bytes. To run the program one simply types: 9 :r 9To delete a breakpoint, for instance the entry to the func- tion _s_e_t_t_a_b, one types: 9 settab+4:d 9To continue execution of the program from the breakpoint type: 9 :c Once the program has stopped (in this case at the breakpoint for _f_o_p_e_n), ADB requests can be used to display the contents of memory. For example: 9 $C 9to display a stack trace, or: 9 - 8 - tabs,3/8o 9to print three lines of 8 locations each from the array called _t_a_b_s. By this time (at location _f_o_p_e_n) in the C pro- gram, _s_e_t_t_a_b has been called and should have set a one in every eighth location of _t_a_b_s. _3._4. _A_d_v_a_n_c_e_d _B_r_e_a_k_p_o_i_n_t _U_s_a_g_e We continue execution of the program with: 9 :c 9See Figure 6b. _G_e_t_c is called three times and the contents of the variable _c in the function _m_a_i_n are displayed each time. The single character on the left hand edge is the output from the C program. On the third occurrence of _g_e_t_c the program stops. We can look at the full buffer of char- acters by typing: 9 ibuf+6/20c 9When we continue the program with: 9 :c 9we hit our first breakpoint at _t_a_b_p_o_s since there is a tab following the "This" word of the data. Several breakpoints of _t_a_b_p_o_s will occur until the pro- gram has changed the tab into equivalent blanks. Since we feel that _t_a_b_p_o_s is working, we can remove the breakpoint at that location by: 9 tabpos+4:d 9If the program is continued with: 9 :c 9it resumes normal execution after ADB prints the message 9 a.out:running 9 The UNIX 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 con- trol is returned to ADB. The signal is saved by ADB and is passed on to the test program if: 9 :c 9is typed. This can be useful when testing interrupt han- dling routines. The signal is not passed on to the test program if: 9 :c 0 9is typed. Now let us reset the breakpoint at _s_e_t_t_a_b and display the instructions located there when we reach the breakpoint. 9 - 9 - This is accomplished by: 9 settab+4:b settab,5?ia * 9It is also possible to execute the ADB requests for each occurrence of the breakpoint but only stop after the third occurrence by typing: 9 getc+4,3:b main.c?C * 9This request will print the local variable _c in the function _m_a_i_n at each occurrence of the breakpoint. The semicolon is used to separate multiple ADB requests on a single line. Warning: setting a breakpoint causes the value of dot to be changed; executing the program under ADB does not change dot. Therefore: 9 settab+4:b .,5?ia fopen+4:b 9will print the last thing dot was set to (in the example _f_o_p_e_n+_4) _n_o_t the current location (_s_e_t_t_a_b+_4) at which the program is executing. A breakpoint can be overwritten without first deleting the old breakpoint. For example: 9 settab+4:b settab,5?ia; ptab/o * 9could be entered after typing the above requests. Now the display of breakpoints: 9 $b 9shows the above request for the _s_e_t_t_a_b breakpoint. When the breakpoint at _s_e_t_t_a_b is encountered the ADB requests are executed. Note that the location at _s_e_t_t_a_b+_4 has been changed to plant the breakpoint; all the other locations match their original value. Using the functions, _f, _g and _h shown in Figure 3, we can follow the execution of each function by planting non- stopping breakpoints. We call ADB with the executable pro- gram of Figure 3 as follows: 9 adb ex3 - 9Suppose we enter the following breakpoints: __________________________ * Owing to a bug in early versions of ADB (including the version distributed in Generic 3 UNIX) these state- ments must be written as: settab+4:b settab,5?ia;0 getc+4,3:b main.c?C;0 settab+4:b settab,5?ia; ptab/o;0 Note that ;0 will set dot to zero and stop at the breakpoint. - 10 - h+4:b hcnt/d; h.hi/; h.hr/ g+4:b gcnt/d; g.gi/; g.gr/ f+4:b fcnt/d; f.fi/; f.fr/ :r 9Each request line indicates that the variables are printed in decimal (by the specification d). Since the format is not changed, the d can be left off all but the first request. The output in Figure 7 illustrates two points. First, the ADB requests in the breakpoint line are not examined until the program under test is run. That means any errors in those ADB requests is not detected until run time. At the location of the error ADB stops running the program. The second point is the way ADB handles register vari- ables. ADB uses the symbol table to address variables. Register variables, like _f._f_r above, have pointers to unini- tialized places on the stack. Therefore the message "symbol not found". Another way of getting at the data in this example is to print the variables used in the call as: 9 f+4:b fcnt/d; f.a/; f.b/; f.fi/ g+4:b gcnt/d; g.p/; g.q/; g.gi/ :c 9The operator / was used instead of ? to read values from the _c_o_r_e file. The output for each function, as shown in Figure 7, has the same format. For the function _f, for example, it shows the name and value of the _e_x_t_e_r_n_a_l vari- able _f_c_n_t. It also shows the address on the stack and value of the variables _a, _b and _f_i. Notice that the addresses on the stack will continue to decrease until no address space is left for program execu- tion at which time (after many pages of output) the program under test aborts. A display with names would be produced by requests like the following: 9 f+4:b fcnt/d; f.a/"a="d; f.b/"b="d; f.fi/"fi="d 9In this format the quoted string is printed literally and the d produces a decimal display of the variables. The results are shown in Figure 7. _3._5. _O_t_h_e_r _B_r_e_a_k_p_o_i_n_t _F_a_c_i_l_i_t_i_e_s o+ Arguments and change of standard input and output are passed to a program as: 9 :r arg1 arg2 ... outfile 9 This request kills any existing program under test and starts the _a._o_u_t afresh. 9 - 11 - o+ The program being debugged can be single stepped by: 9 :s 9 If necessary, this request will start up the program being debugged and stop after executing the first instruction. o+ ADB allows a program to be entered at a specific address by typing: 9 address:r 9 o+ The count field can be used to skip the first _n break- points as: 9 ,n:r 9 The request: 9 ,n:c 9 may also be used for skipping the first _n breakpoints when continuing a program. o+ A program can be continued at an address different from the breakpoint by: 9 address:c 9 o+ The program being debugged runs as a separate process and can be killed by: 9 :k 9 _4. _M_a_p_s UNIX supports several executable file formats. These are used to tell the loader how to load the program file. File type 407 is the most common and is generated by a C compiler invocation such as cc pgm.c. A 410 file is pro- duced by a C compiler command of the form cc -n pgm.c, whereas a 411 file is produced by cc -i pgm.c. ADB inter- prets these different file formats and provides access to the different segments through a set of maps (see Figure 8). To print the maps type: 9 $m 9 In 407 files, both text (instructions) and data are intermixed. This makes it impossible for ADB to differen- tiate data from instructions and some of the printed sym- bolic addresses look incorrect; for example, printing data addresses as offsets from routines. - 12 - In 410 files (shared text), the instructions are separated from data and ?* accesses the data part of the _a._o_u_t file. The ?* request tells ADB to use the second part of the map in the _a._o_u_t file. Accessing data in the _c_o_r_e file shows the data after it was modified by the execu- tion of the program. Notice also that the data segment may have grown during program execution. In 411 files (separated I & D space), the instructions and data are also separated. However, in this case, since data is mapped through a separate set of segmentation regis- ters, 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 _a._o_u_t file. In both 410 and 411 files the corresponding core file does not contain the program text. Figure 9 shows the display of three maps for the same program linked as a 407, 410, 411 respectively. The b, e, and f fields are used by ADB to map addresses into file addresses. The "f1" field is the length of the header at the beginning of the file (020 bytes for an _a._o_u_t file and 02000 bytes for a _c_o_r_e file). The "f2" field is the dis- placement from the beginning of the file to the data. For a 407 file with mixed text and data this is the same as the length of the header; for 410 and 411 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 an address, A, the location in the file (either _a._o_u_t or _c_o_r_e) is calculated as: 9 b1<_A<_e1 => file address = (A-b1)+f1 b2<_A<_e2 => file address = (A-b2)+f2 9A user can access locations by using the ADB defined vari- ables. The $v request prints the variables initialized by ADB: 9 b base address of data segment d length of the data segment s length of the stack t length of the text m execution type (407,410,411) 9 In Figure 9 those variables not present are zero. Use can be made of these variables by expressions such as: 9 b 9that sets b to octal 2000. These variables are useful to know if the file under examination is an executable or _c_o_r_e - 13 - image file. ADB reads the header of the _c_o_r_e image file to find the values for these variables. If the second file specified does not seem to be a _c_o_r_e file, or if it is missing then the header of the executable file is used instead. _5. _A_d_v_a_n_c_e_d _U_s_a_g_e It is possible with ADB to combine formatting requests to provide elaborate displays. Below are several examples. _5._1. _F_o_r_m_a_t_t_e_d _d_u_m_p The line: 9 b ?m MAXLINE) return(YES); else return(tabs[col]); } 9 /* Settab - Set initial tab stops */ settab(tabp) int *tabp; { 9 - 24 - int i; 9 for(i = 0; i<= MAXLINE; i++) (i%TABSP) ? (tabs[i] = NO) : (tabs[i] = YES); } 9 - 25 - _F_i_g_u_r_e _6_a: _A_D_B _o_u_t_p_u_t _f_o_r _C _p_r_o_g_r_a_m _o_f _F_i_g_u_r_e _5 adb a.out - settab+4:b fopen+4:b getc+4:b tabpos+4:b $b breakpoints count bkpt command 1 ~tabpos+04 1 _getc+04 1 _fopen+04 1 ~settab+04 settab,5?ia ~settab: jsr r5,csv ~settab+04: tst -(sp) ~settab+06: clr 0177770(r5) ~settab+012: cmp $0120,0177770(r5) ~settab+020: blt ~settab+076 ~settab+022: settab,5?i ~settab: jsr r5,csv tst -(sp) clr 0177770(r5) cmp $0120,0177770(r5) blt ~settab+076 :r a.out: running breakpoint ~settab+04: tst -(sp) settab+4:d :c a.out: running breakpoint _fopen+04: mov 04(r5),nulstr+012 $C _fopen(02302,02472) ~main(01,0177770) col: 01 c: 0 ptab: 03500 tabs,3/8o 03500: 01 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 - 26 - _F_i_g_u_r_e _6_b: _A_D_B _o_u_t_p_u_t _f_o_r _C _p_r_o_g_r_a_m _o_f _F_i_g_u_r_e _5 :c a.out: running breakpoint _getc+04: mov 04(r5),r1 ibuf+6/20c __cleanu+0202: This is a test of :c a.out: running breakpoint ~tabpos+04: cmp $0120,04(r5) tabpos+4:d settab+4:b settab,5?ia settab+4:b settab,5?ia; 0 getc+4,3:b main.c?C; 0 settab+4:b settab,5?ia; ptab/o; 0 $b breakpoints count bkpt command 1 ~tabpos+04 3 _getc+04 main.c?C;0 1 _fopen+04 1 ~settab+04 settab,5?ia;ptab?o;0 ~settab: jsr r5,csv ~settab+04: bpt ~settab+06: clr 0177770(r5) ~settab+012: cmp $0120,0177770(r5) ~settab+020: blt ~settab+076 ~settab+022: 0177766: 0177770 0177744: @` T0177744: T h0177744: h i0177744: i s0177744: s - 27 - _F_i_g_u_r_e _7: _A_D_B _o_u_t_p_u_t _f_o_r _C _p_r_o_g_r_a_m _w_i_t_h _b_r_e_a_k_p_o_i_n_t_s 8 adb ex3 - 8 h+4:b hcnt/d; h.hi/; h.hr/ 8 g+4:b gcnt/d; g.gi/; g.gr/ 8 f+4:b fcnt/d; f.fi/; f.fr/ 8 :r 8 ex3: running 8 _fcnt: 0 8 0177732: 214 8 symbol not found 8 f+4:b fcnt/d; f.a/; f.b/; f.fi/ 8 g+4:b gcnt/d; g.p/; g.q/; g.gi/ 8 h+4:b hcnt/d; h.x/; h.y/; h.hi/ 8 :c 8 ex3: running 8 _fcnt: 0 8 0177746: 1 8 0177750: 1 8 0177732: 214 8 _gcnt: 0 8 0177726: 2 8 0177730: 3 8 0177712: 214 8 _hcnt: 0 8 0177706: 2 8 0177710: 1 8 0177672: 214 8 _fcnt: 1 8 0177666: 2 8 0177670: 3 8 0177652: 214 8 _gcnt: 1 8 0177646: 5 8 0177650: 8 8 0177632: 214 8 HIT DEL 8 f+4:b fcnt/d; f.a/"a = "d; f.b/"b = "d; f.fi/"fi = "d 8 g+4:b gcnt/d; g.p/"p = "d; g.q/"q = "d; g.gi/"gi = "d 8 h+4:b hcnt/d; h.x/"x = "d; h.y/"h = "d; h.hi/"hi = "d 8 :r 8 ex3: running 8 _fcnt: 0 8 0177746: a = 1 8 0177750: b = 1 8 0177732: fi = 214 8 _gcnt: 0 8 0177726: p = 2 8 0177730: q = 3 8 0177712: gi = 214 8 _hcnt: 0 8 0177706: x = 2 8 0177710: y = 1 8 0177672: hi = 214 8 _fcnt: 1 8 0177666: a = 2 8 0177670: b = 3 8 0177652: fi = 214 8 HIT DEL 8 $q 9 9 - 28 - _F_i_g_u_r_e _8: _A_D_B _a_d_d_r_e_s_s _m_a_p_s _4_0_7 _f_i_l_e_s a.out hdr text+data |____|_____________________________| 0 D core hdr text+data stack |______|_____________________________......|________| 0 D S E _4_1_0 _f_i_l_e_s (_s_h_a_r_e_d _t_e_x_t) a.out hdr text data |____|_____________________________|________________| 0 T B D core hdr data stack |______|________________......|________| B D S E _4_1_1 _f_i_l_e_s (_s_e_p_a_r_a_t_e_d _I _a_n_d _D _s_p_a_c_e) a.out hdr text data |____|_____________________________|________________| 0 T 0 D core hdr data stack |______|________________......|________| 0 D S E The following _a_d_b variables are set. 407 410 411 b base of data 0 B 0 d length of data D D-B D s length of stack S S S t length of text 0 T T - 29 - _F_i_g_u_r_e _9: _A_D_B _o_u_t_p_u_t _f_o_r _m_a_p_s adb map407 core407 $m text map `map407' b1 = 0 e1 = 0256 f1 = 020 b2 = 0 e2 = 0256 f2 = 020 data map `core407' b1 = 0 e1 = 0300 f1 = 02000 b2 = 0175400 e2 = 0200000 f2 = 02300 $v variables d = 0300 m = 0407 s = 02400 $q adb map410 core410 $m text map `map410' b1 = 0 e1 = 0200 f1 = 020 b2 = 020000 e2 = 020116 f2 = 0220 data map `core410' b1 = 020000 e1 = 020200 f1 = 02000 b2 = 0175400 e2 = 0200000 f2 = 02200 $v variables b = 020000 d = 0200 m = 0410 s = 02400 t = 0200 $q adb map411 core411 $m text map `map411' b1 = 0 e1 = 0200 f1 = 020 b2 = 0 e2 = 0116 f2 = 0220 data map `core411' b1 = 0 e1 = 0200 f1 = 02000 b2 = 0175400 e2 = 0200000 f2 = 02200 $v variables d = 0200 m = 0411 s = 02400 t = 0200 $q - 30 - _F_i_g_u_r_e _1_0: _S_i_m_p_l_e _C _p_r_o_g_r_a_m _f_o_r _i_l_l_u_s_t_r_a_t_i_n_g _f_o_r_m_a_t_t_i_n_g _a_n_d _p_a_t_c_h_i_n_g char str1[] "This is a character string"; int one 1; int number 456; long lnum 1234; float fpt 1.25; char str2[] "This is the second character string"; main() { one = 2; } - 31 - _F_i_g_u_r_e _1_1: _A_D_B _o_u_t_p_u_t _i_l_l_u_s_t_r_a_t_i_n_g _f_a_n_c_y _f_o_r_m_a_t_s adb map410 core410 b ?m_n_a_m_e assign dot to variable or register _n_a_m_e 9 - 35 - _F_o_r_m_a_t _S_u_m_m_a_r_y a the value of dot b one byte in octal c one byte as a character d one word in decimal f two words in floating point i PDP 11 instruction o one word in octal n print a newline r print a blank space s a null terminated character string _nt move to next _n space tab u one word as unsigned integer x hexadecimal Y date ^ backup dot "..." print string _E_x_p_r_e_s_s_i_o_n _S_u_m_m_a_r_y a) expression components decimal integere.g. 256 octal integere.g. 0277 hexadecimale.g. #ff symbols e.g. flag _main main.argc variables e.g.