home *** CD-ROM | disk | FTP | other *** search
- \ DEBUG.SEQ A high level debugger Enhancements by Tom Zimmer
-
- \ The debugger is designed to let the user single step the
- \ execution of a high level definition. To invoke the
- \ debugger, type DEBUG XXX where XXX is the name of the
- \ word you wish to trace. When XXX executes, you will get
- \ a single step trace showing you the word within XXX that
- \ is about to execute, and the contents of the parameter
- \ stack. This debugger works by patching the NEXT routine,
- \ so it is highly machine and implementation dependent.
-
- ONLY FORTH ALSO DEFINITIONS BUG ALSO
-
- headerless
-
- VARIABLE DBSEG
- VARIABLE DBOFF
- VARIABLE CNT
- VARIABLE 'DEBUG ( Code field for high level trace )
- DEFER DBG.S ' .S IS DBG.S \ default DBG.S to the systems .S
- DEFER SKIP_TO ' NOOP IS SKIP_TO \ allow skipping to later point in
- \ definition.
-
- LABEL FNEXT ( Fix the >NEXT code back to normal )
- MOV AX, # $AD26 \ ES: LODSW
- MOV >NEXT AX
- MOV AX, # $E0FF \ JMP AX
- MOV >NEXT 2+ AX
- RET END-CODE
-
- LABEL DNEXT ( The Debugger version of a normal >NEXT )
- ES: LODSW JMP AX
- END-CODE
-
- LABEL DEBNEXT
- MOV AX, ES
- CMP AX, DBSEG \ does SEG match?
- 0= IF MOV AX, IP
- CMP AX, DBOFF \ is offset greater
- >= IF INC CNT
- CMP CNT # 2 \ gone through twice?
- 0= IF MOV CNT # 0
- CALL FNEXT
- PUSH IP
- MOV AX, 'DEBUG
- JMP AX
- THEN
- THEN
- THEN JMP DNEXT
- END-CODE
-
- CODE PNEXT ( -- )
- MOV AL, # $0E9
- MOV >NEXT AL
- MOV AX, # DEBNEXT >NEXT 3 + -
- MOV >NEXT 1+ AX
- NEXT C;
-
- headers
-
- FORTH DEFINITIONS ALSO HIDDEN ALSO
-
- CODE UNBUG ( -- )
- CALL FNEXT
- NEXT C;
-
- BUG DEFINITIONS
-
- headerless
-
- CREATE DSTK 100 ALLOT DSTK 100 ERASE
-
- variable slowly
- variable dcnt
- variable dbcfa
-
- \ ' >NAME.ID @REL>ABS CONSTANT 'DOCOL
- ' KEY @REL>ABS CONSTANT 'UDEFER
- ' BDOS @REL>ABS CONSTANT 'DEFER
- ' FORTH @REL>ABS @REL>ABS CONSTANT 'DODOES
-
- 0 value segabove \ segment of routine above current
-
- : find_: ( a1 n1 -- a2 n2 ) \ find any definition
- begin $E9 ( jmp ) scan
- over @rel>abs 'docol <> over and
- while 3 -3 d+ 0 max
- repeat ;
-
- : find_dodoes ( a1 n1 -- a2 n2 ) \ find any definition
- begin $E8 ( call ) scan
- over @rel>abs @rel>abs 'dodoes <> over and
- while 3 -3 d+ 0 max
- repeat ;
-
- : seg>cfa ( seg -- cfa f1 ) \ find cfa given the physical segment
- xseg @ - >r
- $100 here $100 -
- begin find_: over >body @ r@ <> over and
- while 5 -5 d+ 0 max
- repeat dup 0=
- if 2drop
- $100 here $100 -
- begin find_dodoes over @rel>abs
- >body @ r@ <> over and
- while 5 -5 d+ 0 max
- repeat
- then r>drop ;
-
- : n>name.id ( cfa --- )
- on> ?defattrib >name.id
- off> ?defattrib ;
-
- : next_word@ ( -- cfa )
- dbseg @ pfasav @ @L ;
-
- : d.id ( -- ) \ debugger id dot
- ccr
- save> base hex
- dbseg @ 4 u.r
- pfasav @ 3 u.r
- restore> base
- dcnt @ 0max 16 mod spaces
- next_word@ dup @rel>abs
- case
- 'docol of ." : " endof
- 'udefer of ." Ud " endof
- 'defer of ." d " endof
- over
- case
- ['] execute of ." e " endof
- ['] perform of ." p " endof
- ['] exec: of ." e: " endof
- 4 spaces
- drop
- endcase
- drop
- endcase
- n>name.id 16 nlen @ - spaces ;
-
- : setdebug ( cfa1 cfa2 -- ) \ cfa1 is for name displaying
- \ cfa2 is for debugging
- swap defcfa !
- dup dbcfa !
- >body @ +xseg dbseg !
- off> pfaline off> #empty
- slowly off 1 CNT ! DBOFF OFF ;
-
- : >user@ ( cfa1 -- cfa2 )
- >body @ up @ + @ ;
-
- : DSTK0 DSTK 100 ERASE DCNT OFF ;
-
- : >DS DCNT @ DSTK + ! 2 DCNT +! ;
-
- : DS> DCNT @ 2 < 0= IF -2 DCNT +! THEN DCNT @ DSTK + @ ;
-
- : nest1 ( cfa1 cfa2 -- ) \ save current debug and nest to
- ccr \ "cfa2". display "cfa1".
- over dup h. n>name.id
- ." nesting "
- dbcfa @ >ds
- defcfa @ >ds
- setdebug ;
-
- : ?docol ( cfa -- f1 )
- @rel>abs 'docol = ;
-
- : ?nest ( cfa -- ) \ try to nest the word "cfa"
- recursive \ this is a recursive definition
- dup @rel>abs
- case
- 'docol of dup nest1 endof
- 'udefer of >user@ ?nest endof
- 'defer of >body @ ?nest endof
- >r
- case
- ['] execute of dup ?nest endof
- ['] perform of dup @ ?nest endof
- ['] exec: of dup 1+ 2*
- dbseg @ pfasav @ rot +
- @L ?nest endof
- \ *** DOES> test ***
- dup @rel>abs @rel>abs
- ['] forth @rel>abs @rel>abs =
- if dup dup @rel>abs nest1
- else ccr
- dup h. dup n>name.id
- ." Is not debugable "
- then
- drop
- endcase
- r>drop
- endcase ;
-
- : unnest1 ( -- )
- off> pfaline
- off> #empty
- slowly @
- if .defsrc
- then off> slowly
- dcnt @ 4 >=
- if ds> ds> setdebug
- then ;
-
- : ?unnest1 ( -- )
- next_word@
- case
- ['] unnest of unnest1 endof
- ['] exit of unnest1 endof
- ['] ?exit of dup if unnest1 then endof
- drop
- endcase ;
-
-
- \ Type "?" while in the debugger to display the following line;
-
- \ C-cont, D-done, F-forth, Q-quit, N-nest, U-unnest:
-
- \ The commands are available while debugging, as follows;
-
- \ C-cont Continuous, scrolls through words as they
- \ are executed, stop by pressing <return>.
- \ D-done We are Done debugging, allow normal execution
- \ to continue.
- \ F-forth Allow entry of Forth commands, until a <return>
- \ is pressed on an empty command line.
- \ P.S. don't make any typing errors or you will
- \ fall out of the debugger.
- \ Q-quit Quit the debugger, and unpatch the debug word.
- \ Returns to Forth.
- \ N-nest Nest into the current definition the debugger
- \ is sitting on, if it is a ":" definition, else
- \ issue an error message but don't abort.
- \ U-unnest Unnest from the current word being debugged, the
- \ debugger will re-enter when the word finishes
- \ executing, and pops up one level to the word that
- \ called it. You cannot Unnest without Nesting.
-
- : get-command ( --- c1 )
- begin ." ?> "
- (key) upc 0 '?' 2 pick =
- if ccr
- ." C-cont, D-done, F-forth, N-nest, Q-quit, S-skipto, U-unnest, X-source-on/off: "
- 0=
- then 'F' 2 pick =
- if 2>r
- ccr
- ." Press <Enter> on an empty command line to continue debugging."
- begin ccr dbg.s ." ->"
- query #tib @
- while interpret
- repeat 2r> 0=
- then
- while drop d.id repeat ;
-
- 0 VALUE SAVESEG
-
- : trace ( ip - )
- pfasav ! dbg.s d.id
- slowly @ 0= if .defsrc then
- 2r> 2r> over =: segabove 2>r 2>r
- ?unnest1
- slowly @ 0= (key?) or
- if slowly off get-command
- case
- 'C' of slowly on endof
- 'N' of next_word@ ?nest endof
- 'X' of @> .defsrc ['] noop =
- if srcon else srcoff then endof
- 'D' of off> pfaline off> #empty
- -1 pfasav ! exit endof
- 'S' of skip_to endof
- 'U' of dcnt @ 4 >=
- if ds> ds> setdebug
- else segabove seg>cfa \ -- cfa f1
- if dup @rel>abs @rel>abs
- 'dodoes =
- if ccr
- ." Definition NAME may not be correct, this is one word of a class of words."
- ccr
- dup @rel>abs
- setdebug
- else dup setdebug
- then
- else drop
- ccr ." Couldn't find CFA "
- then
- then endof
- 'Q' of -1 pfasav !
- off> pfaline off> #empty
- true abort" unbug" endof
- drop
- endcase
- else 3 spaces
- then
- pnext ;
-
- ' TRACE 'DEBUG !
-
- : %skip_to ( -- ) \ set point to skip to
- save> pfasav
- 0 split-l# at >attrib3
- ." Use + and - to move the hilighted word to the point where you want to stop "
- eeol
- 0 split-l# 1+ at >attrib3
- ." Press Enter when done, or ESC to cancel skip " eeol >norm
- begin .defsrc
- key upc
- case
- '+' of 2 pfasav +! false endof
- '-' of pfasav @ 2- 0max pfasav ! false endof
- ( ESC ) 27 of true endof
- ( Enter ) 13 of pfasav @ 2- 0max DBOFF ! true endof
- drop false beep
- endcase
- until
- restore> pfasav ;
-
- ' %skip_to is skip_to
-
- headers
-
- FORTH DEFINITIONS
-
- : adebug ( a1 --- )
- debugable \ convert inline next to jmp next for debugger.
- dstk0 \ clear debugger stack
- ?nest \ try to nest into definition
- dcnt @ 0= abort" Aborting.. "
- dstk0 \ clear debugger stack again
- ." Debugger ready."
- pnext ; \ set debugger active
-
- : debug ' adebug ;
- : dbg >in @ debug >in ! ;
-
- behead
-
- ONLY FORTH ALSO DEFINITIONS
-
-
-