.TLAcid: A Debugger Built From A Language.AU.I "Phil Winterbottom".AI.I "Lucent Technologies Inc".AB.FS\l'1i'.brOriginally appeared in.IProc. of the Winter 1994 USENIX Conf.,.Rpp. 211-222,San Francisco, CA;and subsequently in the.I "Plan 9 Programmer's Manual, Volume 2 (Second Edition)" ..FEAcid is an unusual source-level symbolic debugger for Plan 9. It is implementedas a language interpreter with specialized primitives that providedebugger support. Programs written in the language manipulateone or more target processes; variables in the language represent thesymbols, state, and resources of those processes. This structure allows complexinteraction between the debugger and the target program andprovides a convenient method of parameterizing differences betweenmachine architectures.Although some effort is required to learnthe debugging language, the richness and flexibility of thedebugging environment encourages new ways of reasoning about the wayprograms run and the conditions under which they fail..AE.NHIntroduction.PPThe size and complexityof programs have increased in proportion to processor speed and memory butthe interface between debugger and programmer has changed little.Graphical user interfaces have eased some of the tediousaspects of the interaction. A graphical interface is a convenientmeans for navigating through source and data structures but provideslittle benefit for process control.The introduction of a new concurrent language, Alef [Win93], emphasized theinadequacies of the existing Plan 9 [Pike90] debugger.I db ,a distant relative of.I adb ,and made it clear that a new debugger was required..PPCurrent debuggers like.I dbx ,.I sdb ,and.I gdbare limited to answering only the questions their authorsenvisage. As a result, they supply a plethoraof specialized commands, each attempting to anticipatea specific question a user may ask.When a debugging situation arises that is beyond the scopeof the command set, the tool is useless.Further,it is often tedious or impossible to reproduce an anomalous stateof the program, especially whenthe state is embedded in the program's data structures..PPAcid applies some ideas found in CAD software used forhardware test and simulation.It is based on the notion that the state and resources of a programare best represented and manipulated by a language. The state and resources,such as memory, registers, variables, type information and source codeare represented by variables in the language.Expressions provide a computation mechanism and controlstatements allow repetitive or selective interpretation basedon the result of expression evaluation.The heart of the Acid debugger is an interpreter for a small typelesslanguage whose operators mirror the operationsof C and Alef, which in turn correspond well to the basic operations ofthe machine. The interpreter itself knows nothing of the underlyinghardware; it deals with the program state and resourcesin the abstract.Fundamental routines to controlprocesses, read files, and interface to the system are implementedas builtin functions available to the interpreter.The actual debugger functionality is codedin Acid; commands are implemented as Acid functions..PPThis language-based approach has several advantages.Most importantly, programs written in Acid, including most of thedebugger itself, are inherently portable.Furthermore, Acid avoids the limitations other debuggers impose whendebugging parallel programs. Instead of embedding a fixedprocess model in the debugger, Acid allows theprogrammer to adapt the debugger to handle anarbitrary process partitioning or program structure. The ability tointeract dynamically with an executing process provides clear advantagesover debuggers constrained to probe a static image.Finally, the Acid language is a powerful vehicle for expressingassertions about logic, process state, and the contents of data structures.When combined with dynamic interaction it allows alimited form of automated program verification without requiringmodification or recompilation of the source code.The language is also anexcellent vehicle for preserving a test suite for later regression testing..PPThe debugger may be customized by its users; standardfunctions may be modified or extended to suit a particular applicationor preference.For example, the kernel developers in our group require acommand set supporting assembler-level debugging while the applicationprogrammers prefer source-level functionality.Although the default library is biased toward assembler-level debugging,it is easily modified to provide a convenient source-level interface.The debugger itself does not change; the user combines primitivesand existing Acid functions in different ways toimplement the desired interface..NHRelated Work.PPDUEL [Gol93], an extension to.I gdb[Stal91], proposes using a high level expression evaluator to solvesome of these problems. The evaluator provides iterators to loop over datastructures and conditionals to control evaluation of expressions.The author shows that complex state queries can be formulatedby combining concise expressions but this only addresses part of the problem.A program is a dynamic entity; questions asked when the program is ina static state are meaningful only after the program has been `caught' inthat state. The framework for manipulating the program is still asprimitive as the underlying debugger. While DUEL provides a means toprobe data structures it entirely neglects the most beneficial aspectof debugging languages: the ability to control processes. Acid is structuredaround a thread of control that passes between the interpreter and thetarget program..PPThe NeD debugger [May92] is a set of extensions to TCL [Ous90] that providedebugging primitives. The resulting language, NeDtcl, is used to implementa portable interface between a conventional debugger, pdb [May90], anda server that executes NeDtcl programs operating on the target program.Execution of the NeDtcl programs implements the debugging primitivesthat pdb expects.NeD is targeted at multi-process debugging across a network,and proves the flexibility of a language as a means ofcommunication between debugging tools. Whereas NeD provides an interfacebetween a conventional debugger and the process it debugs, Acid is thedebugger itself. While NeD has some of the ideasfound in Acid it is targeted toward a different purpose. Acid seeks tointegrate the manipulation of a program's resources into the debuggerwhile NeD provides a flexible interconnect between components ofthe debugging environment. The choice of TCL is appropriate for its usein NeD but is not suitable for Acid. Acid relies on the coupling of the typesystem with expression evaluation, which are the root of its design,to provide the debugging primitives..PPDalek [Ols90] is an event based language extension to gdb. State transitionsin the target program cause events to be queued for processing by thedebugging language..PPAcid has many of the advantages of same process or.I local.I agentdebuggers, like Parasight [Aral], without the need for dynamic linking orshared memory.Acid improves on the ideas of these other systems by completely integratingall aspects of the debugging process into the language environment. Ofparticular importance is the relationship between Acid variables,program symbols, source code, registers and type information. Thisintegration is made possible by the design of the Acid language..PPInterpreted languages such as Lisp and Smalltalk are able to providericher debugging environments through more complete information thantheir compiled counterparts. Acid is a means to gather and representsimilar information about compiled programs through cooperationwith the compilation tools and library implementers..NHAcid the Language.PPAcid is a small interpreted language targeted to its debugging task.It focuses on representing program state and addressing data rather thanexpressing complex computations. Program state is.I addressablefrom an Acid program.In addition to parsing and executing expressions and providingan architecture-independent interface to the target process,the interpreter supplies a mark-and-scan garbage collectorto manage storage..PPEvery Acid session begins with the loading of the Acid libraries.These libraries contain functions, written in Acid, that providea standard debugging environment including breakpoint management,stepping by instruction or statement, stack tracing, andaccess to variables, memory, and registers.The library contains 600 lines of Acid code and providesfunctionality similar to.I dbx .Following the loading of the system library, Acid loadsuser-specified libraries; this load sequence allows theuser to augment or override the standard commandsto customize the debugging environment. When all librariesare loaded, Acid issues an interactive prompt and beginsevaluating expressions entered by the user. The Acid `commands'are actually invocations of builtin primitives or previously definedAcid functions. Acid evaluates each expression as it is entered andprints the result..NHTypes and Variables.PPAcid variables are of four basic types:.I integer ,.I string ,.I float ,and.I list .The type of a variable is inferred by the type of the right-hand side ofan assignment expression.Many of the operators can be applied to more thanone type; for these operators the action of the operator is determinedby the type of its operands.For example,the.CW +operator adds.I integerand.I floatoperands, and concatenates.I stringand.I listoperands.Lists are the only complex type in Acid; there are no arrays, structuresor pointers. Operators provide.CW head ,.CW tail ,.CW appendand.CW deleteoperations.Lists can also be indexed like arrays..PPAcid has two levels of scope: global and local.Function parameters and variables declared in a function bodyusing the.CW localkeyword are created at entry to the function andexist for the lifetime of a function.Global variables are created by assignment and need not be declared.All variables and functions in the programbeing debugged are entered in the Acid symbol table as globalvariables during Acid initialization.Conflicting variable names are resolved by prefixing enough `$' charactersto make them unique.Syntactically, Acid variables and target programsymbols are referenced identically.However, the variables are managed differently in the Acidsymbol table and the user must be aware of this distinction.The value of an Acid variable is stored in the symboltable; a reference returns the value.The symbol table entry for a variable or function in the targetprogram contains the address of that symbol in the imageof the program. Thus, the value of a program variable isaccessed by indirect reference through the Acidvariable that has the same name; the value of an Acid variable is theaddress of the corresponding program variable..NHControl Flow.PPThe.CW whileand.CW loopstatements implement looping.The formeris similar to the same statement in C.The latter evaluates starting and ending expressions yieldingintegers and iterates while an incrementing loop indexis within the bounds of those expressions..P1acid: i = 0; loop 1,5 do print(i=i+1)0x000000010x000000020x000000030x000000040x00000005acid:.P2The traditional.CW if-then-else statement implements conditional execution..NHAddressing.PPTwo indirection operators allow Acid to access values inthe program being debugged.The.CW *operator fetches a value from the memory image of anexecuting process;the.CW @operator fetches a value from the text file of the process.When either operator appears on the left side of an assignment, the valueis written rather than read..PPThe indirection operator must know the size of the objectreferenced by a variable.The Plan 9 compilers neglect to include thisinformation in the program symbol table, so Acid cannotderive this information implicitly.Instead Acid variables have formats.The format is a codeletter specifying the printing style and the effect of some of theoperators on that variable.The indirection operators look at the format code to determine thenumber of bytes to read or write.The format codes are derived from the format letters used by.I db .By default, symbol table variables and numeric constantsare assigned the format code.CW 'X'which specifies 32-bit hexadecimal.Printing such a variable yields output of the form.CW 0x00123456 .An indirect reference through the variable fetches 32 bitsof data at the address indicated by the variable.Other formats specify various data types, for example.CW ian instruction,.CW Da signed 32 bit decimal,.CW sa null-terminated string.The.CW fmtfunctionallows the user to change the format code of a variableto control the printing format andoperator side effects.This function evaluates the expression supplied as the firstargument, attaches the format code supplied as the secondargument to the result and returns that value.If the result is assigned to a variable,the new format code applies tothat variable. For convenience, Acid provides the.CW \eoperator as a shorthand infix form of.CW fmt .For example:.P1acid: x=10acid: x // print x in hex0x0000000a acid: x = fmt(x, 'D') // make x type decimalacid: print(x, fmt(x, 'X'), x\eX) // print x in decimal & hex10 0x0000000a 0x0000000aacid: x // print x in decimal10acid: x\eo // print x in octal000000000012.P2The .CW ++and.CW --operators increment or decrement a variable by an amountdetermined by its format code. Some formats imply a non-fixed size.For example, the.CW iformat code disassembles an instruction into a string.On a 68020, which has variable length instructions:.P1acid: p=main\ei // p=addr(main), type INSTacid: loop 1,5 do print(p\eX, @p++) // disassemble 5 instr's0x0000222e LEA 0xffffe948(A7),A70x00002232 MOVL s+0x4(A7),A20x00002236 PEA 0x2f($0)0x0000223a MOVL A2,-(A7)0x0000223c BSR utfrruneacid:.P2Here,.CW mainis the address of the function of the same name in the program under test.The loop retrieves the five instructions beginning at that address andthen prints the address and the assembly language representation of each.Notice that the stride of the increment operator varies with the size ofthe instruction: the.CW MOVLat .CW 0x0000223ais a two byte instruction while all others are four bytes long..PPRegisters are treated as normal program variables referencedby their symbolic assembler language names.When aprocess stops, the register set is saved by the kernelat a known virtual address in the process memory map.The Acid variables associated with the registers pointto the saved values and the.CW *indirection operator can then be used to read and write the register set.Since the registers are accessed via Acid variables they maybe used in arbitrary expressions..P1acid: PC // addr of saved PC0xc0000f60 acid: *PC0x0000623c // contents of PCacid: *PC\eamainacid: *R1=10 // modify R1acid: asm(*PC+4) // disassemble @ PC+4main+0x4 0x00006240 MOVW R31,0x0(R29)main+0x8 0x00006244 MOVW $setR30(SB),R30main+0x10 0x0000624c MOVW R1,_clock(SB).P2Here, the saved.CW PCis stored at address.CW 0xc0000f60 ;its current content is.CW 0x0000623c .The.CW a ' `format code converts this value to a string specifyingthe address as an offset beyond the nearest symbol.After setting the value of register.CW 1 ,the example uses the.CW asmcommand to disassemble a short section of code beginningat four bytes beyond the current value of the.CW PC ..NHProcess Interface.PPA program executing under Acid is monitored through the.I procfile system interface provided by Plan 9.Textual messages written to the.CW ctlfile control the execution of the process.For example writing.CW waitstopto the control file causes the write to block until the targetprocess enters the kernel and is stopped. When the process is stoppedthe write completes. The.CW startstopmessage starts the target process and then does a.CW waitstopaction.Synchronization between the debugger and the target process is determinedby the actions of the various messages. Some operate asynchronously to thetarget process and always complete immediately, others block until theaction completes. The asynchronous messages allow Acid to controlseveral processes simultaneously..PPThe interpreter has builtin functions named after each of the controlmessages. The functions take a process id as argument.Any time a control message causes the program to execute instructions the interpreter performs two actions when the control operation has completed.The Acid variables pointing at the register set are fixed up to pointat the saved registers, and thenthe user defined function.CW stoppedis executed.The .CW stoppedfunction may print the current address,line of source or instruction and return to interactive mode. Alternativelyit may traverse a complex data structure, gather statistics and then setthe program running again..PPSeveral Acid variables are maintained by the debugger rather than theprogrammer.These variables allow generic Acid code to deal with the current process,architecture specifics or the symbol table.The variable.CW pidis the process id of the current process Acid is debugging.The variable.CW symbolscontains a list of lists where each sublist contains the symbolname, its type and the value of the symbol.The variable.CW registerscontains a list of the machine-specific register names. Global symbols in the target programcan be referenced directly by name from Acid. Local variablesare referenced using the colon operator as \f(CWfunction:variable\fP..NHSource Level Debugging.PPAcid provides several builtin functions to manipulate source code.The.CW filefunction reads a text file, inserting each line into a list.The.CW pcfileandLines 1–500 of 1327. Load more
.TL Acid: A Debugger Built From A Language .AU .I "Phil Winterbottom" .AI .I "Lucent Technologies Inc" .AB .FS \l'1i' .br Originally appeared in .I Proc. of the Winter 1994 USENIX Conf., .R pp. 211-222, San Francisco, CA; and subsequently in the .I "Plan 9 Programmer's Manual, Volume 2 (Second Edition)" . .FE Acid is an unusual source-level symbolic debugger for Plan 9. It is implemented as a language interpreter with specialized primitives that provide debugger support. Programs written in the language manipulate one or more target processes; variables in the language represent the symbols, state, and resources of those processes. This structure allows complex interaction between the debugger and the target program and provides a convenient method of parameterizing differences between machine architectures. Although some effort is required to learn the debugging language, the richness and flexibility of the debugging environment encourages new ways of reasoning about the way programs run and the conditions under which they fail. .AE .NH Introduction .PP The size and complexity of programs have increased in proportion to processor speed and memory but the interface between debugger and programmer has changed little. Graphical user interfaces have eased some of the tedious aspects of the interaction. A graphical interface is a convenient means for navigating through source and data structures but provides little benefit for process control. The introduction of a new concurrent language, Alef [Win93], emphasized the inadequacies of the existing Plan 9 [Pike90] debugger .I db , a distant relative of .I adb , and made it clear that a new debugger was required. .PP Current debuggers like .I dbx , .I sdb , and .I gdb are limited to answering only the questions their authors envisage. As a result, they supply a plethora of specialized commands, each attempting to anticipate a specific question a user may ask. When a debugging situation arises that is beyond the scope of the command set, the tool is useless. Further, it is often tedious or impossible to reproduce an anomalous state of the program, especially when the state is embedded in the program's data structures. .PP Acid applies some ideas found in CAD software used for hardware test and simulation. It is based on the notion that the state and resources of a program are best represented and manipulated by a language. The state and resources, such as memory, registers, variables, type information and source code are represented by variables in the language. Expressions provide a computation mechanism and control statements allow repetitive or selective interpretation based on the result of expression evaluation. The heart of the Acid debugger is an interpreter for a small typeless language whose operators mirror the operations of C and Alef, which in turn correspond well to the basic operations of the machine. The interpreter itself knows nothing of the underlying hardware; it deals with the program state and resources in the abstract. Fundamental routines to control processes, read files, and interface to the system are implemented as builtin functions available to the interpreter. The actual debugger functionality is coded in Acid; commands are implemented as Acid functions. .PP This language-based approach has several advantages. Most importantly, programs written in Acid, including most of the debugger itself, are inherently portable. Furthermore, Acid avoids the limitations other debuggers impose when debugging parallel programs. Instead of embedding a fixed process model in the debugger, Acid allows the programmer to adapt the debugger to handle an arbitrary process partitioning or program structure. The ability to interact dynamically with an executing process provides clear advantages over debuggers constrained to probe a static image. Finally, the Acid language is a powerful vehicle for expressing assertions about logic, process state, and the contents of data structures. When combined with dynamic interaction it allows a limited form of automated program verification without requiring modification or recompilation of the source code. The language is also an excellent vehicle for preserving a test suite for later regression testing. .PP The debugger may be customized by its users; standard functions may be modified or extended to suit a particular application or preference. For example, the kernel developers in our group require a command set supporting assembler-level debugging while the application programmers prefer source-level functionality. Although the default library is biased toward assembler-level debugging, it is easily modified to provide a convenient source-level interface. The debugger itself does not change; the user combines primitives and existing Acid functions in different ways to implement the desired interface. .NH Related Work .PP DUEL [Gol93], an extension to .I gdb [Stal91], proposes using a high level expression evaluator to solve some of these problems. The evaluator provides iterators to loop over data structures and conditionals to control evaluation of expressions. The author shows that complex state queries can be formulated by combining concise expressions but this only addresses part of the problem. A program is a dynamic entity; questions asked when the program is in a static state are meaningful only after the program has been `caught' in that state. The framework for manipulating the program is still as primitive as the underlying debugger. While DUEL provides a means to probe data structures it entirely neglects the most beneficial aspect of debugging languages: the ability to control processes. Acid is structured around a thread of control that passes between the interpreter and the target program. .PP The NeD debugger [May92] is a set of extensions to TCL [Ous90] that provide debugging primitives. The resulting language, NeDtcl, is used to implement a portable interface between a conventional debugger, pdb [May90], and a server that executes NeDtcl programs operating on the target program. Execution of the NeDtcl programs implements the debugging primitives that pdb expects. NeD is targeted at multi-process debugging across a network, and proves the flexibility of a language as a means of communication between debugging tools. Whereas NeD provides an interface between a conventional debugger and the process it debugs, Acid is the debugger itself. While NeD has some of the ideas found in Acid it is targeted toward a different purpose. Acid seeks to integrate the manipulation of a program's resources into the debugger while NeD provides a flexible interconnect between components of the debugging environment. The choice of TCL is appropriate for its use in NeD but is not suitable for Acid. Acid relies on the coupling of the type system with expression evaluation, which are the root of its design, to provide the debugging primitives. .PP Dalek [Ols90] is an event based language extension to gdb. State transitions in the target program cause events to be queued for processing by the debugging language. .PP Acid has many of the advantages of same process or .I local .I agent debuggers, like Parasight [Aral], without the need for dynamic linking or shared memory. Acid improves on the ideas of these other systems by completely integrating all aspects of the debugging process into the language environment. Of particular importance is the relationship between Acid variables, program symbols, source code, registers and type information. This integration is made possible by the design of the Acid language. .PP Interpreted languages such as Lisp and Smalltalk are able to provide richer debugging environments through more complete information than their compiled counterparts. Acid is a means to gather and represent similar information about compiled programs through cooperation with the compilation tools and library implementers. .NH Acid the Language .PP Acid is a small interpreted language targeted to its debugging task. It focuses on representing program state and addressing data rather than expressing complex computations. Program state is .I addressable from an Acid program. In addition to parsing and executing expressions and providing an architecture-independent interface to the target process, the interpreter supplies a mark-and-scan garbage collector to manage storage. .PP Every Acid session begins with the loading of the Acid libraries. These libraries contain functions, written in Acid, that provide a standard debugging environment including breakpoint management, stepping by instruction or statement, stack tracing, and access to variables, memory, and registers. The library contains 600 lines of Acid code and provides functionality similar to .I dbx . Following the loading of the system library, Acid loads user-specified libraries; this load sequence allows the user to augment or override the standard commands to customize the debugging environment. When all libraries are loaded, Acid issues an interactive prompt and begins evaluating expressions entered by the user. The Acid `commands' are actually invocations of builtin primitives or previously defined Acid functions. Acid evaluates each expression as it is entered and prints the result. .NH Types and Variables .PP Acid variables are of four basic types: .I integer , .I string , .I float , and .I list . The type of a variable is inferred by the type of the right-hand side of an assignment expression. Many of the operators can be applied to more than one type; for these operators the action of the operator is determined by the type of its operands. For example, the .CW + operator adds .I integer and .I float operands, and concatenates .I string and .I list operands. Lists are the only complex type in Acid; there are no arrays, structures or pointers. Operators provide .CW head , .CW tail , .CW append and .CW delete operations. Lists can also be indexed like arrays. .PP Acid has two levels of scope: global and local. Function parameters and variables declared in a function body using the .CW local keyword are created at entry to the function and exist for the lifetime of a function. Global variables are created by assignment and need not be declared. All variables and functions in the program being debugged are entered in the Acid symbol table as global variables during Acid initialization. Conflicting variable names are resolved by prefixing enough `$' characters to make them unique. Syntactically, Acid variables and target program symbols are referenced identically. However, the variables are managed differently in the Acid symbol table and the user must be aware of this distinction. The value of an Acid variable is stored in the symbol table; a reference returns the value. The symbol table entry for a variable or function in the target program contains the address of that symbol in the image of the program. Thus, the value of a program variable is accessed by indirect reference through the Acid variable that has the same name; the value of an Acid variable is the address of the corresponding program variable. .NH Control Flow .PP The .CW while and .CW loop statements implement looping. The former is similar to the same statement in C. The latter evaluates starting and ending expressions yielding integers and iterates while an incrementing loop index is within the bounds of those expressions. .P1 acid: i = 0; loop 1,5 do print(i=i+1) 0x00000001 0x00000002 0x00000003 0x00000004 0x00000005 acid: .P2 The traditional .CW if-then-else statement implements conditional execution. .NH Addressing .PP Two indirection operators allow Acid to access values in the program being debugged. The .CW * operator fetches a value from the memory image of an executing process; the .CW @ operator fetches a value from the text file of the process. When either operator appears on the left side of an assignment, the value is written rather than read. .PP The indirection operator must know the size of the object referenced by a variable. The Plan 9 compilers neglect to include this information in the program symbol table, so Acid cannot derive this information implicitly. Instead Acid variables have formats. The format is a code letter specifying the printing style and the effect of some of the operators on that variable. The indirection operators look at the format code to determine the number of bytes to read or write. The format codes are derived from the format letters used by .I db . By default, symbol table variables and numeric constants are assigned the format code .CW 'X' which specifies 32-bit hexadecimal. Printing such a variable yields output of the form .CW 0x00123456 . An indirect reference through the variable fetches 32 bits of data at the address indicated by the variable. Other formats specify various data types, for example .CW i an instruction, .CW D a signed 32 bit decimal, .CW s a null-terminated string. The .CW fmt function allows the user to change the format code of a variable to control the printing format and operator side effects. This function evaluates the expression supplied as the first argument, attaches the format code supplied as the second argument to the result and returns that value. If the result is assigned to a variable, the new format code applies to that variable. For convenience, Acid provides the .CW \e operator as a shorthand infix form of .CW fmt . For example: .P1 acid: x=10 acid: x // print x in hex 0x0000000a acid: x = fmt(x, 'D') // make x type decimal acid: print(x, fmt(x, 'X'), x\eX) // print x in decimal & hex 10 0x0000000a 0x0000000a acid: x // print x in decimal 10 acid: x\eo // print x in octal 000000000012 .P2 The .CW ++ and .CW -- operators increment or decrement a variable by an amount determined by its format code. Some formats imply a non-fixed size. For example, the .CW i format code disassembles an instruction into a string. On a 68020, which has variable length instructions: .P1 acid: p=main\ei // p=addr(main), type INST acid: loop 1,5 do print(p\eX, @p++) // disassemble 5 instr's 0x0000222e LEA 0xffffe948(A7),A7 0x00002232 MOVL s+0x4(A7),A2 0x00002236 PEA 0x2f($0) 0x0000223a MOVL A2,-(A7) 0x0000223c BSR utfrrune acid: .P2 Here, .CW main is the address of the function of the same name in the program under test. The loop retrieves the five instructions beginning at that address and then prints the address and the assembly language representation of each. Notice that the stride of the increment operator varies with the size of the instruction: the .CW MOVL at .CW 0x0000223a is a two byte instruction while all others are four bytes long. .PP Registers are treated as normal program variables referenced by their symbolic assembler language names. When a process stops, the register set is saved by the kernel at a known virtual address in the process memory map. The Acid variables associated with the registers point to the saved values and the .CW * indirection operator can then be used to read and write the register set. Since the registers are accessed via Acid variables they may be used in arbitrary expressions. .P1 acid: PC // addr of saved PC 0xc0000f60 acid: *PC 0x0000623c // contents of PC acid: *PC\ea main acid: *R1=10 // modify R1 acid: asm(*PC+4) // disassemble @ PC+4 main+0x4 0x00006240 MOVW R31,0x0(R29) main+0x8 0x00006244 MOVW $setR30(SB),R30 main+0x10 0x0000624c MOVW R1,_clock(SB) .P2 Here, the saved .CW PC is stored at address .CW 0xc0000f60 ; its current content is .CW 0x0000623c . The .CW a ' ` format code converts this value to a string specifying the address as an offset beyond the nearest symbol. After setting the value of register .CW 1 , the example uses the .CW asm command to disassemble a short section of code beginning at four bytes beyond the current value of the .CW PC . .NH Process Interface .PP A program executing under Acid is monitored through the .I proc file system interface provided by Plan 9. Textual messages written to the .CW ctl file control the execution of the process. For example writing .CW waitstop to the control file causes the write to block until the target process enters the kernel and is stopped. When the process is stopped the write completes. The .CW startstop message starts the target process and then does a .CW waitstop action. Synchronization between the debugger and the target process is determined by the actions of the various messages. Some operate asynchronously to the target process and always complete immediately, others block until the action completes. The asynchronous messages allow Acid to control several processes simultaneously. .PP The interpreter has builtin functions named after each of the control messages. The functions take a process id as argument. Any time a control message causes the program to execute instructions the interpreter performs two actions when the control operation has completed. The Acid variables pointing at the register set are fixed up to point at the saved registers, and then the user defined function .CW stopped is executed. The .CW stopped function may print the current address, line of source or instruction and return to interactive mode. Alternatively it may traverse a complex data structure, gather statistics and then set the program running again. .PP Several Acid variables are maintained by the debugger rather than the programmer. These variables allow generic Acid code to deal with the current process, architecture specifics or the symbol table. The variable .CW pid is the process id of the current process Acid is debugging. The variable .CW symbols contains a list of lists where each sublist contains the symbol name, its type and the value of the symbol. The variable .CW registers contains a list of the machine-specific register names. Global symbols in the target program can be referenced directly by name from Acid. Local variables are referenced using the colon operator as \f(CWfunction:variable\fP. .NH Source Level Debugging .PP Acid provides several builtin functions to manipulate source code. The .CW file function reads a text file, inserting each line into a list. The .CW pcfile and