The DDT Debugger for PDP11 ABSTRACT: This document is a beginner's introduction to using DDT. It does not contain all DDT commands, but a "novice subset" sufficient to be useful. WHAT IS DDT DDT is a symbolic debug aid. With existing debug aids like ODT, you can execute programs a bit at a time, but you can display programs only in octal and need to refer continually to maps and listing files. Also there are some numbers (e.g. floating point) that are hard to display; the octal radix is not meaningful. With DDT you can display or enter MACRO-11 instructions, octal or decimal numbers, text, floating point, or other formats, do all ODT functions, and refer to your symbols by name rather than as octal mystery numbers. This allows debugs with only source listings, which need not be recreated with EVERY edit since DDT's instruction display makes it easy to find code sequences you know. Since debug aids sometimes don't fit, a special DDT kernel (DDTKNL) can be built into your program, taking as little as 128 words (more typically 200), and you can debug with DDT in a separate task. Or you can just include DDT in your task's space as you do with ODT. DDT works in any PDP11 on any DEC operating system (even has code for user mode I and D space for RSX11M+ V2), though under RSTS using RT11 or RSX emulation its operation is not tested. The debugging from a separate task works under RSX11M, M+, or IAS (though under IAS the tasks must run realtime). Descriptions here will be RSX oriented. GETTING STARTED with DDT To first use DDT, you must include a copy of DDT into your task with the taskbuilder (TKB). We will assume it fits first. You include DDT as a debug aid by specifying it with the /DA switch on the INPUT side of your taskbuild command line (or, with the /DA switch in the root of your .ODL file). That is, you would use a command like TKB>myfile.tsk,myfile.map,myfile.stb=myfile,mysubs1,mysubs2,...,[1,1]DDT/DA which will include DDT from [1,1] (substitute another UIC if that is where DDT.OBJ is) and set it up as a debug aid. Note you do NOT specify /DA on the output side of the TKB command line; that will load ODT and cause conflicts. DDT is built by running DDTBLD.CMD and answering questions; it is assumed your system manager has done this and the DDT.OBJ is your "system standard" DDT, a "1-task" DDT version. Since DDT can be rather large, if you get an error message like "ADDRESS SPACE OVERFLOW - ALLOCATION DELETED" your task is too big for DDT to fit. Since this happens a lot with DDT on large programs, there is a special DDT kernel called (mysteriously enough) DDTKNL which will allow your task to be built and debugged with most of DDT in a separate task. If you use DDTKNL, just replace the "[1,1]DDT/DA" with "[1,1]DDTKNL/DA" in your command lines. When TKB finishes, if DDT is in your task space you can just run the task and DDT will be active. If DDTKNL is used, you must activate DDT22M first. To run DDT22M, type RUN [1,1]DDT22M/TASK=DDT22M (or the equivalent if DDT22M is either an installed task or in another UIC). Then type UM and then G to start DDT22M. The "" means the ESCAPE key (octal 33), echoing as $, not the 5 characters shown. In the following, the "$" character will be used to mean ESCAPE, and NOT the literal "$" character (that is, it will represent ASCII code 33, not ASCII code 44). Now your task is ready to run. (Note some versions of DDT22M auto-start). Then run your task. Once DDT22M types out a message, type $UM (escape, UM) to ensure DDT22M is looking at the target task. Now you can pretend you are debugging from within your task; most things will be the same. The $UM command tells DDT to use the remotely Mapped task's space for areas to examine/modify. It is undone by the $UV command which tells DDT to use its own Virtual address space. These commands switch address spaces. GENERAL CONSOLE FEATURES DDT handles the console in a somewhat nonstandard way. When it starts, it types a message out, but does NOT prompt. That is, it will NOT type "-" the way ODT does to say it is waiting for input; it just waits. You type to it (in either case; DDT is not case sensitive) and DDT acknowledges correct actions by typing a tab (actually it types from 1 to 7 spaces). Thus, several lines may be placed on a line. If you type a "delete" or "rubout" (ASCII 177) character, DDT will type a "XXX" and wait for you to retype the whole command. It will NOT allow single character corrections as RSX does; its parser is much too simple for that. It is inportant that you realize DDT will act as soon as you enter a command. There is no "command terminator" such as a carriage return or double escape to start the command. All you have is the DDT standard acknowledgement of completion by typing a tab (actually, some spaces). If DDT didn't type the tab, most likely something went wrong. DDT is picky about syntax and not very helpful about errors. It types U for an undefined symbol, and ? for most other errors. FURTHER SETUP Your program is permitted to use the TRAP or EMT or other trap instructions. If it does, zero locations DDTTRP, DDTEMT, or similar names. Some versions of DDT will not catch TRAP instructions automatically since FORTRAN and F4P use them. (If using DDTKNL, forget this; you change what traps DDTKNL gets by editing and reassembling DDTKNL.) Use one of the commands below to put a zero into the location named DDTTRP or DDTEMT for TRAP and EMT respectively. EXAMPLES If you run DDT as part of your task, your input might look like this, assuming you have a map and subroutine MUMBLE is the one to be debugged. Comments at the right are not typed, but are here to explain individual steps. The , , or symbols are used to represent the RETURN, LINEFEED, or ESCAPE keys. Notice that the commands "/" (open in current mode, default instruction mode), "[" (open as numeric, default octal), and (close, open next) are used with some othjer commands below. We will describe these commands in detail later. For the present, the comments describe what is happening. >RUN MYPROG Run the task to be debugged DDT-11 V004A RSX/FPU DDT prints identifier. (This tells some available features in DDT, in this case that floating point display is available.) 31642B Set a breakpoint at MUMBLE+62 G Start the task ... MUMBLE+62 >> 1B Eventually reach the breakpoint R2[3274 Examine R2 R1[1 Examine R1 in octal, find 1 R5[32740 [31 Examine R5, find it contains 32740. Next "[" examines location 32740 and finds it contains 31. MUMBLE+62/ MOVB (R4)+,(R0)+ Examine 3 instructions starting at MUMBLE+64/ JSR PC,35776 ; 2 WORDS the breakpoint address MUMBLE+70/ SOB R0,MUMBLE+20 to check code. R0[4 Examine R0 in octal here ... and so forth to set up for next breakpoint P Proceed from the breakpoint. If using 2 - task DDT, you will operate similarly, but the first few steps of a debug session will look like this (assuming there is a runnable DDT22M in LB:[1,1]): >RUN LB:[1,1]DDT22M/TASK=DDT22M The "/TASK=DDT22M" MUST be there! DDT-11 V004A RSX/FPU/MTSK DDT22M identifies itself UM Set up DDT22M to examine the target task space once it gets a breakpoint G Start up DDT22M. Note the terminal is NOT attached, so you can now proceed. >ACT ...MCR DDT22M Check that DDT22M is really active (optional) >RUN MYPROG Run your task as above TT7 BGN22M+1536 >> BPT! Get startup message of a BPT to DDT 31642B Set a breakpoint at MUMBLE+62 G Start the task ... The rest of the session goes as above. When done with the session, type ABORT DDT22M to kill the debugger. With DDT22M, it will frequently be possible to use a .STB file to define locations automatically. Thus one would issue a command like UO .STB FILE:MYPROG You just type MYPROG (.STB assumed) MUMBLE=31642 DDT evaluates MUMBLE from file FUBAR=35776 and also value of FUBAR So now you can examine MUMBLE symbolically: MUMBLE+62/ MOVB (R4)+,(R0)+ Examine 3 instructions starting at MUMBLE+64/ JSR PC,FUBAR ; 2 WORDS the breakpoint address MUMBLE+70/ SOB R0,MUMBLE+20 to check code. Note that the .STB file is closed when DDT cannot find a value for a named symbol. It may be re-opened with the UO command, and symbols are cached. Basic DDT Commands The following are a "basic subset" of DDT commands. DDT has a large set of commands, most of which are not needed for basic user interaction. A number of these set "modes" governing some details of other commands (e.g., default typeout format). LABELS: A DDT label is any 6 or less alphanumeric characters (with . and $ permitted also). You may refer to a location in several ways: * LABEL or LABEL+nnn or LABEL-nnn (nnn a number) or * nnnnnn (an octal number) or * nnnnn. (a decimal number). Where the term "address" is used below, it means any of the above. Where a LABEL is used, it must be defined first; DDT is not prescient. The commands are grouped into commands that display memory, commands that control execution, and utility commands (mainly for control of internal DDT options). I. DDT Commands that Display or Modify Memory address/ (open address in current mode) This command will display the contents of the word (or up to 3 words in instruction mode) viewed in the current mode. These modes may be MACRO-11 instructions, octal numbers, decimal numbers, ASCII text, or RAD50 packed text (as the most common selections). The default when DDT starts is to display instructions. DDT will tab over to the right when the location is displayed, awaiting a further command. The normal ones are to possibly insert a new value, then type either or to close the location (and open the next if ). New values are specified as one of MACRO-11 instruction Octal number (if default radix is unchanged) Decimal number. (period after a number means it is in decimal) "'cc' i.e., double quote, delimiter, 2 ASCII characters, then the same delimiter again, inserts the 2 characters in ASCII into the location. "'ccc' i.e., double quote, escape, delimiter, 3 RAD50 characters, delimiter, insert the 3 characters in RAD50 into the location Note that an instruction may modify up to 3 words. Several commands change the modes used for the / command. (Note that using a single will allow reopen in a new mode until a is entered; the forms given are effective until changed.) S (Symbolic mode) This command changes the mode to symbolic instruction mode, i.e., MACRO-11 instructions. DDT starts in this mode. A (Absolute addresses) This command causes any numeric symbol type outs to appear as "pure" numbers instead of offsets from the next lower defined label if there is a label whose value is "close" to that number (this is defined as 128 or less at start.) R (Relative addresses) This command causes numbers to be typed relative to the next lower symbol if that symbol is "close" (within 128) before the number. Note that the numeric value may always be seen by typing "=" (equal sign) to print as (normally) pure octal. T (Text typeout) This command causes the / command to display memory as ASCII text. H (Halfword typeout) This command causes / to display bytes. It is reset by the S or the 5T commands. Normally the address for / is expected to be even unless in this mode. 5T (RAD50 typeout) This command causes / to display memory as unpacked RAD50. address[ (Open address as numeric) This command displays the contents of address in numeric radix, normally octal. (There is a command to change display radix which is not covered here.) A second [ to a displayed address will display the contents of where it points. That is, if you have a construct like: FOO: .WORD BAR ... BAR: .WORD MUMBLE ... MUMBLE: .WORD 345 you can display the chain like this: FOO[BAR [MUMBLE [345 Note that the next address for the command remains FOO+2, however. The @ command may be used to change this. The command 10R will change the display radix to decimal and the command 8R will change it to octal. The 16R changes the radix to hex, but not all numbers can be handled. This arises due to DDT's inability to distinguish symbols from hex numbers beginning in A through F. There are extended commands able to handle hex more consistently. address? (Display address in RAD50) This command displays the address in RAD50. It also forces the address to be even by zeroing the low bit. Another group of display commands are used to terminate the display and modify sequence. The most commonly needed are the following: [number] (modify and close location) This command will insert the number (instruction, ASCII or RAD50 text, or whatever) in the location given and close the location, terminating the command. If no number is entered, the location is simply closed. THIS IS IMPORTANT! If you could not close a location, the next address you wished to examine might be inadvertently placed in the last location. It is essential to close a location before beginning work on another one. [number] (modify and close location, open next location) This command first performs the function of , i.e., optionally modifies the currently open location and then closes it. It then opens the next location in the same way as the last and displays it and its contents. Note that the "next" location depends somewhat on how the display is set up. A byte display will advance by 1, word displays by 2, and instructions may show a next location that is 1, 2, or 3 words later. The insertion of an instruction is not done until a terminating command is given, even if it is 2 or 3 words long. Thus, a "delete" (rubout) keyin will abort it even if most of the instruction is typed in. As an aside, use of ^ rather thal will back up but always by 1 word or byte. @ (close location, open location addressed) This command closes the current address and opens the address it points to. This is handy for following a pointer and quickly examining a table it points to. II. DDT Commands that Control DDT Options addressUO (Prompt for symbol table file) This command allows DDT to read symbol table files to try to resolve symbols. The files are closed by UQ or when an undefined symbol occurs. Thus, it is good practice to use the UO command and answer the ".STB FILE:" prompt with the name of your .STB file, then immediately use the = command to get DDT to evaluate symbols. An example would be something like this: $UO .STB FILE:msx.stb s.rsav=23442 s.rres=23462 mx.stl=1076 mx.tbl=1104 state4=13206 At this point, the named symbols are known to DDT and can be used. DDT caches about 20 symbols from the .STB file in memory, permitting this. III. Commands to DDT for Controlling Program Execution addressB (Insert Breakpoint) This command sets a breakpoint at the given address. That is, the program will stop execution when it reaches that instruction and DDT will print a message indicating where it is and allow user examination or modification of memory. Note further that DDT breakpoints must be on instructions. Breakpoints on data, or on instruction words other than the first of an instruction, will not ever be effective, and will probably result in incorrect execution as well. (DDT replaces the instruction with a trap unless in single step mode, so the trap must be executed to be effective.) Breakpoints may be on any instruction except an RTT or RTI instruction. Note that you hit a breakpoint BEFORE the instruction you "break" is executed. It will be executed when you proceed. B (Remove all breakpoints) This command removes all breakpoints. Note that to remove a single breakpoint 0 to 7, setting its address to 0 does this (the comand would be 03B to remove breakpoint 3 only.) You run out of breakpoints after number 7 and this lets you clear them out to reuse them at other addresses. P (Proceed from breakpoint) This command resumes execution of a program after a breakpoint. There is a variant to allow n passes through the break before any type-out is done. You cannot Proceed after a fatal error however; you can only use the Go command (below). G (Start Program at default start address) This command just starts the program at its default start address from the taskbuilder (recorded in the cell JOBSA in DDT and available in that name. Normally this address is labelled BGN too and can be examined in that form. It may be called BGNTnn at times as well. addressG (Start program at address) The address$G command (Go) starts execution of a program at the address given. It is legal anytime the program is stopped for any reason. 1UT (Turn on single stepping) The $1UT command turns on single stepping by arranging a breakpoint after every instruction. (It executes all instructions with the T bit set.) You get a breakpoint message for ficticious breakpoint 8 after each instruction, and use the Proceed command to execute the next instruction. This mode is handy if you know the program is leaping off into space somewhere and you want to find out where it does it. UT (Turn off single stepping) This command restores normal operation and turns off single step mode. You need to be in the normal mode for exiting to work normally. Other Useful Features Not Described: DDT is able to watch up to 8 locations (more by reassembly) while executing a program and generate a memory breakpoint whenever any of the locations changes value. If something in your program is clobbering a part of memory, this command (the UZ command) allows you to find the culprit provided it doesn't clobber DDT first. There is logic in DDT to check some memory address when a break is reached and skip the breakpoint unless that address, ANDed with a mask, is equal to a test pattern. This is good for breaking on a single bit or a few bits changing where the content of a full word is not of interest. Obviously, one can go very far providing conditional breaks, but DDT does only this, a fairly simple test. DDT can display or enter 2 or 4 word floating point numbers if built with that support, and can examine or modify floating accumulators (internally named AC0 through AC5). There are several control words to control this. DDT is able to display 32 bit integers in any radix, or enter them in any radix (up to 36; beyond radix 36 it gets silly). The storage convention it uses is that of FORTRAN. DDT can examine any area of physical memory or any file on disk as though that file were memory, providing a symbolic ZAP. It can also do nonfile structured modifications of disks, or open files or disks in read-only mode. DDT has support for a special breakpoint in overlay load code (symbolic location $ALBP2) that will not modify overlays, allowing that (and only that) break to signal the user to remove old breakpoints and insert some that are meaningful to the new overlay. Automatically Defined Variables in DDT When you start in DDT a number of variables are defined for you automatically. Among them are the following, which are examined or modified with ordinary memory examine/modify commands as shown above: R0 through R5, SP, and PC - These are the PDP11 general registers as normal in MACRO-11. $DSW - The RSX Directive Status Word at the break I - The program's PSW 2I - DDT's PSW AC0 through AC5 - FPU accumulators JOBSA - Word holding program start address BYE - Address in DDT to start at to exit program. (Also may be reached by typing control Z). D.FILV - Word holding pattern (initially 0) to be filled in by the $Z (memory Zero) command. - The start address of the task DDTEMT - Address for DDT to use for non-RSX EMTs. Zero to allow task access to these. DDTRES - Address for trapping reserved instructions Zero to allow task access to these. DDTTRP - Address for trapping task TRAP instructions. Zero to allow task access to these. DDTIOT - Address for trapping task IOT instructions. Zero to allow task access to these. DDTODD - Address for handling odd address errors. Zero to allow task access to these. DDTBGN - Start address of DDT itself.