home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
forth
/
compiler
/
fpc
/
source
/
debug.seq
< prev
next >
Wrap
Text File
|
1991-04-10
|
15KB
|
397 lines
\ 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 HIDDEN ALSO
: SHOWSRC ( --- ) \ Show the source for the current debugging word.
0 save!> nosetcur
savecursor
0 0 AT
['] SRCEEOLCR IS CR
ON> ?DEBUG
DEFCFA @ (SEE)
OFF> ?DEBUG
KEY? 0=
IF #LINE @ SPLIT-L# 1- MIN SPLIT-L# 1- SWAP
?DO CR EEOL
LOOP
THEN
['] CRLF IS CR
0 SPLIT-L# 1- AT >ATTRIB4
." Cont, Done, Forth, Nest, Quit, Skipto, Unnest, Watch, X-srctgl"
EEOL >NORM
restcursor
restore> nosetcur ;
: SRCCR ( --- ) \ Source CR for the debugger, subscreen scroll.
0 SPLIT-L# AT -LINE 0 ROWS 1- AT ;
' SRCCR IS .SRCCR
DEFER .DEFSRC ' NOOP IS .DEFSRC \ display definition source
: SRCON ( --- ) \ Enable source printing durring debugging.
['] showsrc is .defsrc
['] SRCCR IS CCR ;
: SRCOFF ( --- ) \ disable source printing durring debugging.
['] noop is .defsrc
['] CRLF IS CCR ;
SRCOFF
DEFER .WATCH ' NOOP IS .WATCH \ a watch point, do nothing fopr now
DEFER .WATCHER ' NOOP IS .WATCHER \ a place where .watch func is saved
DEFER SETWATCH ' BEEP IS SETWATCH \ allow setting up watch points
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
: WATCHON ( -- )
@> .WATCHER IS .WATCH ;
: WATCHOFF ( -- )
['] NOOP IS .WATCH ;
WATCHOFF \ disable watch points for now
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 /string
repeat ;
: find_dodoes ( a1 n1 -- a2 n2 ) \ find any definition
begin $E8 ( call ) scan
over @rel>abs @rel>abs 'dodoes <> over and
while 3 /string
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 /string
repeat dup 0=
if 2drop
$100 here $100 -
begin find_dodoes over @rel>abs
>body @ r@ <> over and
while 5 /string
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 .watch
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
." Cont, Done, Forth, Nest, Quit, Skipto, Unnest, Watch, X-srctgl:" eeol
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 .watch 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 watchon
else srcoff watchoff
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
'W' of setwatch 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 .watch
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