761 lines
30 KiB
Plaintext
761 lines
30 KiB
Plaintext
====== A Tutorial Introduction to ADB ======
|
|
|
|
//J. F. Maranzano, S. R. Bourne//
|
|
//May 5, 1977//
|
|
|
|
===== 1. Introduction =====
|
|
|
|
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 familiar
|
|
with the basic commands on UNIX with the C language, and
|
|
with References 1, 2 and 3.
|
|
|
|
|
|
===== 2. A Quick Survey =====
|
|
|
|
==== 2.1. Invocation ====
|
|
|
|
ADB is invoked as:
|
|
**adb objfile corefile**
|
|
where ''objfile'' is an executable UNIX file and ''corefile'' is a
|
|
core image file. Many times this will look like:
|
|
**adb a.out core**
|
|
or more simply:
|
|
**adb**
|
|
where the defaults are ''a.out'' and ''core'' respectively. The
|
|
filename minus (-) means ignore this argument as in:
|
|
**adb - core**
|
|
|
|
ADB has requests for examining locations in either file.
|
|
The **?** request examines the contents of ''objfile'',
|
|
the **/** request examines the ''corefile''. The general form of these
|
|
requests is:
|
|
**address ? format**
|
|
or
|
|
**address / format**
|
|
|
|
==== 2.2. Current Address ====
|
|
|
|
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 location,
|
|
so that:
|
|
**0126?i**
|
|
sets dot to octal 126 and prints the instruction at that
|
|
address. The request:
|
|
**.,10/d**
|
|
prints 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 combined
|
|
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,
|
|
the user can type ''name'' or ''_name''; ADB will recognize both
|
|
forms.
|
|
|
|
==== 2.3. Formats ====
|
|
|
|
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.
|
|
|
|
|| 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 ||
|
|
|
|
(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. General Request Meanings ====
|
|
|
|
The general form of a request is:
|
|
**address,count command modifier**
|
|
which sets `dot' to ''address'' and executes the command ''count''
|
|
times.
|
|
|
|
The following table illustrates some general ADB command meanings:
|
|
|
|
^^ Command ^^ Meaning ^^
|
|
|| ? || Print contents from ''a.out'' file ||
|
|
|| / || Print contents from ''core'' file ||
|
|
|| = || Print value of "dot" ||
|
|
|| : || Breakpoint control ||
|
|
|| $ || Miscellaneous requests ||
|
|
|| ; || Request separator ||
|
|
|| ! || Escape to shell ||
|
|
|
|
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.
|
|
|
|
===== 3. Debugging C Programs =====
|
|
|
|
==== 3.1. Debugging A Core Image ====
|
|
|
|
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 ''charp'' 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 ''charp'' instead of the string pointed to by ''charp''.
|
|
Executing the program produces a core file because of an out
|
|
of bounds memory reference.
|
|
|
|
ADB is invoked by:
|
|
**adb a.out core**
|
|
The first debugging request:
|
|
**$c**
|
|
is used to give a C backtrace through the subroutines
|
|
called. As shown in Figure 2 only one function (''main'') was
|
|
called and the arguments ''argc'' and ''argv'' have octal values 02
|
|
and 0177762 respectively. Both of these values look reasonable;
|
|
02 = two arguments, 0177762 = address on stack of
|
|
parameter vector.
|
|
The next request:
|
|
**$C**
|
|
is 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 ''cc'' looks incorrect since
|
|
''cc'' was declared as a character.
|
|
|
|
The next request:
|
|
**$r**
|
|
prints out the registers including the program counter and
|
|
an interpretation of the instruction at that location.
|
|
|
|
The request:
|
|
**$e**
|
|
prints out the values of all external variables.
|
|
|
|
A map exists for each file handled by ADB. The map for
|
|
the ''a.out'' file is referenced by **?** whereas the map for ''core**
|
|
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:
|
|
**$m**
|
|
This produces a report of the contents of the maps. More
|
|
about these maps later.
|
|
|
|
In our example, it is useful to see the contents of the
|
|
string pointed to by ''charp.'' This is done by:
|
|
***charp/s**
|
|
which says use ''charp'' as a pointer in the ''core'' 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 ''charp'' 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:
|
|
**main.argc/d**
|
|
prints the decimal ''core'' image value of the argument ''argc'' in
|
|
the function //main.//
|
|
The request:
|
|
***main.argv,3/o**
|
|
prints the octal values of the three consecutive cells
|
|
pointed to by ''argv'' in the function ''main.'' Note that these
|
|
values are the addresses of the arguments to main. Therefore:
|
|
**0177770/s**
|
|
prints the ASCII value of the first argument. Another way
|
|
to print this value would have been
|
|
***"/s**
|
|
The " means ditto which remembers the last address typed, in
|
|
this case ''main.argc'' ; the ** * ** instructs ADB to use the address
|
|
field of the ''core'' file as a pointer.
|
|
|
|
The request:
|
|
**.=o**
|
|
prints 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:
|
|
**.-10/d**
|
|
|
|
==== 3.2. Multiple Functions ====
|
|
|
|
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:
|
|
**adb**
|
|
which assumes the names ''a.out'' and ''core'' for the executable
|
|
file and core image file respectively. The request:
|
|
**$c**
|
|
will fill a page of backtrace references to //f,'' ''g,'' and ''h.//
|
|
Figure 4 shows an abbreviated list (typing ''DEL'' will terminate
|
|
the output and bring you back to ADB request level).
|
|
|
|
The request:
|
|
**,5$C**
|
|
prints 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:
|
|
**fcnt/d**
|
|
prints the decimal value of the counter for the function //f.//
|
|
Similarly ''gcnt'' and ''hcnt'' 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:
|
|
**h.x/d**
|
|
It 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. Setting Breakpoints ====
|
|
|
|
Consider the C program in Figure 5. This program,
|
|
which changes tabs into blanks, is adapted from //Software//
|
|
''Tools'' by Kernighan and Plauger, pp. 18-27.
|
|
|
|
We will run this program under the control of ADB (see
|
|
Figure 6a) by:
|
|
**adb a.out -**
|
|
Breakpoints are set in the program as:
|
|
**address:b [request]**
|
|
The requests:
|
|
**settab+4:b**
|
|
**fopen+4:b**
|
|
**getc+4:b**
|
|
**tabpos+4:b**
|
|
set 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 function
|
|
entry points without a knowledge of the code generated
|
|
by the C compiler. The above addresses are entered as **symbol+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 (''csv''). Note that some of the functions are from the
|
|
C library.
|
|
|
|
To print the location of breakpoints one types:
|
|
**$b**
|
|
The display indicates a ''count'' field. 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 our example no //command//
|
|
fields are present.
|
|
|
|
By displaying the original instructions at the function
|
|
''settab'' we see that the breakpoint is set after the jsr to
|
|
the C save routine. We can display the instructions using
|
|
the ADB request:
|
|
**settab,5?ia**
|
|
This request displays five instructions starting at //settab//
|
|
with the addresses of each location displayed. Another
|
|
variation is:
|
|
**settab,5?i**
|
|
which displays the instructions with only the starting
|
|
address.
|
|
|
|
Notice that we accessed the addresses from the //a.out//
|
|
file with the **?** command. In general when asking for a
|
|
printout 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:
|
|
**:r**
|
|
To delete a breakpoint, for instance the entry to the function
|
|
''settab,'' one types:
|
|
**settab+4:d**
|
|
To continue execution of the program from the breakpoint
|
|
type:
|
|
**:c**
|
|
|
|
Once the program has stopped (in this case at the
|
|
breakpoint for ''fopen),'' ADB requests can be used to display
|
|
the contents of memory. For example:
|
|
**$C**
|
|
to display a stack trace, or:
|
|
**tabs,3/8o**
|
|
to print three lines of 8 locations each from the array
|
|
called ''tabs.'' By this time (at location ''fopen)'' in the C program,
|
|
''settab'' has been called and should have set a one in
|
|
every eighth location of //tabs.//
|
|
|
|
==== 3.4. Advanced Breakpoint Usage ====
|
|
|
|
We continue execution of the program with:
|
|
**:c**
|
|
See Figure 6b. ''Getc'' is called three times and the contents
|
|
of the variable ''c'' in the function ''main'' are displayed each
|
|
time. The single character on the left hand edge is the
|
|
output from the C program. On the third occurrence of //getc//
|
|
the program stops. We can look at the full buffer of
|
|
characters by typing:
|
|
**ibuf+6/20c**
|
|
When we continue the program with:
|
|
**:c**
|
|
we hit our first breakpoint at ''tabpos'' since there is a tab
|
|
following the "This" word of the data.
|
|
|
|
Several breakpoints of ''tabpos'' will occur until the program
|
|
has changed the tab into equivalent blanks. Since we
|
|
feel that ''tabpos'' is working, we can remove the breakpoint at
|
|
that location by:
|
|
**tabpos+4:d**
|
|
If the program is continued with:
|
|
**:c**
|
|
it resumes normal execution after ADB prints the message
|
|
**a.out:running**
|
|
|
|
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 control
|
|
is returned to ADB. The signal is saved by ADB and is
|
|
passed on to the test program if:
|
|
**:c**
|
|
is typed. This can be useful when testing interrupt handling
|
|
routines. The signal is not passed on to the test
|
|
program if:
|
|
**:c 0**
|
|
is typed.
|
|
|
|
Now let us reset the breakpoint at ''settab'' and display
|
|
the instructions located there when we reach the breakpoint.
|
|
This is accomplished by:
|
|
**settab+4:b settab,5?ia** (*
|
|
It is also possible to execute the ADB requests for each
|
|
occurrence of the breakpoint but only stop after the third
|
|
occurrence by typing:
|
|
**getc+4,3:b main.c?C** (*
|
|
This request will print the local variable ''c'' in the function
|
|
''main'' 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:
|
|
**settab+4:b .,5?ia**
|
|
-----------
|
|
(* Owing to a bug in early versions of ADB (including
|
|
the version distributed in Generic 3 UNIX)
|
|
these statements 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.
|
|
|
|
**fopen+4:b**
|
|
will print the last thing dot was set to (in the example
|
|
''fopen+4'') ''not'' the current location (''settab+4'') at which the
|
|
program is executing.
|
|
|
|
A breakpoint can be overwritten without first deleting
|
|
the old breakpoint. For example:
|
|
**settab+4:b settab,5?ia; ptab/o** (*
|
|
could be entered after typing the above requests.
|
|
|
|
Now the display of breakpoints:
|
|
**$b**
|
|
shows the above request for the ''settab'' breakpoint. When the
|
|
breakpoint at ''settab'' is encountered the ADB requests are
|
|
executed. Note that the location at ''settab+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 program
|
|
of Figure 3 as follows:
|
|
**adb ex3 -**
|
|
Suppose we enter the following breakpoints:
|
|
**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**
|
|
Each 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 variables.
|
|
ADB uses the symbol table to address variables.
|
|
Register variables, like ''f.fr'' above, have pointers to uninitialized
|
|
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:
|
|
**f+4:b fcnt/d; f.a/; f.b/; f.fi/**
|
|
**g+4:b gcnt/d; g.p/; g.q/; g.gi/**
|
|
**:c**
|
|
The operator / was used instead of ? to read values from
|
|
the ''core'' 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 //external//
|
|
variable ''fcnt.'' It also shows the address on the stack and
|
|
value of the variables //a,'' ''b'' and ''fi.//
|
|
|
|
Notice that the addresses on the stack will continue to
|
|
decrease until no address space is left for program execution
|
|
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:
|
|
**f+4:b fcnt/d; f.a/"a="d; f.b/"b="d; f.fi/"fi="d**
|
|
In 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. Other Breakpoint Facilities ====
|
|
|
|
(*) Arguments and change of standard input and output are
|
|
passed to a program as:
|
|
**:r arg1 arg2 ... <infile >outfile**
|
|
This request kills any existing program under test and
|
|
starts the ''a.out'' afresh.
|
|
|
|
(*) The program being debugged can be single stepped by:
|
|
**:s**
|
|
If necessary, this request will start up the program
|
|
being debugged and stop after executing the first
|
|
instruction.
|
|
|
|
(*) ADB allows a program to be entered at a specific address
|
|
by typing:
|
|
**address:r**
|
|
|
|
(*) The count field can be used to skip the first ''n'' breakpoints as:
|
|
**,n:r**
|
|
The request:
|
|
**,n:c**
|
|
may also be used for skipping the first ''n'' breakpoints
|
|
when continuing a program.
|
|
|
|
|
|
(*) A program can be continued at an address different from
|
|
the breakpoint by:
|
|
**address:c**
|
|
|
|
(*) The program being debugged runs as a separate process
|
|
and can be killed by:
|
|
**:k**
|
|
|
|
|
|
===== 4. Maps =====
|
|
|
|
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 produced
|
|
by a C compiler command of the form **cc -n pgm.c**,
|
|
whereas a 411 file is produced by **cc -i pgm.c**. ADB interprets
|
|
these different file formats and provides access to
|
|
the different segments through a set of maps (see Figure 8).
|
|
To print the maps type:
|
|
**$m**
|
|
|
|
In 407 files, both text (instructions) and data are
|
|
intermixed. This makes it impossible for ADB to differentiate
|
|
data from instructions and some of the printed symbolic
|
|
addresses look incorrect; for example, printing data
|
|
addresses as offsets from routines.
|
|
|
|
In 410 files (shared text), the instructions are separated
|
|
from data and **?* ** accesses the data part of the ''a.out**
|
|
file. The **?* ** request tells ADB to use the second part of
|
|
the map in the ''a.out'' 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.
|
|
|
|
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 registers,
|
|
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.out'' 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.out'' file and
|
|
02000 bytes for a ''core'' file). The "f2" field is the displacement
|
|
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.out'' or ''core'') is calculated as:
|
|
**b1<=A<=e1 => file address = (A-b1)+f1**
|
|
**b2<=A<=e2 => file address = (A-b2)+f2**
|
|
A user can access locations by using the ADB defined variables.
|
|
The **$v** request prints the variables initialized by
|
|
ADB:
|
|
|
|
|| 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) ||
|
|
|
|
In Figure 9 those variables not present are zero. Use
|
|
can be made of these variables by expressions such as:
|
|
**<b**
|
|
in the address field. Similarly the value of the variable
|
|
can be changed by an assignment request such as:
|
|
**02000>b**
|
|
that sets **b** to octal 2000. These variables are useful to
|
|
know if the file under examination is an executable or //core//
|
|
image file.
|
|
|
|
ADB 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.
|
|
|
|
|
|
===== 5. Advanced Usage =====
|
|
|
|
It is possible with ADB to combine formatting requests
|
|
to provide elaborate displays. Below are several examples.
|
|
|
|
==== 5.1. Formatted dump ====
|
|
|
|
The line:
|
|
**<b,-1/4o4^8Cn**
|
|
prints 4 octal words followed by their ASCII interpretation
|
|
from the data space of the core image file. Broken down,
|
|
the various request pieces mean:
|
|
|
|
|| <b || The base address of the data segment. ||
|
|
|| <b,-1 || Print from the base address to the end of file. A negative count is used here and elsewhere to loop indefinitely or until some error condition (like end of file) is detected. ||
|
|
|
|
The format **4o4^8Cn** is broken down as follows:
|
|
|
|
|| 4o || Print 4 octal locations. ||
|
|
|| 4^ || Backup the current address 4 locations (to the original start of the field). ||
|
|
|| 8C || Print 8 consecutive characters using an escape convention; each character in the range 0 to 037 is printed as @ followed by the corresponding character in the range 0140 to 0177. An @ is printed as @@. ||
|
|
|| n || Print a newline. ||
|
|
|
|
The request:
|
|
**<b,<d/4o4^8Cn**
|
|
could have been used instead to allow the printing to stop
|
|
at the end of the data segment (<d provides the data segment
|
|
size in bytes).
|
|
|
|
The formatting requests can be combined with ADB's
|
|
ability to read in a script to produce a core image dump
|
|
script. ADB is invoked as:
|
|
**adb a.out core < dump**
|
|
to read in a script file, ''dump,'' of requests. An example of
|
|
such a script is:
|
|
**120$w**
|
|
**4095$s**
|
|
**$v**
|
|
**=3n**
|
|
**$m**
|
|
**=3n"C Stack Backtrace"**
|
|
**$C**
|
|
**=3n"C External Variables"**
|
|
**$e**
|
|
**=3n"Registers"**
|
|
**$r**
|
|
**0$s**
|
|
**=3n"Data Segment"**
|
|
**<b,-1/8ona**
|
|
|
|
The request **120$w** sets the width of the output to 120
|
|
characters (normally, the width is 80 characters). ADB
|
|
attempts to print addresses as:
|
|
**symbol + offset**
|
|
The request **4095$s** increases the maximum permissible offset
|
|
to the nearest symbolic address from 255 (default) to 4095.
|
|
The request **=** can be used to print literal strings. Thus,
|
|
headings are provided in this ''dump'' program with requests of
|
|
the form:
|
|
**=3n"C Stack Backtrace"**
|
|
that spaces three lines and prints the literal string. The
|
|
request **$v** prints all non-zero ADB variables (see Figure 8).
|
|
The request **0$s** sets the maximum offset for symbol matches
|
|
to zero thus suppressing the printing of symbolic labels in
|
|
favor of octal values. Note that this is only done for the
|
|
printing of the data segment. The request:
|
|
**<b,-1/8ona**
|
|
prints a dump from the base of the data segment to the end
|
|
of file with an octal address field and eight octal numbers
|
|
per line.
|
|
|
|
Figure 11 shows the results of some formatting requests
|
|
on the C program of Figure 10.
|
|
|
|
==== 5.2. Directory Dump ====
|
|
|
|
As another illustration (Figure 12) consider a set of
|
|
requests to dump the contents of a directory (which is made
|
|
up of an integer ''inumber'' followed by a 14 character name):
|
|
**adb dir -**
|
|
**=n8t"Inum"8t"Name"**
|
|
**0,-1? u8t14cn**
|
|
In this example, the **u** prints the ''inumber'' as an unsigned
|
|
decimal integer, the **8t** means that ADB will space to the
|
|
next multiple of 8 on the output line, and the **14c** prints
|
|
the 14 character file name.
|
|
|
|
==== 5.3. Ilist Dump ====
|
|
|
|
Similarly the contents of the ''ilist'' of a file system,
|
|
(e.g. /dev/src, on UNIX systems distributed by the UNIX Support
|
|
Group; see UNIX Programmer's Manual Section V) could be
|
|
dumped with the following set of requests:
|
|
**adb /dev/src -**
|
|
**02000>b**
|
|
**?m <b**
|
|
**<b,-1?"flags"8ton"links,uid,gid"8t3bn",size"8tbrdn"addr"8t8un"times"8t2Y2na**
|
|
In this example the value of the base for the map was
|
|
changed to 02000 (by saying **?m<b**) since that is the start of
|
|
an ''ilist'' within a file system. An artifice (**brd** above) was
|
|
used to print the 24 bit size field as a byte, a space, and
|
|
a decimal integer. The last access time and last modify
|
|
time are printed with the **2Y** operator. Figure 12 shows portions
|
|
of these requests as applied to a directory and file
|
|
system.
|
|
|
|
==== 5.4. Converting values ====
|
|
|
|
ADB may be used to convert values from one representation
|
|
to another. For example:
|
|
**072 = odx**
|
|
will print
|
|
**072 58 #3a**
|
|
which is the octal, decimal and hexadecimal representations
|
|
of 072 (octal). The format is remembered so that typing
|
|
subsequent numbers will print them in the given formats.
|
|
Character values may be converted similarly, for example:
|
|
**'a' = co**
|
|
prints
|
|
**a 0141**
|
|
It may also be used to evaluate expressions but be warned
|
|
that all binary operators have the same precedence which is
|
|
lower than that for unary operators.
|
|
|
|
|
|
===== 6. Patching =====
|
|
|
|
Patching files with ADB is accomplished with the //write,// **w** or **W**,
|
|
request (which is not like the ''ed'' editor write
|
|
command). This is often used in conjunction with the
|
|
''locate,'' **l** or **L** request. In general, the request syntax
|
|
for **l** and **w** are similar as follows:
|
|
**?l value**
|
|
The request **l** is used to match on two bytes, **L** is used for
|
|
four bytes. The request **w** is used to write two bytes,
|
|
whereas **W** writes four bytes. The **value** field in either
|
|
''locate'' or ''write'' requests is an expression. Therefore, decimal
|
|
and octal numbers, or character strings are supported.
|
|
|
|
In order to modify a file, ADB must be called as:
|
|
**adb -w file1 file2**
|
|
When called with this option, ''file1'' and ''file2'' are created if
|
|
necessary and opened for both reading and writing.
|
|
|
|
For example, consider the C program shown in Figure 10.
|
|
We can change the word "This" to "The " in the executable
|
|
file for this program, ''ex7'', by using the following requests:
|
|
**adb -w ex7 -**
|
|
**?l 'Th'**
|
|
**?W 'The '**
|
|
The request **?l** starts at dot and stops at the first match of
|
|
"Th" having set dot to the address of the location found.
|
|
Note the use of **?** to write to the ''a.out'' file. The form **?* **
|
|
would have been used for a 411 file.
|
|
|
|
More frequently the request will be typed as:
|
|
**?l 'Th'; ?s**
|
|
and locates the first occurrence of "Th" and print the
|
|
entire string. Execution of this ADB request will set dot
|
|
to the address of the "Th" characters.
|
|
|
|
As another example of the utility of the patching
|
|
facility, consider a C program that has an internal logic
|
|
flag. The flag could be set by the user through ADB and the
|
|
program run. For example:
|
|
**adb a.out -**
|
|
**:s arg1 arg2**
|
|
**flag/w 1**
|
|
**:c**
|
|
The **:s** request is normally used to single step through a
|
|
process or start a process in single step mode. In this
|
|
case it starts ''a.out'' as a subprocess with arguments **arg1** and **arg2**.
|
|
If there is a subprocess running ADB writes to it
|
|
rather than to the file so the **w** request causes ''flag'' to be
|
|
changed in the memory of the subprocess.
|
|
|
|
|
|
===== 7. Anomalies =====
|
|
|
|
Below is a list of some strange things that users
|
|
should be aware of.
|
|
|
|
- Function calls and arguments are put on the stack by the C save routine. Putting breakpoints at the entry point to routines means that the function appears not to have been called when the breakpoint occurs.
|
|
|
|
- When printing addresses, ADB uses either text or data symbols from the ''a.out'' file. This sometimes causes unexpected symbol names to be printed with data (e.g. ''savr5+022''). This does not happen if **?** is used for text (instructions) and **/** for data.
|
|
|
|
- ADB cannot handle C register variables in the most recently activated function.
|
|
|
|
===== 8. Acknowledgements =====
|
|
|
|
The authors are grateful for the thoughtful comments on
|
|
how to organize this document from R. B. Brandt, E. N. Pinson
|
|
and B. A. Tague. D. M. Ritchie made the system changes
|
|
necessary to accommodate tracing within ADB. He also participated
|
|
in discussions during the writing of ADB. His earlier
|
|
work with DB and CDB led to many of the features found in ADB.
|
|
|
|
|
|
===== 9. References =====
|
|
|
|
- D. M. Ritchie and K. Thompson, "The UNIX Time-Sharing System", CACM, July, 1974.
|
|
|
|
- B. W. Kernighan and D. M. Ritchie, "The C Programming Language", Prentice-Hall, 1978.
|
|
|
|
- K. Thompson and D. M. Ritchie, UNIX Programmer's Manual - 7th Edition, 1978.
|
|
|
|
- B. W. Kernighan and P. J. Plauger, "Software Tools", Addison-Wesley, 1976.
|