PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/test/hrc/forth/full/fth.trace.fth

https://github.com/mediogre/colorite
Forth | 423 lines | 391 code | 32 blank | 0 comment | 10 complexity | 81177e0a58ce9c917542d9a629615c4f MD5 | raw file
  1. \ @(#) trace.fth 98/01/28 1.2
  2. \ TRACE ( <name> -- , trace pForth word )
  3. \
  4. \ Single step debugger.
  5. \ TRACE ( i*x <name> -- , setup trace for Forth word )
  6. \ S ( -- , step over )
  7. \ SM ( many -- , step over many times )
  8. \ SD ( -- , step down )
  9. \ G ( -- , go to end of word )
  10. \ GD ( n -- , go down N levels from current level, stop at end of this level )
  11. \
  12. \ This debugger works by emulating the inner interpreter of pForth.
  13. \ It executes code and maintains a separate return stack for the
  14. \ program under test. Thus all primitives that operate on the return
  15. \ stack, such as DO and R> must be trapped. Local variables must
  16. \ also be handled specially. Several state variables are also
  17. \ saved and restored to establish the context for the program being
  18. \ tested.
  19. \
  20. \ Copyright 1997 Phil Burk
  21. anew task-trace.fth
  22. : SPACE.TO.COLUMN ( col -- ) out @ - spaces ;
  23. : IS.PRIMITIVE? ( xt -- flag , true if kernel primitive )
  24. ['] first_colon < ;
  25. 0 value TRACE-BEGWORD_IP \ Instruction pointer begining of words
  26. 0 value TRACE_IP \ instruction pointer
  27. 0 value TRACE_LEVEL \ level of descent for inner interpreter
  28. 0 value TRACE_LEVEL_MAX \ maximum level of descent
  29. private{
  30. \ use fake return stack
  31. 128 cells constant TRACE_RETURN_SIZE \ size of return stack in bytes
  32. create TRACE-RETURN-STACK TRACE_RETURN_SIZE 16 + allot
  33. variable TRACE-RSP
  34. : TRACE.>R ( n -- ) trace-rsp @ cell- dup trace-rsp ! ! ; \ *(--rsp) = n
  35. : TRACE.R> ( -- n ) trace-rsp @ dup @ swap cell+ trace-rsp ! ; \ n = *rsp++
  36. : TRACE.R@ ( -- n ) trace-rsp @ @ ; \ n = *rsp
  37. : TRACE.RPICK ( index -- n ) cells trace-rsp @ + @ ; \ n = rsp[index]
  38. : TRACE.0RP ( -- n ) trace-return-stack trace_return_size + 8 + trace-rsp ! ;
  39. : TRACE.RDROP ( -- ) cell trace-rsp +! ;
  40. : TRACE.RCHECK ( -- , abort if return stack out of range )
  41. trace-rsp @ trace-return-stack u<
  42. abort" TRACE return stack OVERFLOW!"
  43. trace-rsp @ trace-return-stack trace_return_size + 12 + u>
  44. abort" TRACE return stack UNDERFLOW!" ;
  45. \ save and restore several state variables
  46. 10 cells constant TRACE_STATE_SIZE
  47. create TRACE-STATE-1 TRACE_STATE_SIZE allot
  48. create TRACE-STATE-2 TRACE_STATE_SIZE allot
  49. variable TRACE-STATE-PTR
  50. : TRACE.SAVE++ ( addr -- , save next thing )
  51. @ trace-state-ptr @ !
  52. cell trace-state-ptr +! ;
  53. : TRACE.SAVE.STATE ( -- )
  54. state trace.save++
  55. hld trace.save++
  56. base trace.save++ ;
  57. : TRACE.SAVE.STATE1 ( -- , save normal state )
  58. trace-state-1 trace-state-ptr !
  59. trace.save.state ;
  60. : TRACE.SAVE.STATE2 ( -- , save state of word being debugged )
  61. trace-state-2 trace-state-ptr !
  62. trace.save.state ;
  63. : TRACE.RESTORE++ ( addr -- , restore next thing )
  64. trace-state-ptr @ @ swap !
  65. cell trace-state-ptr +! ;
  66. : TRACE.RESTORE.STATE ( -- )
  67. state trace.restore++
  68. hld trace.restore++
  69. base trace.restore++ ;
  70. : TRACE.RESTORE.STATE1 ( -- )
  71. trace-state-1 trace-state-ptr !
  72. trace.restore.state ;
  73. : TRACE.RESTORE.STATE2 ( -- )
  74. trace-state-2 trace-state-ptr !
  75. trace.restore.state ;
  76. \ The implementation of these pForth primitives is specific to pForth.
  77. variable TRACE-LOCALS-PTR \ point to top of local frame
  78. \ create a return stack frame for NUM local variables
  79. : TRACE.(LOCAL.ENTRY) ( x0 x1 ... xn n -- ) { num | lp -- }
  80. trace-locals-ptr @ trace.>r
  81. trace-rsp @ trace-locals-ptr !
  82. trace-rsp @ num cells - trace-rsp ! \ make room for locals
  83. trace-rsp @ -> lp
  84. num 0
  85. DO
  86. lp !
  87. cell +-> lp \ move data into locals frame on return stack
  88. LOOP
  89. ;
  90. : TRACE.(LOCAL.EXIT) ( -- )
  91. trace-locals-ptr @ trace-rsp !
  92. trace.r> trace-locals-ptr ! ;
  93. : TRACE.(LOCAL@) ( l# -- n , fetch from local frame )
  94. trace-locals-ptr @ swap cells - @ ;
  95. : TRACE.(1_LOCAL@) ( -- n ) 1 trace.(local@) ;
  96. : TRACE.(2_LOCAL@) ( -- n ) 2 trace.(local@) ;
  97. : TRACE.(3_LOCAL@) ( -- n ) 3 trace.(local@) ;
  98. : TRACE.(4_LOCAL@) ( -- n ) 4 trace.(local@) ;
  99. : TRACE.(5_LOCAL@) ( -- n ) 5 trace.(local@) ;
  100. : TRACE.(6_LOCAL@) ( -- n ) 6 trace.(local@) ;
  101. : TRACE.(7_LOCAL@) ( -- n ) 7 trace.(local@) ;
  102. : TRACE.(8_LOCAL@) ( -- n ) 8 trace.(local@) ;
  103. : TRACE.(LOCAL!) ( n l# -- , store into local frame )
  104. trace-locals-ptr @ swap cells - ! ;
  105. : TRACE.(1_LOCAL!) ( -- n ) 1 trace.(local!) ;
  106. : TRACE.(2_LOCAL!) ( -- n ) 2 trace.(local!) ;
  107. : TRACE.(3_LOCAL!) ( -- n ) 3 trace.(local!) ;
  108. : TRACE.(4_LOCAL!) ( -- n ) 4 trace.(local!) ;
  109. : TRACE.(5_LOCAL!) ( -- n ) 5 trace.(local!) ;
  110. : TRACE.(6_LOCAL!) ( -- n ) 6 trace.(local!) ;
  111. : TRACE.(7_LOCAL!) ( -- n ) 7 trace.(local!) ;
  112. : TRACE.(8_LOCAL!) ( -- n ) 8 trace.(local!) ;
  113. : TRACE.(LOCAL+!) ( n l# -- , store into local frame )
  114. trace-locals-ptr @ swap cells - +! ;
  115. : TRACE.(?DO) { limit start ip -- ip' }
  116. limit start =
  117. IF
  118. ip @ +-> ip \ BRANCH
  119. ELSE
  120. start trace.>r
  121. limit trace.>r
  122. cell +-> ip
  123. THEN
  124. ip ;
  125. : TRACE.(LOOP) { ip | limit indx -- ip' }
  126. trace.r> -> limit
  127. trace.r> 1+ -> indx
  128. limit indx =
  129. IF
  130. cell +-> ip
  131. ELSE
  132. indx trace.>r
  133. limit trace.>r
  134. ip @ +-> ip
  135. THEN
  136. ip ;
  137. : TRACE.(+LOOP) { delta ip | limit indx oldindx -- ip' }
  138. trace.r> -> limit
  139. trace.r> -> oldindx
  140. oldindx delta + -> indx
  141. \ /* Do indices cross boundary between LIMIT-1 and LIMIT ? */
  142. \ if( ( (OldIndex - Limit) & ((Limit-1) - NewIndex) & 0x80000000 ) ||
  143. \ ( (NewIndex - Limit) & ((Limit-1) - OldIndex) & 0x80000000 ) )
  144. oldindx limit - limit 1- indx - AND $ 80000000 AND
  145. indx limit - limit 1- oldindx - AND $ 80000000 AND OR
  146. IF
  147. cell +-> ip
  148. ELSE
  149. indx trace.>r
  150. limit trace.>r
  151. ip @ +-> ip
  152. THEN ip ;
  153. : TRACE.CHECK.IP { ip -- }
  154. ip ['] first_colon u<
  155. ip here u> OR
  156. IF
  157. ." TRACE - IP out of range = " ip .hex cr abort
  158. THEN ;
  159. : TRACE.SHOW.IP { ip -- , print name and offset }
  160. ip ( >code code> ) ( code@ ) name> >name dup id.
  161. name> ip code> swap - 4 / ." +" .dec ." 's words" ;
  162. : TRACE.SHOW.STACK { | mdepth -- }
  163. base @ >r
  164. ." <" base @ decimal 1 .r ." :"
  165. depth 1 .r ." > "
  166. r> base !
  167. depth 5 min -> mdepth
  168. depth mdepth -
  169. IF
  170. ." ... " \ if we don't show entire stack
  171. THEN
  172. mdepth 0
  173. ?DO
  174. mdepth i 1+ - pick . \ show numbers in current base
  175. LOOP ;
  176. : TRACE.SHOW.NEXT { ip -- }
  177. >newline
  178. ip trace.check.ip
  179. \ show word name and offset
  180. ." << "
  181. trace_ip trace.show.ip
  182. 30 space.to.column
  183. \ show data stack
  184. trace.show.stack
  185. 80 space.to.column ." || Next word - "
  186. trace_level 2* spaces
  187. ip code@
  188. cell +-> ip
  189. \ show primitive about to be executed
  190. dup .xt space
  191. \ trap any primitives that are followed by inline data
  192. CASE
  193. ['] (LITERAL) OF ip @ dup . space 255 and emit ENDOF
  194. ['] (ALITERAL) OF ip a@ dup . space 255 and emit ENDOF
  195. [ exists? (FLITERAL) [IF] ]
  196. ['] (FLITERAL) OF ip f@ f. ENDOF
  197. [ [THEN] ]
  198. ['] BRANCH OF ip @ 4 / . ENDOF
  199. ['] 0BRANCH OF ip @ 4 / . ENDOF
  200. ['] (.") OF ip count type .' "' ENDOF
  201. ['] (C") OF ip count type .' "' ENDOF
  202. ['] (S") OF ip count type .' "' ENDOF
  203. ENDCASE
  204. 100 space.to.column ." >> " ;
  205. : TRACE.DO.PRIMITIVE { ip xt | oldhere -- ip' , perform code at ip }
  206. xt
  207. CASE
  208. 0 OF -1 +-> trace_level trace.r> -> ip ENDOF \ EXIT
  209. ['] (CREATE) OF ip cell- body_offset + ENDOF
  210. ['] (LITERAL) OF ip @ cell +-> ip ENDOF
  211. ['] (ALITERAL) OF ip a@ cell +-> ip ENDOF
  212. [ exists? (FLITERAL) [IF] ]
  213. ['] (FLITERAL) OF ip f@ 1 floats +-> ip ENDOF
  214. [ [THEN] ]
  215. ['] BRANCH OF ip @ +-> ip ENDOF
  216. ['] 0BRANCH OF 0= IF ip @ +-> ip ELSE cell +-> ip THEN ENDOF
  217. ['] >R OF trace.>r ENDOF
  218. ['] R> OF trace.r> ENDOF
  219. ['] R@ OF trace.r@ ENDOF
  220. ['] RDROP OF trace.rdrop ENDOF
  221. ['] 2>R OF trace.>r trace.>r ENDOF
  222. ['] 2R> OF trace.r> trace.r> ENDOF
  223. ['] 2R@ OF trace.r@ 1 trace.rpick ENDOF
  224. ['] i OF 1 trace.rpick ENDOF
  225. ['] j OF 3 trace.rpick ENDOF
  226. ['] (LEAVE) OF trace.rdrop trace.rdrop ip @ +-> ip ENDOF
  227. ['] (LOOP) OF ip trace.(loop) -> ip ENDOF
  228. ['] (+LOOP) OF ip trace.(+loop) -> ip ENDOF
  229. ['] (DO) OF trace.>r trace.>r ENDOF
  230. ['] (?DO) OF ip trace.(?do) -> ip ENDOF
  231. ['] (.") OF ip count type ip count + aligned -> ip ENDOF
  232. ['] (C") OF ip ip count + aligned -> ip ENDOF
  233. ['] (S") OF ip count ip count + aligned -> ip ENDOF
  234. ['] (LOCAL.ENTRY) OF trace.(local.entry) ENDOF
  235. ['] (LOCAL.EXIT) OF trace.(local.exit) ENDOF
  236. ['] (LOCAL@) OF trace.(local@) ENDOF
  237. ['] (1_LOCAL@) OF trace.(1_local@) ENDOF
  238. ['] (2_LOCAL@) OF trace.(2_local@) ENDOF
  239. ['] (3_LOCAL@) OF trace.(3_local@) ENDOF
  240. ['] (4_LOCAL@) OF trace.(4_local@) ENDOF
  241. ['] (5_LOCAL@) OF trace.(5_local@) ENDOF
  242. ['] (6_LOCAL@) OF trace.(6_local@) ENDOF
  243. ['] (7_LOCAL@) OF trace.(7_local@) ENDOF
  244. ['] (8_LOCAL@) OF trace.(8_local@) ENDOF
  245. ['] (LOCAL!) OF trace.(local!) ENDOF
  246. ['] (1_LOCAL!) OF trace.(1_local!) ENDOF
  247. ['] (2_LOCAL!) OF trace.(2_local!) ENDOF
  248. ['] (3_LOCAL!) OF trace.(3_local!) ENDOF
  249. ['] (4_LOCAL!) OF trace.(4_local!) ENDOF
  250. ['] (5_LOCAL!) OF trace.(5_local!) ENDOF
  251. ['] (6_LOCAL!) OF trace.(6_local!) ENDOF
  252. ['] (7_LOCAL!) OF trace.(7_local!) ENDOF
  253. ['] (8_LOCAL!) OF trace.(8_local!) ENDOF
  254. ['] (LOCAL+!) OF trace.(local+!) ENDOF
  255. >r xt EXECUTE r>
  256. ENDCASE
  257. ip ;
  258. : MONITOR ( ) LIB ( B )
  259. case
  260. 0 of tlink endof
  261. 3 of getm endof
  262. 4 of putm endof
  263. 033 of ex endof \ BR 0 TLINK 3 GETM 4 PUTM 033 EX ELSE ER_COM
  264. er_com \ Default
  265. endcase ( ) ;
  266. : TRACE.DO.NEXT { ip | xt oldhere -- ip' , perform code at ip }
  267. ip trace.check.ip
  268. \ set context for word under test
  269. trace.save.state1
  270. here -> oldhere
  271. trace.restore.state2
  272. oldhere 256 + dp !
  273. \ get execution token
  274. ip code@ -> xt
  275. cell +-> ip
  276. \ execute token
  277. xt is.primitive?
  278. IF \ primitive
  279. ip xt trace.do.primitive -> ip
  280. ELSE \ secondary
  281. trace_level trace_level_max <
  282. IF
  283. ip trace.>r \ threaded execution
  284. 1 +-> trace_level
  285. xt codebase + -> ip
  286. ELSE
  287. \ treat it as a primitive
  288. ip xt trace.do.primitive -> ip
  289. THEN
  290. THEN
  291. \ restore original context
  292. trace.rcheck
  293. trace.save.state2
  294. trace.restore.state1
  295. oldhere dp !
  296. ip ;
  297. : TRACE.NEXT { ip | xt -- ip' }
  298. trace_level 0>
  299. IF
  300. ip trace.do.next -> ip
  301. THEN
  302. trace_level 0>
  303. IF
  304. ip trace.show.next
  305. ELSE
  306. ." Finished." cr
  307. THEN
  308. ip
  309. ;
  310. }private
  311. : TRACE ( i*x <name> -- i*x , setup trace environment )
  312. ' dup is.primitive?
  313. IF
  314. drop ." Sorry. You can't trace a primitive." cr
  315. ELSE
  316. 1 -> trace_level
  317. trace_level -> trace_level_max
  318. trace.0rp
  319. dup -> TRACE-BEGWORD_IP
  320. >code -> trace_ip
  321. trace_ip trace.show.next
  322. trace-stack off
  323. trace.save.state2
  324. THEN ;
  325. : s ( -- , step over )
  326. trace_level -> trace_level_max
  327. trace_ip trace.next -> trace_ip ;
  328. : sd ( -- , step down )
  329. trace_level 1+ -> trace_level_max
  330. trace_ip trace.next -> trace_ip ;
  331. : sm ( many -- , step many times )
  332. trace_level -> trace_level_max
  333. 0
  334. ?DO
  335. trace_ip trace.next -> trace_ip
  336. LOOP ;
  337. defer trace.user ( IP -- stop? )
  338. ' 0= is trace.user
  339. : gd { more_levels | stop_level userflag -- }
  340. here what's trace.user u< \ has it been forgotten?
  341. IF
  342. ." Resetting TRACE.USER !!!" cr
  343. ['] 0= is trace.user
  344. THEN
  345. more_levels 0<
  346. more_levels 10 >
  347. IF
  348. ." GD level out of range (0-10), = " more_levels . cr
  349. ELSE
  350. trace_level more_levels + -> trace_level_max
  351. trace_level 1- -> stop_level
  352. BEGIN
  353. trace_ip trace.user \ call deferred user word
  354. dup \ leave flag for UNTIL
  355. IF
  356. ." TRACE.USER returned " dup . ." so stopping execution." cr
  357. ELSE
  358. -> userflag drop
  359. \ cr ." before=" .s
  360. trace_ip
  361. trace.next
  362. -> trace_ip
  363. \ ." after=" .s key drop
  364. userflag
  365. trace_level stop_level > not
  366. THEN
  367. UNTIL
  368. drop
  369. THEN ;
  370. : g ( -- , execute until end of word ) 0 gd ;
  371. : TRACE.HELP ( -- )
  372. ." TRACE ( i*x <name> -- , setup trace for Forth word )" cr
  373. ." S ( -- , step over )" cr
  374. ." SM ( many -- , step over many times )" cr
  375. ." SD ( -- , step down )" cr
  376. ." G ( -- , go to end of word )" cr
  377. ." GD ( n -- , go down N levels from current level," cr
  378. ." stop at end of this level )" cr ;
  379. privatize
  380. 0 [IF]
  381. variable var1 100 var1 !
  382. : FOO dup IF 1 + . THEN 77 var1 @ + . ;
  383. : ZOO 29 foo 99 22 + . ;
  384. : ROO 92 >r 1 r@ + . r> . ;
  385. : MOO c" hello" count type ." This is a message." cr s" another message" type cr ;
  386. : KOO 7 FOO ." DONE" ;
  387. : TR.DO 4 0 DO i . LOOP ;
  388. : TR.?DO 0 ?DO i . LOOP ;
  389. : TR.LOC1 { aa bb } aa bb + . ;
  390. : TR.LOC2 789 >r 4 5 tr.loc1 r> . ;
  391. [THEN]