DDT-11 - Dynamic Debugging Technique on the PDP-11 DDT is a powerful debugging tool on the PDP11 that can control execution of a program or display program or data in a variety of formats. It can display or allow entry of data as MACRO-11 instructions, octal or decimal constants, floating point munbers, ASCII, RAD50, or, in some limited cases, hex or other radices, or bytes of arbitrary length. It can single step through programs, allow execution until breaks, or execute until one or more memory locations changes. It allows users to define symbols and displays addresses either absolutely or relative to symbols. It can read symbol table files to automatically define global symbols too, and caches these symbols internally to speed searches. Where DDT is too big to fit into a task's context, it may be assembled and linked to run in a separate task under RSX11M, RSX11D, RSX11M+, or IAS and to debug another task or a collection of tasks from a debug task, with all facilities intact and available and only minor speed loss. This makes DDT suitable for all PDP11 debugging chores. Under certain conditions, DDT may need to be sure tasks are not shuffled too much, but it can operate in a mode ("pure send/ receive") that does not need any such constraint. It is able to address a task directly, however, considerably faster than it can pseudo-address the task by communicating with a "debug kernel", and in this mode needs to be sure the task does not move until a breakpoint is fully processed. These constraints apply only to DDT debugging one task from another. It should be noted that DDT can operate using pure send and receive data directives between tasks, and in this mode is not sensitive to shuffling/checkpointing, etc. However, single stepping with a watchpoint was measured about 3 times slower in "pure send/receive" mode than in "DDT mapping" mode (50 instructions per second vs. 16 instructions per second, single stepping and examining 1 memory location per step; representative of the speed of handling normal breakpoints, but worse than normal single stepping. Each command in DDT/11 is identical to the PDP-10 version whenever possible. In some cases, DDT/10 commands have been omitted in the interest of saving core and making good sense. The following is a list of the DDT/11 commands: The $ used in the examples below is an ESCape character. For ODT compatibility, the ; (semicolon) character has the same effect as escape. n/ Open word n. Type contents in current mode / Open word pointed to by last typed value n Modify currently open word to be n. Close word. n Modify, close, open next word n^ Modify, close, open previous word n Modify, close, open word pointed to by last typed address n\ Modify, close, examine word n \ Examine word pointed to by last typed value n? Type word n in RAD50 format (forces even address) @ Types out location absolutely addressed by the open location (the same convention as , and the same as the DEC ODT convention for @ sign. ====> Important !!!! <==== Note that the following 9 commands are usually used with 2 escapes (e.g. $$S) to set the modes "permanently" rather than only until the next carriage return. ====> ************** <==== $S Change current mode to instruction type out ("Symbolic") $A Addresses will be typed as absolute numbers ("Absolute") $R Addresses will be typed relative to symbols ("Relative") $C Change current mode to numeric type out ("Constant") $nR Change current radix for $C to n (n read in decimal) $T Change current mode to ASCII text output ("Text") $5T Change current mode to Radix-50 text output $nO Change current mode to n bit byte typeout $H Change to halfword (byte) mode (reset by $5T and $S) Note that the initial modes are $S and $8R. These can be temporarily changed by the above commands and will return to the permanent setting by a carriage return. The settings can be permanently changed by using two altmodes before the mode setting command ($$T sets permanent ASCII mode) n[ Open location n, type as a numeric n] Open location n, type as instruction n! Open location n, do not type value ; Retype currently open word = Retype currently open word as number n= Type value of n as a number _ Retype currently open word as instruction $_ Retype currently open word symbolically i$X Execute instruction i (cannot execute branches or jumps) Note the instruction executes in the context of the target task if multi-task DDT is in use. n$G Start executing program at location n. Default is to start executing at address in JOBSA (start of program) v$nB Set breakpoint n at address v (n from 1 to 8 or can be omitted) a,v$nB Same as above but open address a at breakpoint If two altmodes are used, automatic proceding is enabled. The breakpoint will cause the message to be typed and the program resumed. If you type a character, the automatic proceding will stop. NOTE: If the address a is less than 8 (the number of breakpoints allowed), then macro a will be executed (0 to 8). These macros are defined by the Y command and may consist of any characters to be used as commands. There is however no conditional testing built into DDT commands. These macros are additions to those defined using the $UF, etc. commands and they never echo. 0$nB Remove breakpoint n $B Remove all breakpoints $P Procede from breakpoint n$P Procede from breakpoint n times (without halting) If two altmodes are used, the breakpoint will be proceded from automatically. n$UW Set offset limit to n (used when typing addresses) $1UT Turn on single stepping (break at each instruction) a$1UT Turn on single stepping and open location a at each break If two altmodes are used, the single stepping will be done automatically. NOTE: the same restriction about a less than 8 applies as for breakpoints. $UT Turn off single stepping a: Make current location have symbolic name a v Define macro n as the characters between the &. To enter & use 2 &'s. 0$nY Delete contents of macro n. $nY Execute macro n. Does not echo. n$M Set mask for searches (below) to n ls$W Search core from l to u for word s. ls$E Search core from l to u for effective address s. ls$N Search core from l to u for word not equal to s. addr$UInumber Insert 32-bit floating-point number at addr addr$UJnumber Insert 64-bit floating point number at addr addr$UX EXamine floating point number at addr. Assumed to have precision in D.PRCN (2 or 4 for 32 or 64 bits) which is left over from last $UI or $UJ or set from console. Note that floating AC's are saved/restored only if FPCTL is set nonzero. If so, FPSTAT is FPU status and AC0-AC% are floating AC's. addr$J Display contents of (addr, addr+2) as a 32 bit integer in current radix. addr$1Jnumber Insert number at addr and addr+2 as a 32 bit integer. number is delimited by any character not legal in the current radix. The 32 bit integers are assumed stored as (low order, high order) in memory (addr=l.o., addr+2=h.o.). addr$2Jnumber Insert number (in current radix) at addr as a 16 bit number. This is provided in addition to the usual DDT methods since the DDT parser cannot handle bases higher than 10. Thus, this command gives a means to enter, as well as display, numbers in higher bases, such as hex. $L Close open core image file. Must be done prior to exit from DDT. $1L Prompt for and open core image file to use instead of virtual memory in $UM mode. CD.BLK is (lo,hi) base block number in file (initially 1,0) and CD.BAS is lowest address in file. DDT converts addresses to file relative form and reads or writes. If the /RO switch is used, the file is read only, else read/write, and it must be on SY:. If the /AB switch is used, DDT tries to do read/write logical block on a device directly. $UO Prompt for name of symbol table file. If a file is specified and exists, set to use it to resolve symbols. If file spec is null or does not exist, close existing symbol table file. $1UO will close any open symbol table file too but will erase DDT's internal "cache" of symbols. $UQ leaves that cache intact. $UQ Close symbol table file if any is open. $UM Turn on use of virtual map. Variables PAR0 through PAR7 will be used as APR's for all number entry or displays in any format. Where I/D space support is used, $UM refers to data space annd $1UM refers to instruction space. $UU Turn on virtual mapping and copy current User APR's into maps used by DDT. All addressing will be done via those virtual APR's. $UK Turn on virtual mapping and copy current Kernel APR's into maps used by DDT. All mapping will be done via these APR's. Note that if Kernel I and D space exists, $UK gets kernel D APRs and $1UK gets I space kernel APRs. $UV Use standard DDT virtual mapping (no pseudo maps). This differs from the other commands in that no APR's are used; the others use the APR's that DDT is intialized with, which may be inadequate if the task is checkpointed and moved. DDT initializes in this mode and can, in it, access whatever a normal DDT can access (and conversely). brk#text Fill in text of macro (up to 80 char) with any characters. Text is always read from console and the command terminates, filling in a legal end sentinel, after buffer full or recognition of the second delimiter character, which may be any ASCII character not in the text string. These macros are enabled by the D.MCRO assembly conditional defined. NOTE DDT mapping does not affect program execution; only displays are affected. Modifications to memory will use the current APR's, but breakpoints will not be put into arbitrary memory locations. The $UM, $UV, $UU and $UK commands only exist where the assembly conditional $VMEM was defined and DDT is linked to a common in the I/O page at APR 7. ; The following command is used to point DDT at a task in the system. ; It is automatically used in cases where DDT is debugging another ; task. $ULTSKNAM Read a task name (6 characters maximum) from the console (or macro) and locate its header and mapping information inside RSX11M. Then compute the APR mappings for that task and move them into the locations used by DDT for its pseudo mapping. This option requires that R$XMDB be defined and that DDT be assembled with $VMEM defined and with the appropriate RSX macros (normally [1,1]EXEMC) available for header, TCB, and window block offset definitions. Also, the task using such a version of DDT must have access to the I/O page via APR 7. This option only makes sense on fixed tasks or in systems without checkpointing, but may be useful in those systems for examining or modifying other tasks. The $UM command is needed to actually use the virtual APRs set up by the $UL command; $UL only sets them up for later use. Note that numbers can be as any combination of the following: . " "$ The operators + (addition), - (subtraction), * (multiplication), and ' (division) are evaluated from left to right unless parenthesis are included. The space is treated like a plus except after instructions when it is merely a separator. All input is accepted in lower or upper case and is folded (except for text.) In addition to program symbols, the following are also defined for you: R0-R5 are the user registers. R1/ would open register 1. SP is the user's stack pointer PC is the user's program counter $I is the user status $2I is the status of DDT $M is the mask for searches $Q is the value at the current address $V is the value at the current address with the bytes switched $nB is the address of breakpoint n JOBSA is the starting address of your program. In multi-task DDT, U.PSW and U.DSW are the target task's PSW and $DSW respectively. Then D.R0 thru D.PC are the DDT registers. AC0-AC5 are the FPU registers where $D$FPU was defined at assembly (Note however that instructions still print the symbols R0 through R5 instead of AC0-AC5.) FPSTAT is the FPU status register FPCTL controls FP save/restore. If 0, no save/restore of floating registers occurs. if nonzero, all FPU status is saved across calls. Initially the value of $D$FPU at assembly. FPFMT 2 bytes for number decimals and width fo FP print field D.PRCN is the precision of FP print conversions. It may be 2 or 4 for single precision or double precision outputs. RSXEXT IS RSX-11-M or -D EXIT$S call $$DOS is DOS-11 EXIT call DDTODD is DDT odd addr SST table entry (RSX DDT only) DDTIOT is DDT IOT table entry DDTTRP is TRAP entry (This is frequently assembled as 0 for FORTRAN OTS use) DDTRES is RESERVED INST entry DDTEMT is non-RSX EMT entry D.FILV is number filled in by $Z command (initially 0) (TASK NAME) is start address of task BYE is equivalent to RSXEXT in RSX DDT (in RSX, a control Z also exits DDT.) DDTBGN is the start address of DDT itself PAR0 Is the current virtual memory APR 0. (PDR is always 4K R/W) PAR1 is the current virtual APR 1 PAR2 is current APR 2 PAR3 is current APR 3 PAR4 is current APR 4 (all these are in virtual ($UM) space PAR5 is current APR 5 PAR6 is current APR 6 PAR7 is current APR 7 (must be I/O page for this to work) MEMCTL is the control for memory breakpoints. MEMBPA and MBPVAL are addresses and last seen values for watchpoints which are used if MEMCTL is nonzero. Note D.CT should be -1 and DDT should be in single step mode to use memory watchpoints. The $UZ command establishes those conditions. SR.CTL if 0 allows normal DDT mapping to arbitrary memory areas, and if 1 allows send/receive data directives to be used for communication with a target task (if MU$DBG defined only!) OVRBRK If present, may contain 0 or the address of a special breakpoint. If nonzero, then if a breakpoint occurs from the address in OVRBRK, only the data from OVRBRK will be restored with the original instruction. It is expected that a break at $ALBP2 will be used here (the autoload completion point) so breakpoints may be redefined after an overlay load. Thus, to use this facility, one would load the address of $ALBP2 into OVRBRK, then put a breakpoint at $ALBP2. Then one would insert breakpoints into an overlay and debug normally. When a new overlay occurs, and one reaches the break at $ALBP2, remove all breaks that were defined in the old overlay and insert new ones in the new overlay. Then continue. PRFCTL If 0, turns off profiler (default) or if nonzero turns profiler on. If the profiler is on, then execution will be histogrammed. The address of each breakpoint (typically a single step with many proceeds in the proceed count; -1 is infinite proceed count) will be compared with PRFBAS and if above it will have PRFBAS subtracted from it. The offset will then be shifted RIGHT by PRFSHF bits, and the result converted into a word offset. The word of PRFHST so found will be incremented, provided the offset is within the bound of PRFSIZ. Breakpoint then proceeds normally. Note that watchpoints also enable single step mode and permit execution profiles to be done. Only addresses of instructions will be monitored in this way and the PRFHST array, internal to DDT, may be examined at any time with the normal DDT commands. Since the PC at break is always available, no intertask message overhead occurs with profiler above that of single step overhead. D.BMSK and D.BTST Used to support conditional breakpoints, in the following sense: if the D.BMSK array word corresponding to breakpoint number is nonzero, it is ANDed with the word opened at the breakpoint and if the result is different from the corresponding word in the D.BTST array (both are word arrays generally 9 words long), the breakpoint will be ignored. This is the correct way to allow a "stack" break, by entering the current value of SP into D.BTST and opening SP at each break, then single stepping until you hit the break (D.BMSK should have 177777 in it, of course). This allows one to step over a set of subroutines easily. Up to 160. user symbols (as presently defined) may be entered. . represents the current location. Thus .$1B puts breakpoint 1 at the currently opened location. When your program is executing, the following unexpected traps may occur. NXM! is caused when your program requests a non-existant memory or does a word operation on an odd address. ILG! is caused by an illegal instruction. BPT! is caused by an entry to DDT that is unexpected (i.e. executing the BPT instruction or setting the T-bit). Also TRP! means a TRAP, EMT! means an EMT was seen, and a few others indicate the type of trap. (SEG! means memory protect error.) To include DDT with your task, just include on the input side of the taskbuild. thus, whn your normal TKB would be TKB MYFILE,MYFILE=MYFILE make it look like this: TKB MYFILE,MYFILE=MYFILE,[1,1]DDT/DA DDT will gain control at startup. To start your program, type G where you type the ESC key, not the 5 characters "". To exit prematurely, type BYEG (again the ESC key). A type-in of control Z will also exit DDT. Note that DDT does not prompt with anything! Where DDT is built to do its own echo, it echoes ESC as $. If not built this way, DDT may not look like it echoes everything on VT52 or VT100 terminals, but will still function correctly. Some instruction mnemonics in DDT are nonstandard to reduce the size of the instruction database. The following are the nonstandard mnemonics and their standard counterparts: Nonstd Standard HLT HALT WAT WAIT RST RESET MK MARK FA FADD FS FSUB FM FMUL FD FDIV GD MFPD PD MTPD CC CFCC F SETF I SETI D SETD L SETL LS LDFPS SS STFPS S STST C CLRF T TSTF AB ABSF NG NEGF ML MULF MD MODF AD ADDF LD LDF SB SUBF CM CMPF ST STF DV DIVF SX STEXP SI STCFI SD STCFD LX LDEXP LI LDCFI LF LDCDF This completes the list of nonstandard DDT instruction mnemonics. DDT was derived from the original program of S. Rubin @CMU for stand- alone GDP PDP11s, and extensively modified and extended by G. Everhart for DEC environments, bugfixes, floating point, multi-task use, symbol table reads, hex radix, watchpoints, kernel mode dual mode support, macros, and a few other things. There is a comment in the original that credits an old version of ODT as the starting point S. Rubin used; I haven't been able to find any of that old ODT code! G. Everhart, 1/12/81 A command file DDTBLD.CMD is provided to build DDT more or less reasonably for all operating systems of the RSX/IAS/VMS family. If you need more help, there is some info about the conditionals of DDT assembly in the front of the DDT22.MAC source file, and also a copy of most of this file.