Debugger Primitives Instruction Breakpoints Most basic type of break Generally handled via modifying code Can cause problems if mem protected. Access controls violation on some machines (access instruction space as data) Restrictions on Where Not on RTI or RTT on PDP11 Must be on Instruction Boundary Where no T bit or similar aid present, done via interpretation or simulation. May prevent traps on calls or jumps. (PDP9, PDP10). Only kind of break in ODT. Won't handle clobbered data very well by itself. Execution Control Some Debuggers have none ... only monitor execution. (HOL debuggers often this way; scope changes too hard to do otherwise) Most complete debuggers allow start anywhere and single or multiple step operation. Single step best in HOL debuggers where it corresponds to a source statement. May be many instructions. Lends itself to support via runtime system. Easiest to know where to start if source lines are somehow labelled. Frequent in HOL debuggers, less so in assembler debuggers. Can introduce errors by starting at wrong spots. Memory Breakpoints Watchpoints Step until a memory location changes Limitations on stepping through some instructions a problem. Slow Needs no special hardware; can be done wherever there is a decent instruction breakpoint. Hardware May have limitations when cache is used, or only a few locations (most commonly 1) may be monitorable. Can catch read as well as write access. Fast, efficient. Interpretation Slow (interpret instructions)... worse than watchpoints May be only way to debug if machine has sufficient limitations. Can catch any kind of access, but huge space and time cost. Memory Display Numeric (various formats) Should support all formats known to machine or language. Common radices need to be there too. Text Not only ASCII, but any special packings are helpful (e.g. RAD50 on PDP11). Structures Stacks Heaps Call Sequence Tracebacks Arrays / Trees / Lists / etc. Language Specific Need to know what language, compiler detail May involve access restriction problems, especially where hardware attempts to keep things like calling sequences out of user space. Can be expensive for more than a few languages. Not a thing typical of user efforts, as a new compiler may not fit a debugger's scheme unless orchestrated. Memory Display (Continued) Code Display of code is fairly basic, needed to help sort out effects of optimizers. Octal / Hex Simplest displays, hardest to use for code. Instruction (assembler) Better than just octal or hex, no language dependence, and reasonably compact. For HOL programmer, requires listing to correlate code with source. Assembly language may even be a detriment to the HOL programmer unless he knows machine well. HOL Most useful to HOL programmer. Susceptible to errors from optimizers. Highly language specific Reverse compilation is generally prohibitive. As a practical matter, need compiler to save source info somewhere. Pointer to src file can allow display of actual source. Almost never done because source listing is as informative. Use line numbers in source instead, needed for traceback already. Symbolic Names Needed for HOL debugging (helpful for any debugging). Usually extended to include line numbers, routine names, and code as well as variable names. Best to include variable type (simplify display). How to Arrange Globals are generally free, needed for linking; Internal symbols the issue Compiler/linker save them Process listings to generate them again (FDT) Process task images to capture traceback info. Replace parts of runtime systems to allow generation of the info. Memory Modification Same set of issues as for display; tightly coupled. Instruction changes have special problems in the case of HOLs. May also modify following instructions if not careful. Size and Speed Costs Memory (16 bit limitation) Debuggers in Task Space may not fit. Less a problem on 32 bit machines. Serious on smaller ones. Speed Breakpoints may slow down process, even where no console activity is needed. Especially bad where instructions are single stepped, where conditional breaks are used, or where instructions are interpreted. Gets worse as debugger is moved to another task or CPU. I/O System Interactions Program monitoring I/O may interfere with the program's I/O to the console. File interaction may produce errors (e.g., by using up file system in-task pools). Internals on PDP11 How a Breakpoint is Implemented BPT on instruction Replace instruction, execute with T bit set Replace BPT when T bit traps Extensions for RTI/RTT Inspect code for RTI/RTT and set T bit of task stack Moving to Different Tasks Saves most of space problem... debug kernel can be 128 words long (with some limitations). Serves to move context for traps out of task. Target gets trap Target sends message to debugger giving code, info Target suspends itself Debugger gets message Debugger accesses target space (may involve messages) Debugger sends Target message with new PS,PC Debugger resumes Target Target now starts using new PS/PC On single processor, debugger can "peek" at target space or use messages to send instructions back (send instructiopns in messages and PC to point at them). Debugging from Separate Processors Once a debugger can use messages for all communication to its target, it can send the messages over a network too. Characteristics of the Multi-Task Model for Debugging Some Interaction with Intertask Communications Debugger must not take all of message channel Only Tasks Reaching Breaks stop; others go on. Can find non-handshaking communications, avoid deadlocks by finding during debug Can fail systems where handshaking is impossible and where a break should stop everything. Some debuggers (MDT for instance, a modified XDT) stop the whole system at break Better simulation for realtime (in some cases) Not usable in shared environment Schemes so far assume specially built tasks with kernels; possible to debug unprepared tasks with some exec support and smarter debugger (system saves registers, PS, PC too).