2 |
- |
1 |
.HTML "Acid: A Debugger Built From A Language
|
|
|
2 |
.TL
|
|
|
3 |
Acid: A Debugger Built From A Language
|
|
|
4 |
.AU
|
|
|
5 |
Phil Winterbottom
|
|
|
6 |
philw@plan9.bell-labs.com
|
|
|
7 |
.AB
|
|
|
8 |
.FS
|
|
|
9 |
Originally appeared in
|
|
|
10 |
.I
|
|
|
11 |
Proc. of the Winter 1994 USENIX Conf.,
|
|
|
12 |
.R
|
|
|
13 |
pp. 211-222,
|
|
|
14 |
San Francisco, CA
|
|
|
15 |
.FE
|
|
|
16 |
Acid is an unusual source-level symbolic debugger for Plan 9. It is implemented
|
|
|
17 |
as a language interpreter with specialized primitives that provide
|
|
|
18 |
debugger support. Programs written in the language manipulate
|
|
|
19 |
one or more target processes; variables in the language represent the
|
|
|
20 |
symbols, state, and resources of those processes.
|
|
|
21 |
This structure allows complex
|
|
|
22 |
interaction between the debugger and the target program and
|
|
|
23 |
provides a convenient method of parameterizing differences between
|
|
|
24 |
machine architectures.
|
|
|
25 |
Although some effort is required to learn
|
|
|
26 |
the debugging language, the richness and flexibility of the
|
|
|
27 |
debugging environment encourages new ways of reasoning about the way
|
|
|
28 |
programs run and the conditions under which they fail.
|
|
|
29 |
.AE
|
|
|
30 |
.NH
|
|
|
31 |
Introduction
|
|
|
32 |
.PP
|
|
|
33 |
The size and complexity
|
|
|
34 |
of programs have increased in proportion to processor speed and memory but
|
|
|
35 |
the interface between debugger and programmer has changed little.
|
|
|
36 |
Graphical user interfaces have eased some of the tedious
|
|
|
37 |
aspects of the interaction. A graphical interface is a convenient
|
|
|
38 |
means for navigating through source and data structures but provides
|
|
|
39 |
little benefit for process control.
|
|
|
40 |
The introduction of a new concurrent language, Alef [Win93], emphasized the
|
|
|
41 |
inadequacies of the existing Plan 9 [Pike90] debugger
|
|
|
42 |
.I db ,
|
|
|
43 |
a distant relative of
|
|
|
44 |
.I adb ,
|
|
|
45 |
and made it clear that a new debugger was required.
|
|
|
46 |
.PP
|
|
|
47 |
Current debuggers like
|
|
|
48 |
.I dbx ,
|
|
|
49 |
.I sdb ,
|
|
|
50 |
and
|
|
|
51 |
.I gdb
|
|
|
52 |
are limited to answering only the questions their authors
|
|
|
53 |
envisage. As a result, they supply a plethora
|
|
|
54 |
of specialized commands, each attempting to anticipate
|
|
|
55 |
a specific question a user may ask.
|
|
|
56 |
When a debugging situation arises that is beyond the scope
|
|
|
57 |
of the command set, the tool is useless.
|
|
|
58 |
Further,
|
|
|
59 |
it is often tedious or impossible to reproduce an anomalous state
|
|
|
60 |
of the program, especially when
|
|
|
61 |
the state is embedded in the program's data structures.
|
|
|
62 |
.PP
|
|
|
63 |
Acid applies some ideas found in CAD software used for
|
|
|
64 |
hardware test and simulation.
|
|
|
65 |
It is based on the notion that the state and resources of a program
|
|
|
66 |
are best represented and manipulated by a language. The state and resources,
|
|
|
67 |
such as memory, registers, variables, type information and source code
|
|
|
68 |
are represented by variables in the language.
|
|
|
69 |
Expressions provide a computation mechanism and control
|
|
|
70 |
statements allow repetitive or selective interpretation based
|
|
|
71 |
on the result of expression evaluation.
|
|
|
72 |
The heart of the Acid debugger is an interpreter for a small typeless
|
|
|
73 |
language whose operators mirror the operations
|
|
|
74 |
of C and Alef, which in turn correspond well to the basic operations of
|
|
|
75 |
the machine. The interpreter itself knows nothing of the underlying
|
|
|
76 |
hardware; it deals with the program state and resources
|
|
|
77 |
in the abstract.
|
|
|
78 |
Fundamental routines to control
|
|
|
79 |
processes, read files, and interface to the system are implemented
|
|
|
80 |
as builtin functions available to the interpreter.
|
|
|
81 |
The actual debugger functionality is coded
|
|
|
82 |
in Acid; commands are implemented as Acid functions.
|
|
|
83 |
.PP
|
|
|
84 |
This language-based approach has several advantages.
|
|
|
85 |
Most importantly, programs written in Acid, including most of the
|
|
|
86 |
debugger itself, are inherently portable.
|
|
|
87 |
Furthermore, Acid avoids the limitations other debuggers impose when
|
|
|
88 |
debugging parallel programs. Instead of embedding a fixed
|
|
|
89 |
process model in the debugger, Acid allows the
|
|
|
90 |
programmer to adapt the debugger to handle an
|
|
|
91 |
arbitrary process partitioning or program structure.
|
|
|
92 |
The ability to
|
|
|
93 |
interact dynamically with an executing process provides clear advantages
|
|
|
94 |
over debuggers constrained to probe a static image.
|
|
|
95 |
Finally, the Acid language is a powerful vehicle for expressing
|
|
|
96 |
assertions about logic, process state, and the contents of data structures.
|
|
|
97 |
When combined with dynamic interaction it allows a
|
|
|
98 |
limited form of automated program verification without requiring
|
|
|
99 |
modification or recompilation of the source code.
|
|
|
100 |
The language is also an
|
|
|
101 |
excellent vehicle for preserving a test suite for later regression testing.
|
|
|
102 |
.PP
|
|
|
103 |
The debugger may be customized by its users; standard
|
|
|
104 |
functions may be modified or extended to suit a particular application
|
|
|
105 |
or preference.
|
|
|
106 |
For example, the kernel developers in our group require a
|
|
|
107 |
command set supporting assembler-level debugging while the application
|
|
|
108 |
programmers prefer source-level functionality.
|
|
|
109 |
Although the default library is biased toward assembler-level debugging,
|
|
|
110 |
it is easily modified to provide a convenient source-level interface.
|
|
|
111 |
The debugger itself does not change; the user combines primitives
|
|
|
112 |
and existing Acid functions in different ways to
|
|
|
113 |
implement the desired interface.
|
|
|
114 |
.NH
|
|
|
115 |
Related Work
|
|
|
116 |
.PP
|
|
|
117 |
DUEL [Gol93], an extension to
|
|
|
118 |
.I gdb
|
|
|
119 |
[Stal91], proposes using a high level expression evaluator to solve
|
|
|
120 |
some of these problems. The evaluator provides iterators to loop over data
|
|
|
121 |
structures and conditionals to control evaluation of expressions.
|
|
|
122 |
The author shows that complex state queries can be formulated
|
|
|
123 |
by combining concise expressions but this only addresses part of the problem.
|
|
|
124 |
A program is a dynamic entity; questions asked when the program is in
|
|
|
125 |
a static state are meaningful only after the program has been `caught' in
|
|
|
126 |
that state. The framework for manipulating the program is still as
|
|
|
127 |
primitive as the underlying debugger. While DUEL provides a means to
|
|
|
128 |
probe data structures it entirely neglects the most beneficial aspect
|
|
|
129 |
of debugging languages: the ability to control processes. Acid is structured
|
|
|
130 |
around a thread of control that passes between the interpreter and the
|
|
|
131 |
target program.
|
|
|
132 |
.PP
|
|
|
133 |
The NeD debugger [May92] is a set of extensions to TCL [Ous90] that provide
|
|
|
134 |
debugging primitives. The resulting language, NeDtcl, is used to implement
|
|
|
135 |
a portable interface between a conventional debugger, pdb [May90], and
|
|
|
136 |
a server that executes NeDtcl programs operating on the target program.
|
|
|
137 |
Execution of the NeDtcl programs implements the debugging primitives
|
|
|
138 |
that pdb expects.
|
|
|
139 |
NeD is targeted at multi-process debugging across a network,
|
|
|
140 |
and proves the flexibility of a language as a means of
|
|
|
141 |
communication between debugging tools. Whereas NeD provides an interface
|
|
|
142 |
between a conventional debugger and the process it debugs, Acid is the
|
|
|
143 |
debugger itself. While NeD has some of the ideas
|
|
|
144 |
found in Acid it is targeted toward a different purpose. Acid seeks to
|
|
|
145 |
integrate the manipulation of a program's resources into the debugger
|
|
|
146 |
while NeD provides a flexible interconnect between components of
|
|
|
147 |
the debugging environment. The choice of TCL is appropriate for its use
|
|
|
148 |
in NeD but is not suitable for Acid. Acid relies on the coupling of the type
|
|
|
149 |
system with expression evaluation, which are the root of its design,
|
|
|
150 |
to provide the debugging primitives.
|
|
|
151 |
.PP
|
|
|
152 |
Dalek [Ols90] is an event based language extension to gdb. State transitions
|
|
|
153 |
in the target program cause events to be queued for processing by the
|
|
|
154 |
debugging language.
|
|
|
155 |
.PP
|
|
|
156 |
Acid has many of the advantages of same process or
|
|
|
157 |
.I local
|
|
|
158 |
.I agent
|
|
|
159 |
debuggers, like Parasight [Aral], without the need for dynamic linking or
|
|
|
160 |
shared memory.
|
|
|
161 |
Acid improves on the ideas of these other systems by completely integrating
|
|
|
162 |
all aspects of the debugging process into the language environment. Of
|
|
|
163 |
particular importance is the relationship between Acid variables,
|
|
|
164 |
program symbols, source code, registers and type information. This
|
|
|
165 |
integration is made possible by the design of the Acid language.
|
|
|
166 |
.PP
|
|
|
167 |
Interpreted languages such as Lisp and Smalltalk are able to provide
|
|
|
168 |
richer debugging environments through more complete information than
|
|
|
169 |
their compiled counterparts. Acid is a means to gather and represent
|
|
|
170 |
similar information about compiled programs through cooperation
|
|
|
171 |
with the compilation tools and library implementers.
|
|
|
172 |
.NH
|
|
|
173 |
Acid the Language
|
|
|
174 |
.PP
|
|
|
175 |
Acid is a small interpreted language targeted to its debugging task.
|
|
|
176 |
It focuses on representing program state and addressing data rather than
|
|
|
177 |
expressing complex computations. Program state is
|
|
|
178 |
.I addressable
|
|
|
179 |
from an Acid program.
|
|
|
180 |
In addition to parsing and executing expressions and providing
|
|
|
181 |
an architecture-independent interface to the target process,
|
|
|
182 |
the interpreter supplies a mark-and-scan garbage collector
|
|
|
183 |
to manage storage.
|
|
|
184 |
.PP
|
|
|
185 |
Every Acid session begins with the loading of the Acid libraries.
|
|
|
186 |
These libraries contain functions, written in Acid, that provide
|
|
|
187 |
a standard debugging environment including breakpoint management,
|
|
|
188 |
stepping by instruction or statement, stack tracing, and
|
|
|
189 |
access to variables, memory, and registers.
|
|
|
190 |
The library contains 600 lines of Acid code and provides
|
|
|
191 |
functionality similar to
|
|
|
192 |
.I dbx .
|
|
|
193 |
Following the loading of the system library, Acid loads
|
|
|
194 |
user-specified libraries; this load sequence allows the
|
|
|
195 |
user to augment or override the standard commands
|
|
|
196 |
to customize the debugging environment. When all libraries
|
|
|
197 |
are loaded, Acid issues an interactive prompt and begins
|
|
|
198 |
evaluating expressions entered by the user. The Acid `commands'
|
|
|
199 |
are actually invocations of builtin primitives or previously defined
|
|
|
200 |
Acid functions. Acid evaluates each expression as it is entered and
|
|
|
201 |
prints the result.
|
|
|
202 |
.NH
|
|
|
203 |
Types and Variables
|
|
|
204 |
.PP
|
|
|
205 |
Acid variables are of four basic types:
|
|
|
206 |
.I integer ,
|
|
|
207 |
.I string ,
|
|
|
208 |
.I float ,
|
|
|
209 |
and
|
|
|
210 |
.I list .
|
|
|
211 |
The type of a variable is inferred by the type of the right-hand side of
|
|
|
212 |
an assignment expression.
|
|
|
213 |
Many of the operators can be applied to more than
|
|
|
214 |
one type; for these operators the action of the operator is determined
|
|
|
215 |
by the type of its operands.
|
|
|
216 |
For example,
|
|
|
217 |
the
|
|
|
218 |
.CW +
|
|
|
219 |
operator adds
|
|
|
220 |
.I integer
|
|
|
221 |
and
|
|
|
222 |
.I float
|
|
|
223 |
operands, and concatenates
|
|
|
224 |
.I string
|
|
|
225 |
and
|
|
|
226 |
.I list
|
|
|
227 |
operands.
|
|
|
228 |
Lists are the only complex type in Acid; there are no arrays, structures
|
|
|
229 |
or pointers. Operators provide
|
|
|
230 |
.CW head ,
|
|
|
231 |
.CW tail ,
|
|
|
232 |
.CW append
|
|
|
233 |
and
|
|
|
234 |
.CW delete
|
|
|
235 |
operations.
|
|
|
236 |
Lists can also be indexed like arrays.
|
|
|
237 |
.PP
|
|
|
238 |
Acid has two levels of scope: global and local.
|
|
|
239 |
Function parameters and variables declared in a function body
|
|
|
240 |
using the
|
|
|
241 |
.CW local
|
|
|
242 |
keyword are created at entry to the function and
|
|
|
243 |
exist for the lifetime of a function.
|
|
|
244 |
Global variables are created by assignment and need not be declared.
|
|
|
245 |
All variables and functions in the program
|
|
|
246 |
being debugged are entered in the Acid symbol table as global
|
|
|
247 |
variables during Acid initialization.
|
|
|
248 |
Conflicting variable names are resolved by prefixing enough `$' characters
|
|
|
249 |
to make them unique.
|
|
|
250 |
Syntactically, Acid variables and target program
|
|
|
251 |
symbols are referenced identically.
|
|
|
252 |
However, the variables are managed differently in the Acid
|
|
|
253 |
symbol table and the user must be aware of this distinction.
|
|
|
254 |
The value of an Acid variable is stored in the symbol
|
|
|
255 |
table; a reference returns the value.
|
|
|
256 |
The symbol table entry for a variable or function in the target
|
|
|
257 |
program contains the address of that symbol in the image
|
|
|
258 |
of the program. Thus, the value of a program variable is
|
|
|
259 |
accessed by indirect reference through the Acid
|
|
|
260 |
variable that has the same name; the value of an Acid variable is the
|
|
|
261 |
address of the corresponding program variable.
|
|
|
262 |
.NH
|
|
|
263 |
Control Flow
|
|
|
264 |
.PP
|
|
|
265 |
The
|
|
|
266 |
.CW while
|
|
|
267 |
and
|
|
|
268 |
.CW loop
|
|
|
269 |
statements implement looping.
|
|
|
270 |
The former
|
|
|
271 |
is similar to the same statement in C.
|
|
|
272 |
The latter evaluates starting and ending expressions yielding
|
|
|
273 |
integers and iterates while an incrementing loop index
|
|
|
274 |
is within the bounds of those expressions.
|
|
|
275 |
.P1
|
|
|
276 |
acid: i = 0; loop 1,5 do print(i=i+1)
|
|
|
277 |
0x00000001
|
|
|
278 |
0x00000002
|
|
|
279 |
0x00000003
|
|
|
280 |
0x00000004
|
|
|
281 |
0x00000005
|
|
|
282 |
acid:
|
|
|
283 |
.P2
|
|
|
284 |
The traditional
|
|
|
285 |
.CW if-then-else
|
|
|
286 |
statement implements conditional execution.
|
|
|
287 |
.NH
|
|
|
288 |
Addressing
|
|
|
289 |
.PP
|
|
|
290 |
Two indirection operators allow Acid to access values in
|
|
|
291 |
the program being debugged.
|
|
|
292 |
The
|
|
|
293 |
.CW *
|
|
|
294 |
operator fetches a value from the memory image of an
|
|
|
295 |
executing process;
|
|
|
296 |
the
|
|
|
297 |
.CW @
|
|
|
298 |
operator fetches a value from the text file of the process.
|
|
|
299 |
When either operator appears on the left side of an assignment, the value
|
|
|
300 |
is written rather than read.
|
|
|
301 |
.PP
|
|
|
302 |
The indirection operator must know the size of the object
|
|
|
303 |
referenced by a variable.
|
|
|
304 |
The Plan 9 compilers neglect to include this
|
|
|
305 |
information in the program symbol table, so Acid cannot
|
|
|
306 |
derive this information implicitly.
|
|
|
307 |
Instead Acid variables have formats.
|
|
|
308 |
The format is a code
|
|
|
309 |
letter specifying the printing style and the effect of some of the
|
|
|
310 |
operators on that variable.
|
|
|
311 |
The indirection operators look at the format code to determine the
|
|
|
312 |
number of bytes to read or write.
|
|
|
313 |
The format codes are derived from the format letters used by
|
|
|
314 |
.I db .
|
|
|
315 |
By default, symbol table variables and numeric constants
|
|
|
316 |
are assigned the format code
|
|
|
317 |
.CW 'X'
|
|
|
318 |
which specifies 32-bit hexadecimal.
|
|
|
319 |
Printing such a variable yields output of the form
|
|
|
320 |
.CW 0x00123456 .
|
|
|
321 |
An indirect reference through the variable fetches 32 bits
|
|
|
322 |
of data at the address indicated by the variable.
|
|
|
323 |
Other formats specify various data types, for example
|
|
|
324 |
.CW i
|
|
|
325 |
an instruction,
|
|
|
326 |
.CW D
|
|
|
327 |
a signed 32 bit decimal,
|
|
|
328 |
.CW s
|
|
|
329 |
a null-terminated string.
|
|
|
330 |
The
|
|
|
331 |
.CW fmt
|
|
|
332 |
function
|
|
|
333 |
allows the user to change the format code of a variable
|
|
|
334 |
to control the printing format and
|
|
|
335 |
operator side effects.
|
|
|
336 |
This function evaluates the expression supplied as the first
|
|
|
337 |
argument, attaches the format code supplied as the second
|
|
|
338 |
argument to the result and returns that value.
|
|
|
339 |
If the result is assigned to a variable,
|
|
|
340 |
the new format code applies to
|
|
|
341 |
that variable. For convenience, Acid provides the
|
|
|
342 |
.CW \e
|
|
|
343 |
operator as a shorthand infix form of
|
|
|
344 |
.CW fmt .
|
|
|
345 |
For example:
|
|
|
346 |
.P1
|
|
|
347 |
acid: x=10
|
|
|
348 |
acid: x // print x in hex
|
|
|
349 |
0x0000000a
|
|
|
350 |
acid: x = fmt(x, 'D') // make x type decimal
|
|
|
351 |
acid: print(x, fmt(x, 'X'), x\eX) // print x in decimal & hex
|
|
|
352 |
10 0x0000000a 0x0000000a
|
|
|
353 |
acid: x // print x in decimal
|
|
|
354 |
10
|
|
|
355 |
acid: x\eo // print x in octal
|
|
|
356 |
000000000012
|
|
|
357 |
.P2
|
|
|
358 |
The
|
|
|
359 |
.CW ++
|
|
|
360 |
and
|
|
|
361 |
.CW --
|
|
|
362 |
operators increment or decrement a variable by an amount
|
|
|
363 |
determined by its format code. Some formats imply a non-fixed size.
|
|
|
364 |
For example, the
|
|
|
365 |
.CW i
|
|
|
366 |
format code disassembles an instruction into a string.
|
|
|
367 |
On a 68020, which has variable length instructions:
|
|
|
368 |
.P1
|
|
|
369 |
acid: p=main\ei // p=addr(main), type INST
|
|
|
370 |
acid: loop 1,5 do print(p\eX, @p++) // disassemble 5 instr's
|
|
|
371 |
0x0000222e LEA 0xffffe948(A7),A7
|
|
|
372 |
0x00002232 MOVL s+0x4(A7),A2
|
|
|
373 |
0x00002236 PEA 0x2f($0)
|
|
|
374 |
0x0000223a MOVL A2,-(A7)
|
|
|
375 |
0x0000223c BSR utfrrune
|
|
|
376 |
acid:
|
|
|
377 |
.P2
|
|
|
378 |
Here,
|
|
|
379 |
.CW main
|
|
|
380 |
is the address of the function of the same name in the program under test.
|
|
|
381 |
The loop retrieves the five instructions beginning at that address and
|
|
|
382 |
then prints the address and the assembly language representation of each.
|
|
|
383 |
Notice that the stride of the increment operator varies with the size of
|
|
|
384 |
the instruction: the
|
|
|
385 |
.CW MOVL
|
|
|
386 |
at
|
|
|
387 |
.CW 0x0000223a
|
|
|
388 |
is a two byte instruction while all others are four bytes long.
|
|
|
389 |
.PP
|
|
|
390 |
Registers are treated as normal program variables referenced
|
|
|
391 |
by their symbolic assembler language names.
|
|
|
392 |
When a
|
|
|
393 |
process stops, the register set is saved by the kernel
|
|
|
394 |
at a known virtual address in the process memory map.
|
|
|
395 |
The Acid variables associated with the registers point
|
|
|
396 |
to the saved values and the
|
|
|
397 |
.CW *
|
|
|
398 |
indirection operator can then be used to read and write the register set.
|
|
|
399 |
Since the registers are accessed via Acid variables they may
|
|
|
400 |
be used in arbitrary expressions.
|
|
|
401 |
.P1
|
|
|
402 |
acid: PC // addr of saved PC
|
|
|
403 |
0xc0000f60
|
|
|
404 |
acid: *PC
|
|
|
405 |
0x0000623c // contents of PC
|
|
|
406 |
acid: *PC\ea
|
|
|
407 |
main
|
|
|
408 |
acid: *R1=10 // modify R1
|
|
|
409 |
acid: asm(*PC+4) // disassemble @ PC+4
|
|
|
410 |
main+0x4 0x00006240 MOVW R31,0x0(R29)
|
|
|
411 |
main+0x8 0x00006244 MOVW $setR30(SB),R30
|
|
|
412 |
main+0x10 0x0000624c MOVW R1,_clock(SB)
|
|
|
413 |
.P2
|
|
|
414 |
Here, the saved
|
|
|
415 |
.CW PC
|
|
|
416 |
is stored at address
|
|
|
417 |
.CW 0xc0000f60 ;
|
|
|
418 |
its current content is
|
|
|
419 |
.CW 0x0000623c .
|
|
|
420 |
The
|
|
|
421 |
.CW a ' `
|
|
|
422 |
format code converts this value to a string specifying
|
|
|
423 |
the address as an offset beyond the nearest symbol.
|
|
|
424 |
After setting the value of register
|
|
|
425 |
.CW 1 ,
|
|
|
426 |
the example uses the
|
|
|
427 |
.CW asm
|
|
|
428 |
command to disassemble a short section of code beginning
|
|
|
429 |
at four bytes beyond the current value of the
|
|
|
430 |
.CW PC .
|
|
|
431 |
.NH
|
|
|
432 |
Process Interface
|
|
|
433 |
.PP
|
|
|
434 |
A program executing under Acid is monitored through the
|
|
|
435 |
.I proc
|
|
|
436 |
file system interface provided by Plan 9.
|
|
|
437 |
Textual messages written to the
|
|
|
438 |
.CW ctl
|
|
|
439 |
file control the execution of the process.
|
|
|
440 |
For example writing
|
|
|
441 |
.CW waitstop
|
|
|
442 |
to the control file causes the write to block until the target
|
|
|
443 |
process enters the kernel and is stopped. When the process is stopped
|
|
|
444 |
the write completes. The
|
|
|
445 |
.CW startstop
|
|
|
446 |
message starts the target process and then does a
|
|
|
447 |
.CW waitstop
|
|
|
448 |
action.
|
|
|
449 |
Synchronization between the debugger and the target process is determined
|
|
|
450 |
by the actions of the various messages. Some operate asynchronously to the
|
|
|
451 |
target process and always complete immediately, others block until the
|
|
|
452 |
action completes. The asynchronous messages allow Acid to control
|
|
|
453 |
several processes simultaneously.
|
|
|
454 |
.PP
|
|
|
455 |
The interpreter has builtin functions named after each of the control
|
|
|
456 |
messages. The functions take a process id as argument.
|
|
|
457 |
Any time a control message causes the program to execute instructions
|
|
|
458 |
the interpreter performs two actions when the control operation has completed.
|
|
|
459 |
The Acid variables pointing at the register set are fixed up to point
|
|
|
460 |
at the saved registers, and then
|
|
|
461 |
the user defined function
|
|
|
462 |
.CW stopped
|
|
|
463 |
is executed.
|
|
|
464 |
The
|
|
|
465 |
.CW stopped
|
|
|
466 |
function may print the current address,
|
|
|
467 |
line of source or instruction and return to interactive mode. Alternatively
|
|
|
468 |
it may traverse a complex data structure, gather statistics and then set
|
|
|
469 |
the program running again.
|
|
|
470 |
.PP
|
|
|
471 |
Several Acid variables are maintained by the debugger rather than the
|
|
|
472 |
programmer.
|
|
|
473 |
These variables allow generic Acid code to deal with the current process,
|
|
|
474 |
architecture specifics or the symbol table.
|
|
|
475 |
The variable
|
|
|
476 |
.CW pid
|
|
|
477 |
is the process id of the current process Acid is debugging.
|
|
|
478 |
The variable
|
|
|
479 |
.CW symbols
|
|
|
480 |
contains a list of lists where each sublist contains the symbol
|
|
|
481 |
name, its type and the value of the symbol.
|
|
|
482 |
The variable
|
|
|
483 |
.CW registers
|
|
|
484 |
contains a list of the machine-specific register names. Global symbols in the target program
|
|
|
485 |
can be referenced directly by name from Acid. Local variables
|
|
|
486 |
are referenced using the colon operator as \f(CWfunction:variable\fP.
|
|
|
487 |
.NH
|
|
|
488 |
Source Level Debugging
|
|
|
489 |
.PP
|
|
|
490 |
Acid provides several builtin functions to manipulate source code.
|
|
|
491 |
The
|
|
|
492 |
.CW file
|
|
|
493 |
function reads a text file, inserting each line into a list.
|
|
|
494 |
The
|
|
|
495 |
.CW pcfile
|
|
|
496 |
and
|
|
|
497 |
.CW pcline
|
|
|
498 |
functions each take an address as an argument.
|
|
|
499 |
The first
|
|
|
500 |
returns a string containing the name of the source file
|
|
|
501 |
and the second returns an integer containing the line number
|
|
|
502 |
of the source line containing the instruction at the address.
|
|
|
503 |
.P1
|
|
|
504 |
acid: pcfile(main) // file containing main
|
|
|
505 |
main.c
|
|
|
506 |
acid: pcline(main) // line # of main in source
|
|
|
507 |
11
|
|
|
508 |
acid: file(pcfile(main))[pcline(main)] // print that line
|
|
|
509 |
main(int argc, char *argv[])
|
|
|
510 |
acid: src(*PC) // print statements nearby
|
|
|
511 |
9
|
|
|
512 |
10 void
|
|
|
513 |
>11 main(int argc, char *argv[])
|
|
|
514 |
12 {
|
|
|
515 |
13 int a;
|
|
|
516 |
.P2
|
|
|
517 |
In this example, the three primitives are combined in an expression to print
|
|
|
518 |
a line of source code associated with an address.
|
|
|
519 |
The
|
|
|
520 |
.CW src
|
|
|
521 |
function prints a few lines of source
|
|
|
522 |
around the address supplied as its argument. A companion routine,
|
|
|
523 |
.CW Bsrc ,
|
|
|
524 |
communicates with the external editor
|
|
|
525 |
.CW sam .
|
|
|
526 |
Given an address, it loads the corresponding source file into the editor
|
|
|
527 |
and highlights the line containing the address. This simple interface
|
|
|
528 |
is easily extended to more complex functions.
|
|
|
529 |
For example, the
|
|
|
530 |
.CW step
|
|
|
531 |
function can select the current file and line in the editor
|
|
|
532 |
each time the target program stops, giving the user a visual
|
|
|
533 |
trace of the execution path of the program. A more complete interface
|
|
|
534 |
allowing two way communication between Acid and the
|
|
|
535 |
.CW acme
|
|
|
536 |
user interface [Pike93] is under construction. A filter between the debugger
|
|
|
537 |
and the user interface provides interpretation of results from both
|
|
|
538 |
sides of the interface. This allows the programming environment to
|
|
|
539 |
interact with the debugger and vice-versa, a capability missing from the
|
|
|
540 |
.CW sam
|
|
|
541 |
interface.
|
|
|
542 |
The
|
|
|
543 |
.CW src
|
|
|
544 |
and
|
|
|
545 |
.CW Bsrc
|
|
|
546 |
functions are both written in Acid code using the file and line primitives.
|
|
|
547 |
Acid provides library functions to step through source level
|
|
|
548 |
statements and functions. Furthermore, addresses in Acid expressions can be
|
|
|
549 |
specified by source file and line.
|
|
|
550 |
Source code is manipulated in the Acid
|
|
|
551 |
.I list
|
|
|
552 |
data type.
|
|
|
553 |
.NH
|
|
|
554 |
The Acid Library
|
|
|
555 |
.PP
|
|
|
556 |
The following examples define some useful commands and
|
|
|
557 |
illustrate the interaction of the debugger and the interpreter.
|
|
|
558 |
.P1
|
|
|
559 |
defn bpset(addr) // set breakpoint
|
|
|
560 |
{
|
|
|
561 |
if match(addr, bplist) >= 0 then
|
|
|
562 |
print("bkpoint already set:", addr\ea, "\en");
|
|
|
563 |
else {
|
|
|
564 |
*fmt(addr, bpfmt) = bpinst; // plant it
|
|
|
565 |
bplist = append bplist, addr; // add to list
|
|
|
566 |
}
|
|
|
567 |
}
|
|
|
568 |
.P2
|
|
|
569 |
The
|
|
|
570 |
.CW bpset
|
|
|
571 |
function plants a break point in memory. The function starts by
|
|
|
572 |
using the
|
|
|
573 |
.CW match
|
|
|
574 |
builtin to
|
|
|
575 |
search the breakpoint list to determine if a breakpoint is already
|
|
|
576 |
set at the address.
|
|
|
577 |
The indirection operator, controlled by the format code returned
|
|
|
578 |
by the
|
|
|
579 |
.CW fmt
|
|
|
580 |
primitive, is used to plant the breakpoint in memory.
|
|
|
581 |
The variables
|
|
|
582 |
.CW bpfmt
|
|
|
583 |
and
|
|
|
584 |
.CW bpinst
|
|
|
585 |
are Acid global variables containing the format code specifying
|
|
|
586 |
the size of the breakpoint instruction and the breakpoint instruction
|
|
|
587 |
itself.
|
|
|
588 |
These
|
|
|
589 |
variables are set by architecture-dependent library code
|
|
|
590 |
when the debugger first attaches to the executing image.
|
|
|
591 |
Finally the address of the breakpoint is
|
|
|
592 |
appended to the breakpoint list,
|
|
|
593 |
.CW bplist .
|
|
|
594 |
.P1
|
|
|
595 |
defn step() // single step
|
|
|
596 |
{
|
|
|
597 |
local lst, lpl, addr, bput;
|
|
|
598 |
|
|
|
599 |
bput = 0; // sitting on bkpoint
|
|
|
600 |
if match(*PC, bplist) >= 0 then {
|
|
|
601 |
bput = fmt(*PC, bpfmt); // save current addr
|
|
|
602 |
*bput = @bput; // replace it
|
|
|
603 |
}
|
|
|
604 |
|
|
|
605 |
lst = follow(*PC); // get follow set
|
|
|
606 |
|
|
|
607 |
lpl = lst;
|
|
|
608 |
while lpl do { // place breakpoints
|
|
|
609 |
*(head lpl) = bpinst;
|
|
|
610 |
lpl = tail lpl;
|
|
|
611 |
}
|
|
|
612 |
|
|
|
613 |
startstop(pid); // do the step
|
|
|
614 |
|
|
|
615 |
while lst do { // remove breakpoints
|
|
|
616 |
addr = fmt(head lst, bpfmt);
|
|
|
617 |
*addr = @addr; // replace instr.
|
|
|
618 |
lst = tail lst;
|
|
|
619 |
}
|
|
|
620 |
if bput != 0 then
|
|
|
621 |
*bput = bpinst; // restore breakpoint
|
|
|
622 |
}
|
|
|
623 |
.P2
|
|
|
624 |
The
|
|
|
625 |
.CW step
|
|
|
626 |
function executes a single assembler instruction.
|
|
|
627 |
If the
|
|
|
628 |
.CW PC
|
|
|
629 |
is sitting
|
|
|
630 |
on a breakpoint, the address and size of
|
|
|
631 |
the breakpoint are saved.
|
|
|
632 |
The breakpoint instruction
|
|
|
633 |
is then removed using the
|
|
|
634 |
.CW @
|
|
|
635 |
operator to fetch
|
|
|
636 |
.CW bpfmt
|
|
|
637 |
bytes from the text file and to place it into the memory
|
|
|
638 |
of the executing process using the
|
|
|
639 |
.CW *
|
|
|
640 |
operator.
|
|
|
641 |
The
|
|
|
642 |
.CW follow
|
|
|
643 |
function is an Acid
|
|
|
644 |
builtin which returns a follow-set: a list of instruction addresses which
|
|
|
645 |
could be executed next.
|
|
|
646 |
If the instruction stored at the
|
|
|
647 |
.CW PC
|
|
|
648 |
is a branch instruction, the
|
|
|
649 |
list contains the addresses of the next instruction and
|
|
|
650 |
the branch destination; otherwise, it contains only the
|
|
|
651 |
address of the next instruction.
|
|
|
652 |
The follow-set is then used to replace each possible following
|
|
|
653 |
instruction with a breakpoint instruction. The original
|
|
|
654 |
instructions need not be saved; they remain
|
|
|
655 |
in their unaltered state in the text file.
|
|
|
656 |
The
|
|
|
657 |
.CW startstop
|
|
|
658 |
builtin writes the `startstop' message to the
|
|
|
659 |
.I proc
|
|
|
660 |
control file for the process named
|
|
|
661 |
.CW pid .
|
|
|
662 |
The target process executes until some condition causes it to
|
|
|
663 |
enter the kernel, in this case, the execution of a breakpoint.
|
|
|
664 |
When the process blocks, the debugger regains control and invokes the
|
|
|
665 |
Acid library function
|
|
|
666 |
.CW stopped
|
|
|
667 |
which reports the address and cause of the blockage.
|
|
|
668 |
The
|
|
|
669 |
.CW startstop
|
|
|
670 |
function completes and returns to the
|
|
|
671 |
.CW step
|
|
|
672 |
function where
|
|
|
673 |
the follow-set is used to replace the breakpoints placed earlier.
|
|
|
674 |
Finally, if the address of the original
|
|
|
675 |
.CW PC
|
|
|
676 |
contained a breakpoint, it is replaced.
|
|
|
677 |
.PP
|
|
|
678 |
Notice that this approach to process control is inherently portable;
|
|
|
679 |
the Acid code is shared by the debuggers for all architectures.
|
|
|
680 |
Acid variables and builtin functions provide a transparent interface
|
|
|
681 |
to architecture-dependent values and functions. Here the breakpoint
|
|
|
682 |
value and format are referenced through Acid variables and the
|
|
|
683 |
.CW follow
|
|
|
684 |
primitive masks the differences in the underlying instruction set.
|
|
|
685 |
.PP
|
|
|
686 |
The
|
|
|
687 |
.CW next
|
|
|
688 |
function, similar to the
|
|
|
689 |
.I dbx
|
|
|
690 |
command of the same name,
|
|
|
691 |
is a simpler example.
|
|
|
692 |
This function steps through
|
|
|
693 |
a single source statement but steps over function calls.
|
|
|
694 |
.P1
|
|
|
695 |
defn next()
|
|
|
696 |
{
|
|
|
697 |
local sp, bound;
|
|
|
698 |
|
|
|
699 |
sp = *SP; // save starting SP
|
|
|
700 |
bound = fnbound(*PC); // begin & end of fn.
|
|
|
701 |
stmnt(); // step 1 statement
|
|
|
702 |
pc = *PC;
|
|
|
703 |
if pc >= bound[0] && pc < bound[1] then
|
|
|
704 |
return {};
|
|
|
705 |
|
|
|
706 |
while (pc<bound[0] || pc>bound[1]) && sp>=*SP do {
|
|
|
707 |
step();
|
|
|
708 |
pc = *PC;
|
|
|
709 |
}
|
|
|
710 |
src(*PC);
|
|
|
711 |
}
|
|
|
712 |
.P2
|
|
|
713 |
The
|
|
|
714 |
.CW next
|
|
|
715 |
function
|
|
|
716 |
starts by saving the current stack pointer in a local variable.
|
|
|
717 |
It then uses the Acid library function
|
|
|
718 |
.CW fnbound
|
|
|
719 |
to return the addresses of the first and last instructions in
|
|
|
720 |
the current function in a list.
|
|
|
721 |
The
|
|
|
722 |
.CW stmnt
|
|
|
723 |
function executes a single source statement and then uses
|
|
|
724 |
.CW src
|
|
|
725 |
to print a few lines of source around the new
|
|
|
726 |
.CW PC .
|
|
|
727 |
If the new value of the
|
|
|
728 |
.CW PC
|
|
|
729 |
remains in the current function,
|
|
|
730 |
.CW next
|
|
|
731 |
returns.
|
|
|
732 |
When the executed statement is a function call or a return
|
|
|
733 |
from a function, the new value of the
|
|
|
734 |
.CW PC
|
|
|
735 |
is outside the bounds calculated by
|
|
|
736 |
.CW fnbound
|
|
|
737 |
and the test of the
|
|
|
738 |
.CW while
|
|
|
739 |
loop is evaluated.
|
|
|
740 |
If the statement was a return, the new value of the stack pointer
|
|
|
741 |
is greater than the original value and the loop completes without
|
|
|
742 |
execution.
|
|
|
743 |
Otherwise, the loop is entered and instructions are continually
|
|
|
744 |
executed until the value of the
|
|
|
745 |
.CW PC
|
|
|
746 |
is between the bounds calculated earlier. At that point, execution
|
|
|
747 |
ceases and a few lines of source in the vicinity of the
|
|
|
748 |
.CW PC
|
|
|
749 |
are printed.
|
|
|
750 |
.PP
|
|
|
751 |
Acid provides concise and elegant expression for control and
|
|
|
752 |
manipulation of target programs. These examples demonstrate how a
|
|
|
753 |
few well-chosen primitives can be combined to create a rich debugging environment.
|
|
|
754 |
.NH
|
|
|
755 |
Dealing With Multiple Architectures
|
|
|
756 |
.PP
|
|
|
757 |
A single binary of Acid may be used to debug a program running on any
|
|
|
758 |
of the five processor architectures supported by Plan 9. For example,
|
|
|
759 |
Plan 9 allows a user on a MIPS to import the
|
|
|
760 |
.I proc
|
|
|
761 |
file system from an i486-based PC and remotely debug a program executing
|
|
|
762 |
on that processor.
|
|
|
763 |
.PP
|
|
|
764 |
Two levels of abstraction provide this architecture independence.
|
|
|
765 |
On the lowest level, a Plan 9 library supplies functions to
|
|
|
766 |
decode the file header of the program being debugged and
|
|
|
767 |
select a table of system parameters
|
|
|
768 |
and a jump vector of architecture-dependent
|
|
|
769 |
functions based on the magic number.
|
|
|
770 |
Among these functions are byte-order-independent
|
|
|
771 |
access to memory and text files, stack manipulation, disassembly,
|
|
|
772 |
and floating point number interpretation.
|
|
|
773 |
The second level of abstraction is supplied by Acid.
|
|
|
774 |
It consists of primitives and approximately 200 lines
|
|
|
775 |
of architecture-dependent Acid library code that interface the
|
|
|
776 |
interpreter to the architecture-dependent library.
|
|
|
777 |
This layer performs functions such as mapping register names to
|
|
|
778 |
memory locations, supplying breakpoint values and sizes,
|
|
|
779 |
and converting processor specific data to Acid data types.
|
|
|
780 |
An example of the latter is the stack trace function
|
|
|
781 |
.CW strace ,
|
|
|
782 |
which uses the stack traversal functions in the
|
|
|
783 |
architecture-dependent library to construct a list of lists describing
|
|
|
784 |
the context of a process. The first level of list selects
|
|
|
785 |
each function in the trace; subordinate lists contain the
|
|
|
786 |
names and values of parameters and local variables of
|
|
|
787 |
the functions. Acid commands and library functions that
|
|
|
788 |
manipulate and display process state information operate
|
|
|
789 |
on the list representation and are independent of the
|
|
|
790 |
underlying architecture.
|
|
|
791 |
.NH
|
|
|
792 |
Alef Runtime
|
|
|
793 |
.PP
|
|
|
794 |
Alef is a concurrent programming language,
|
|
|
795 |
designed specifically for systems programming, which supports both
|
|
|
796 |
shared variable and message passing paradigms.
|
|
|
797 |
Alef borrows the C expression syntax but implements
|
|
|
798 |
a substantially different type system.
|
|
|
799 |
The language provides a rich set of
|
|
|
800 |
exception handling, process management, and synchronization
|
|
|
801 |
primitives, which rely on a runtime system.
|
|
|
802 |
Alef program bugs are often deadlocks, synchronization failures,
|
|
|
803 |
or non-termination caused by locks being held incorrectly.
|
|
|
804 |
In such cases, a process stalls deep
|
|
|
805 |
in the runtime code and it is clearly
|
|
|
806 |
unreasonable to expect a programmer using the language
|
|
|
807 |
to understand the detailed
|
|
|
808 |
internal semantics of the runtime support functions.
|
|
|
809 |
.PP
|
|
|
810 |
Instead, there is an Alef support library, coded in Acid, that
|
|
|
811 |
allows the programmer to interpret the program state in terms of
|
|
|
812 |
Alef operations. Consider the example of a multi-process program
|
|
|
813 |
stalling because of improper synchronization. A stack trace of
|
|
|
814 |
the program indicates that it is waiting for an event in some
|
|
|
815 |
obscure Alef runtime
|
|
|
816 |
synchronization function.
|
|
|
817 |
The function itself is irrelevant to the
|
|
|
818 |
programmer; of greater importance is the identity of the
|
|
|
819 |
unfulfilled event.
|
|
|
820 |
Commands in the Alef support library decode
|
|
|
821 |
the runtime data structures and program state to report the cause
|
|
|
822 |
of the blockage in terms of the high-level operations available to
|
|
|
823 |
the Alef programmer.
|
|
|
824 |
Here, the Acid language acts
|
|
|
825 |
as a communications medium between Alef implementer and Alef user.
|
|
|
826 |
.NH
|
|
|
827 |
Parallel Debugging
|
|
|
828 |
.PP
|
|
|
829 |
The central issue in parallel debugging is how the debugger is
|
|
|
830 |
multiplexed between the processes comprising
|
|
|
831 |
the program.
|
|
|
832 |
Acid has no intrinsic model of process partitioning; it
|
|
|
833 |
only assumes that parallel programs share a symbol table,
|
|
|
834 |
though they need not share memory.
|
|
|
835 |
The
|
|
|
836 |
.CW setproc
|
|
|
837 |
primitive attaches the debugger to a running process
|
|
|
838 |
associated with the process ID supplied as its argument
|
|
|
839 |
and assigns that value to the global variable
|
|
|
840 |
.CW pid ,
|
|
|
841 |
thereby allowing simple rotation among a group of processes.
|
|
|
842 |
Further, the stack trace primitive is driven by parameters
|
|
|
843 |
specifying a unique process context, so it is possible to
|
|
|
844 |
examine the state of cooperating processes without switching
|
|
|
845 |
the debugger focus from the process of interest.
|
|
|
846 |
Since Acid is inherently extensible and capable of
|
|
|
847 |
dynamic interaction with subordinate processes, the
|
|
|
848 |
programmer can define Acid commands to detect and control
|
|
|
849 |
complex interactions between processes.
|
|
|
850 |
In short, the programmer is free to specify how the debugger reacts
|
|
|
851 |
to events generated in specific threads of the program.
|
|
|
852 |
.PP
|
|
|
853 |
The support for parallel debugging in Acid depends on a crucial kernel
|
|
|
854 |
modification: when the text segment of a program is written (usually to
|
|
|
855 |
place a breakpoint), the segment is cloned to prevent other threads
|
|
|
856 |
from encountering the breakpoint. Although this incurs a slight performance
|
|
|
857 |
penalty, it is of little importance while debugging.
|
|
|
858 |
.NH
|
|
|
859 |
Communication Between Tools
|
|
|
860 |
.PP
|
|
|
861 |
The Plan 9 Alef and C compilers do not
|
|
|
862 |
embed detailed type information in the symbol table of an
|
|
|
863 |
executable file.
|
|
|
864 |
However, they do accept a command line option causing them to
|
|
|
865 |
emit descriptions of complex data types
|
|
|
866 |
(e.g., aggregates and abstract data types)
|
|
|
867 |
to an auxiliary file.
|
|
|
868 |
The vehicle for expressing this information is Acid source code.
|
|
|
869 |
When an Acid debugging session is
|
|
|
870 |
subsequently started, that file is loaded with the other Acid libraries.
|
|
|
871 |
.PP
|
|
|
872 |
For each complex object in the program the compiler generates
|
|
|
873 |
three pieces of Acid code.
|
|
|
874 |
The first is a table describing the size and offset of each
|
|
|
875 |
member of the complex data type. Following is an Acid function,
|
|
|
876 |
named the same as the object, that formats and prints each member.
|
|
|
877 |
Finally, Acid declarations associate the
|
|
|
878 |
Alef or C program variables of a type with the functions
|
|
|
879 |
to print them.
|
|
|
880 |
The three forms of declaration are shown in the following example:
|
|
|
881 |
.P1
|
|
|
882 |
struct Bitmap {
|
|
|
883 |
Rectangle 0 r;
|
|
|
884 |
Rectangle 16 clipr;
|
|
|
885 |
'D' 32 ldepth;
|
|
|
886 |
'D' 36 id;
|
|
|
887 |
'X' 40 cache;
|
|
|
888 |
};
|
|
|
889 |
.P2
|
|
|
890 |
.P1
|
|
|
891 |
defn
|
|
|
892 |
Bitmap(addr) {
|
|
|
893 |
complex Bitmap addr;
|
|
|
894 |
print("Rectangle r {\en");
|
|
|
895 |
Rectangle(addr.r);
|
|
|
896 |
print("}\en");
|
|
|
897 |
print("Rectangle clipr {\en");
|
|
|
898 |
Rectangle(addr.clipr);
|
|
|
899 |
print("}\en");
|
|
|
900 |
print(" ldepth ", addr.ldepth, "\en");
|
|
|
901 |
print(" id ", addr.id, "\en");
|
|
|
902 |
print(" cache ", addr.cache, "\en");
|
|
|
903 |
};
|
|
|
904 |
|
|
|
905 |
complex Bitmap darkgrey;
|
|
|
906 |
complex Bitmap Window_settag:b;
|
|
|
907 |
.P2
|
|
|
908 |
The
|
|
|
909 |
.CW struct
|
|
|
910 |
declaration specifies decoding instructions for the complex type named
|
|
|
911 |
.CW Bitmap .
|
|
|
912 |
Although the syntax is superficially similar to a C structure declaration,
|
|
|
913 |
the semantics differ markedly: the C declaration specifies a layout, while
|
|
|
914 |
the Acid declaration tells how to decode it.
|
|
|
915 |
The declaration specifies a type, an offset, and name for each
|
|
|
916 |
member of the complex object. The type is either the name of another
|
|
|
917 |
complex declaration, for example,
|
|
|
918 |
.CW Rectangle ,
|
|
|
919 |
or a format code.
|
|
|
920 |
The offset is the number of bytes from the start
|
|
|
921 |
of the object to the member
|
|
|
922 |
and the name is the member's name in the Alef or C declaration.
|
|
|
923 |
This type description is a close match for C and Alef, but is simple enough
|
|
|
924 |
to be language independent.
|
|
|
925 |
.PP
|
|
|
926 |
The
|
|
|
927 |
.CW Bitmap
|
|
|
928 |
function expects the address of a
|
|
|
929 |
.CW Bitmap
|
|
|
930 |
as its only argument.
|
|
|
931 |
It uses the decoding information contained in the
|
|
|
932 |
.CW Bitmap
|
|
|
933 |
structure declaration to extract, format, and print the
|
|
|
934 |
value of each member of the complex object pointed to by
|
|
|
935 |
the argument.
|
|
|
936 |
The Alef compiler emits code to call other Acid functions
|
|
|
937 |
where a member is another complex type; here,
|
|
|
938 |
.CW Bitmap
|
|
|
939 |
calls
|
|
|
940 |
.CW Rectangle
|
|
|
941 |
to print its contents.
|
|
|
942 |
.PP
|
|
|
943 |
The
|
|
|
944 |
.CW complex
|
|
|
945 |
declarations associate Alef variables with complex types.
|
|
|
946 |
In the example,
|
|
|
947 |
.CW darkgrey
|
|
|
948 |
is the name of a global variable of type
|
|
|
949 |
.CW Bitmap
|
|
|
950 |
in the program being debugged.
|
|
|
951 |
Whenever the name
|
|
|
952 |
.CW darkgrey
|
|
|
953 |
is evaluated by Acid, it automatically calls the
|
|
|
954 |
.CW Bitmap
|
|
|
955 |
function with the address of
|
|
|
956 |
.CW darkgrey
|
|
|
957 |
as the argument.
|
|
|
958 |
The second
|
|
|
959 |
.CW complex
|
|
|
960 |
declaration associates a local variable or parameter named
|
|
|
961 |
.CW b
|
|
|
962 |
in function
|
|
|
963 |
.CW Window_settag
|
|
|
964 |
with the
|
|
|
965 |
.CW Bitmap
|
|
|
966 |
complex data type.
|
|
|
967 |
.PP
|
|
|
968 |
Acid borrows the C operators
|
|
|
969 |
.CW .
|
|
|
970 |
and
|
|
|
971 |
.CW ->
|
|
|
972 |
to access the decoding parameters of a member of a complex type.
|
|
|
973 |
Although this representation is sufficiently general for describing
|
|
|
974 |
the decoding of both C and Alef complex data types, it may
|
|
|
975 |
prove too restrictive for target languages with more complicated
|
|
|
976 |
type systems.
|
|
|
977 |
Further, the assumption that the compiler can select the proper
|
|
|
978 |
Acid format code for each basic type in the language is somewhat
|
|
|
979 |
naive. For example, when a member of a complex type is a pointer,
|
|
|
980 |
it is assigned a hexadecimal type code; integer members are always
|
|
|
981 |
assigned a decimal type code.
|
|
|
982 |
This heuristic proves inaccurate when an integer field is a
|
|
|
983 |
bit mask or set of bit flags which are more appropriately displayed
|
|
|
984 |
in hexadecimal or octal.
|
|
|
985 |
.NH
|
|
|
986 |
Code Verification
|
|
|
987 |
.PP
|
|
|
988 |
Acid's ability to interact dynamically with
|
|
|
989 |
an executing program allows passive test and
|
|
|
990 |
verification of the target program. For example,
|
|
|
991 |
a common concern is leak detection in programs using
|
|
|
992 |
.CW malloc .
|
|
|
993 |
Of interest are two items: finding memory that was allocated
|
|
|
994 |
but never freed and detecting bad pointers passed to
|
|
|
995 |
.CW free .
|
|
|
996 |
An auxiliary Acid library contains Acid functions to
|
|
|
997 |
monitor the execution of a program and detect these
|
|
|
998 |
faults, either as they happen or in the automated
|
|
|
999 |
post-mortem analysis of the memory arena.
|
|
|
1000 |
In the following example, the
|
|
|
1001 |
.CW sort
|
|
|
1002 |
command is run under the control of the
|
|
|
1003 |
Acid memory leak library.
|
|
|
1004 |
.P1
|
|
|
1005 |
helix% acid -l malloc /bin/sort
|
|
|
1006 |
/bin/sort: mips plan 9 executable
|
|
|
1007 |
/lib/acid/port
|
|
|
1008 |
/lib/acid/mips
|
|
|
1009 |
/lib/acid/malloc
|
|
|
1010 |
acid: go()
|
|
|
1011 |
now
|
|
|
1012 |
is
|
|
|
1013 |
the
|
|
|
1014 |
time
|
|
|
1015 |
<ctrl-d>
|
|
|
1016 |
is
|
|
|
1017 |
now
|
|
|
1018 |
the
|
|
|
1019 |
time
|
|
|
1020 |
27680 : breakpoint _exits+0x4 MOVW $0x8,R1
|
|
|
1021 |
acid:
|
|
|
1022 |
.P2
|
|
|
1023 |
The
|
|
|
1024 |
.CW go
|
|
|
1025 |
command creates a process and plants
|
|
|
1026 |
breakpoints at the entry to
|
|
|
1027 |
.CW malloc
|
|
|
1028 |
and
|
|
|
1029 |
.CW free .
|
|
|
1030 |
The program is then started and continues until it
|
|
|
1031 |
exits or stops. If the reason for stopping is anything
|
|
|
1032 |
other than the breakpoints in
|
|
|
1033 |
.CW malloc
|
|
|
1034 |
and
|
|
|
1035 |
.CW free ,
|
|
|
1036 |
Acid prints the usual status information and returns to the
|
|
|
1037 |
interactive prompt.
|
|
|
1038 |
.PP
|
|
|
1039 |
When the process stops on entering
|
|
|
1040 |
.CW malloc ,
|
|
|
1041 |
the debugger must capture and save the address that
|
|
|
1042 |
.CW malloc
|
|
|
1043 |
will return.
|
|
|
1044 |
After saving a stack
|
|
|
1045 |
trace so the calling routine can be identified, it places
|
|
|
1046 |
a breakpoint at the return address and restarts the program.
|
|
|
1047 |
When
|
|
|
1048 |
.CW malloc
|
|
|
1049 |
returns, the breakpoint stops the program,
|
|
|
1050 |
allowing the debugger
|
|
|
1051 |
to grab the address of the new memory block from the return register.
|
|
|
1052 |
The address and stack trace are added to the list of outstanding
|
|
|
1053 |
memory blocks, the breakpoint is removed from the return point, and
|
|
|
1054 |
the process is restarted.
|
|
|
1055 |
.PP
|
|
|
1056 |
When the process stops at the beginning of
|
|
|
1057 |
.CW free ,
|
|
|
1058 |
the memory address supplied as the argument is compared to the list
|
|
|
1059 |
of outstanding memory blocks. If it is not found an error message
|
|
|
1060 |
and a stack trace of the call is reported; otherwise, the
|
|
|
1061 |
address is deleted from the list.
|
|
|
1062 |
.PP
|
|
|
1063 |
When the program exits, the list of outstanding memory blocks contains
|
|
|
1064 |
the addresses of all blocks that were allocated but never freed.
|
|
|
1065 |
The
|
|
|
1066 |
.CW leak
|
|
|
1067 |
library function traverses the list producing a report describing
|
|
|
1068 |
the allocated blocks.
|
|
|
1069 |
.P1 1m
|
|
|
1070 |
acid: leak()
|
|
|
1071 |
Lost a total of 524288 bytes from:
|
|
|
1072 |
malloc() malloc.c:32 called from dofile+0xe8 sort.c:217
|
|
|
1073 |
dofile() sort.c:190 called from main+0xac sort.c:161
|
|
|
1074 |
main() sort.c:128 called from _main+0x20 main9.s:10
|
|
|
1075 |
Lost a total of 64 bytes from:
|
|
|
1076 |
malloc() malloc.c:32 called from newline+0xfc sort.c:280
|
|
|
1077 |
newline() sort.c:248 called from dofile+0x110 sort.c:222
|
|
|
1078 |
dofile() sort.c:190 called from main+0xac sort.c:161
|
|
|
1079 |
main() sort.c:128 called from _main+0x20 main9.s:10
|
|
|
1080 |
Lost a total of 64 bytes from:
|
|
|
1081 |
malloc() malloc.c:32 called from realloc+0x14 malloc.c:129
|
|
|
1082 |
realloc() malloc.c:123 called from bldkey+0x358 sort.c:1388
|
|
|
1083 |
buildkey() sort.c:1345 called from newline+0x150 sort.c:285
|
|
|
1084 |
newline() sort.c:248 called from dofile+0x110 sort.c:222
|
|
|
1085 |
dofile() sort.c:190 called from main+0xac sort.c:161
|
|
|
1086 |
main() sort.c:128 called from _main+0x20 main9.s:10
|
|
|
1087 |
acid: refs()
|
|
|
1088 |
data...bss...stack...
|
|
|
1089 |
acid: leak()
|
|
|
1090 |
acid:
|
|
|
1091 |
.P2
|
|
|
1092 |
The presence of a block in the allocation list does not imply
|
|
|
1093 |
it is there because of a leak; for instance, it may have been
|
|
|
1094 |
in use when the program terminated.
|
|
|
1095 |
The
|
|
|
1096 |
.CW refs()
|
|
|
1097 |
library function scans the
|
|
|
1098 |
.I data ,
|
|
|
1099 |
.I bss ,
|
|
|
1100 |
and
|
|
|
1101 |
.I stack
|
|
|
1102 |
segments of the process looking for pointers
|
|
|
1103 |
into the allocated blocks. When one is found, the block is deleted from
|
|
|
1104 |
the outstanding block list.
|
|
|
1105 |
The
|
|
|
1106 |
.CW leak
|
|
|
1107 |
function is used again to report the
|
|
|
1108 |
blocks remaining allocated and unreferenced.
|
|
|
1109 |
This strategy proves effective in detecting
|
|
|
1110 |
disconnected (but non-circular) data structures.
|
|
|
1111 |
.PP
|
|
|
1112 |
The leak detection process is entirely passive.
|
|
|
1113 |
The program is not
|
|
|
1114 |
specially compiled and the source code is not required.
|
|
|
1115 |
As with the Acid support functions for the Alef runtime environment,
|
|
|
1116 |
the author of the library routines has encapsulated the
|
|
|
1117 |
functionality of the library interface
|
|
|
1118 |
in Acid code.
|
|
|
1119 |
Any programmer may then check a program's use of the
|
|
|
1120 |
library routines without knowledge of either implementation.
|
|
|
1121 |
The performance impact of running leak detection is great
|
|
|
1122 |
(about 10 times slower),
|
|
|
1123 |
but it has not prevented interactive programs like
|
|
|
1124 |
.CW sam
|
|
|
1125 |
and the
|
|
|
1126 |
.CW 8½
|
|
|
1127 |
window system from being tested.
|
|
|
1128 |
.NH
|
|
|
1129 |
Code Coverage
|
|
|
1130 |
.PP
|
|
|
1131 |
Another common component of software test uses
|
|
|
1132 |
.I coverage
|
|
|
1133 |
analysis.
|
|
|
1134 |
The purpose of the test is to determine which paths through the code have
|
|
|
1135 |
not been executed while running the test suite.
|
|
|
1136 |
This is usually
|
|
|
1137 |
performed by a combination of compiler support and a reporting tool run
|
|
|
1138 |
on the output generated by statements compiled into the program.
|
|
|
1139 |
The compiler emits code that
|
|
|
1140 |
logs the progress of the program as it executes basic blocks and writes the
|
|
|
1141 |
results to a file. The file is then processed by the reporting tool
|
|
|
1142 |
to determine which basic blocks have not been executed.
|
|
|
1143 |
.PP
|
|
|
1144 |
Acid can perform the same function in a language independent manner without
|
|
|
1145 |
modifying the source, object or binary of the program. The following example
|
|
|
1146 |
shows
|
|
|
1147 |
.CW ls
|
|
|
1148 |
being run under the control of the Acid coverage library.
|
|
|
1149 |
.P1
|
|
|
1150 |
philw-helix% acid -l coverage /bin/ls
|
|
|
1151 |
/bin/ls: mips plan 9 executable
|
|
|
1152 |
/lib/acid/port
|
|
|
1153 |
/lib/acid/mips
|
|
|
1154 |
/lib/acid/coverage
|
|
|
1155 |
acid: coverage()
|
|
|
1156 |
acid
|
|
|
1157 |
newstime
|
|
|
1158 |
profile
|
|
|
1159 |
tel
|
|
|
1160 |
wintool
|
|
|
1161 |
2: (error) msg: pid=11419 startstop: process exited
|
|
|
1162 |
acid: analyse(ls)
|
|
|
1163 |
ls.c:102,105
|
|
|
1164 |
102: return 1;
|
|
|
1165 |
103: }
|
|
|
1166 |
104: if(db[0].qid.path&CHDIR && dflag==0){
|
|
|
1167 |
105: output();
|
|
|
1168 |
ls.c:122,126
|
|
|
1169 |
122: memmove(dirbuf+ndir, db, sizeof(Dir));
|
|
|
1170 |
123: dirbuf[ndir].prefix = 0;
|
|
|
1171 |
124: p = utfrrune(s, '/');
|
|
|
1172 |
125: if(p){
|
|
|
1173 |
126: dirbuf[ndir].prefix = s;
|
|
|
1174 |
.P2
|
|
|
1175 |
The
|
|
|
1176 |
.CW coverage
|
|
|
1177 |
function begins by looping through the text segment placing
|
|
|
1178 |
breakpoints at the entry to each basic block. The start of each basic
|
|
|
1179 |
block is found using the Acid builtin function
|
|
|
1180 |
.CW follow .
|
|
|
1181 |
If the list generated by
|
|
|
1182 |
.CW follow
|
|
|
1183 |
contains more than one
|
|
|
1184 |
element, then the addresses mark the start of basic blocks. A breakpoint
|
|
|
1185 |
is placed at each address to detect entry into the block. If the result
|
|
|
1186 |
of
|
|
|
1187 |
.CW follow
|
|
|
1188 |
is a single address then no action is taken, and the next address is
|
|
|
1189 |
considered. Acid maintains a list of
|
|
|
1190 |
breakpoints already in place and avoids placing duplicates (an address may be
|
|
|
1191 |
the destination of several branches).
|
|
|
1192 |
.PP
|
|
|
1193 |
After placing the breakpoints the program is set running.
|
|
|
1194 |
Each time a breakpoint is encountered
|
|
|
1195 |
Acid deletes the address from the breakpoint list, removes the breakpoint
|
|
|
1196 |
from memory and then restarts the program.
|
|
|
1197 |
At any instant the breakpoint list contains the addresses of basic blocks
|
|
|
1198 |
which have not been executed.
|
|
|
1199 |
The
|
|
|
1200 |
.CW analyse
|
|
|
1201 |
function reports the lines of source code bounded by basic blocks
|
|
|
1202 |
whose addresses are have not been deleted from the breakpoint list.
|
|
|
1203 |
These are the basic blocks which have not been executed.
|
|
|
1204 |
Program performance is almost unaffected since each breakpoint is executed
|
|
|
1205 |
only once and then removed.
|
|
|
1206 |
.PP
|
|
|
1207 |
The library contains a total of 128 lines of Acid code.
|
|
|
1208 |
An obvious extension of this algorithm could be used to provide basic block
|
|
|
1209 |
profiling.
|
|
|
1210 |
.NH
|
|
|
1211 |
Conclusion
|
|
|
1212 |
.PP
|
|
|
1213 |
Acid has two areas of weakness. As with
|
|
|
1214 |
other language-based tools like
|
|
|
1215 |
.I awk ,
|
|
|
1216 |
a programmer must learn yet another language to step beyond the normal
|
|
|
1217 |
debugging functions and use the full power of the debugger.
|
|
|
1218 |
Second, the command line interface supplied by the
|
|
|
1219 |
.I yacc
|
|
|
1220 |
parser is inordinately clumsy.
|
|
|
1221 |
Part of the problem relates directly to the use of
|
|
|
1222 |
.I yacc
|
|
|
1223 |
and could be circumvented with a custom parser.
|
|
|
1224 |
However, structural problems would remain: Acid often requires
|
|
|
1225 |
too much typing to execute a simple
|
|
|
1226 |
command.
|
|
|
1227 |
A debugger should prostitute itself to its users, doing whatever
|
|
|
1228 |
is wanted with a minimum of encouragement; commands should be
|
|
|
1229 |
concise and obvious. The language interface is more consistent than
|
|
|
1230 |
an ad hoc command interface but is clumsy to use.
|
|
|
1231 |
Most of these problems are addressed by an Acme interface
|
|
|
1232 |
which is under construction. This should provide the best of
|
|
|
1233 |
both worlds: graphical debugging and access to the underlying acid
|
|
|
1234 |
language when required.
|
|
|
1235 |
.PP
|
|
|
1236 |
The name space clash between Acid variables, keywords, program variables,
|
|
|
1237 |
and functions is unavoidable.
|
|
|
1238 |
Although it rarely affects a debugging session, it is annoying
|
|
|
1239 |
when it happens and is sometimes difficult to circumvent.
|
|
|
1240 |
The current renaming scheme
|
|
|
1241 |
is too crude; the new names are too hard to remember.
|
|
|
1242 |
.PP
|
|
|
1243 |
Acid has proved to be a powerful tool whose applications
|
|
|
1244 |
have exceeded expectations.
|
|
|
1245 |
Of its strengths, portability, extensibility and parallel debugging support
|
|
|
1246 |
were by design and provide the expected utility.
|
|
|
1247 |
In retrospect,
|
|
|
1248 |
its use as a tool for code test and verification and as
|
|
|
1249 |
a medium for communicating type information and encapsulating
|
|
|
1250 |
interfaces has provided unanticipated benefits and altered our
|
|
|
1251 |
view of the debugging process.
|
|
|
1252 |
.NH
|
|
|
1253 |
Acknowledgments
|
|
|
1254 |
.PP
|
|
|
1255 |
Bob Flandrena was the first user and helped prepare the paper.
|
|
|
1256 |
Rob Pike endured three buggy Alef compilers and a new debugger
|
|
|
1257 |
in a single sitting.
|
|
|
1258 |
.NH
|
|
|
1259 |
References
|
|
|
1260 |
.LP
|
|
|
1261 |
[Pike90] R. Pike, D. Presotto, K. Thompson, H. Trickey,
|
|
|
1262 |
``Plan 9 from Bell Labs'',
|
|
|
1263 |
.I
|
|
|
1264 |
UKUUG Proc. of the Summer 1990 Conf.,
|
|
|
1265 |
.R
|
|
|
1266 |
London, England,
|
|
|
1267 |
1990,
|
|
|
1268 |
reprinted, in a different form, in this volume.
|
|
|
1269 |
.LP
|
|
|
1270 |
[Gol93] M. Golan, D. Hanson,
|
|
|
1271 |
``DUEL -- A Very High-Level Debugging Language'',
|
|
|
1272 |
.I
|
|
|
1273 |
USENIX Proc. of the Winter 1993 Conf.,
|
|
|
1274 |
.R
|
|
|
1275 |
San Diego, CA,
|
|
|
1276 |
1993.
|
|
|
1277 |
.LP
|
|
|
1278 |
[Lin90] M. A. Linton,
|
|
|
1279 |
``The Evolution of DBX'',
|
|
|
1280 |
.I
|
|
|
1281 |
USENIX Proc. of the Summer 1990 Conf.,
|
|
|
1282 |
.R
|
|
|
1283 |
Anaheim, CA,
|
|
|
1284 |
1990.
|
|
|
1285 |
.LP
|
|
|
1286 |
[Stal91] R. M. Stallman, R. H. Pesch,
|
|
|
1287 |
``Using GDB: A guide to the GNU source level debugger'',
|
|
|
1288 |
Technical Report, Free Software Foundation,
|
|
|
1289 |
Cambridge, MA,
|
|
|
1290 |
1991.
|
|
|
1291 |
.LP
|
|
|
1292 |
[Win93] P. Winterbottom,
|
|
|
1293 |
``Alef reference Manual'',
|
|
|
1294 |
this volume.
|
|
|
1295 |
.LP
|
|
|
1296 |
[Pike93] Rob Pike,
|
|
|
1297 |
``Acme: A User Interface for Programmers'',
|
|
|
1298 |
.I
|
|
|
1299 |
USENIX Proc. of the Winter 1994 Conf.,
|
|
|
1300 |
.R
|
|
|
1301 |
San Francisco, CA,
|
|
|
1302 |
reprinted in this volume.
|
|
|
1303 |
.LP
|
|
|
1304 |
[Ols90] Ronald A. Olsson, Richard H. Crawford, and W. Wilson Ho,
|
|
|
1305 |
``Dalek: A GNU, improved programmable debugger'',
|
|
|
1306 |
.I
|
|
|
1307 |
USENIX Proc. of the Summer 1990 Conf.,
|
|
|
1308 |
.R
|
|
|
1309 |
Anaheim, CA.
|
|
|
1310 |
.LP
|
|
|
1311 |
[May92] Paul Maybee,
|
|
|
1312 |
``NeD: The Network Extensible Debugger''
|
|
|
1313 |
.I
|
|
|
1314 |
USENIX Proc. of the Summer 1992 Conf.,
|
|
|
1315 |
.R
|
|
|
1316 |
San Antonio, TX.
|
|
|
1317 |
.LP
|
|
|
1318 |
[Aral] Ziya Aral, Ilya Gertner, and Greg Schaffer,
|
|
|
1319 |
``Efficient debugging primitives for multiprocessors'',
|
|
|
1320 |
.I
|
|
|
1321 |
Proceedings of the Third International Conference on Architectural
|
|
|
1322 |
Support for Programming Languages and Operating Systems,
|
|
|
1323 |
.R
|
|
|
1324 |
SIGPLAN notices Nr. 22, May 1989.
|