uidebug.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:38k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. TITLE uidebug.asm - User interface to debugger.
  2. ;*** 
  3. ;uidebug.asm
  4. ;
  5. ; Copyright <C> 1985-1988, Microsoft Corporation
  6. ;
  7. ;Purpose:
  8. ; Debugging support.
  9. ;
  10. ;
  11. ;*******************************************************************************
  12. .xlist
  13. include version.inc
  14. UIDEBUG_ASM = ON
  15. ;Include twin interface headers
  16. include  cw/version.inc
  17. include  cw/windows.inc
  18. include  cw/edityp.inc
  19. ;Next, include QBI's headers
  20. includeOnce architec
  21. includeOnce context
  22. includeOnce executor
  23. includeOnce heap
  24. includeOnce lister
  25. includeOnce opmin
  26. includeOnce opstmt
  27. includeOnce parser
  28. includeOnce qbimsgs
  29. includeOnce scanner
  30. includeOnce txtmgr
  31. includeOnce ui
  32. includeOnce uiint
  33. includeOnce util
  34. includeOnce uimenu
  35. .list
  36. ;---------------------------------------------------------------------------
  37. ;
  38. ; The following demonstrates how the user interface code interacts with
  39. ; the executor code to handle watchpoints and watch expressions.
  40. ; We start the discussion in UserInterface with the following program loaded:
  41. ;   A=1
  42. ;   A=2
  43. ; The pcode for this program is:
  44. ;   opBol
  45. ;   opLit1
  46. ;   opIdSt(A)
  47. ;   opBol
  48. ;   opLit2
  49. ;   opIdSt(A)
  50. ;   opEndProg
  51. ; - User presses single step key, causing UserInterface to exit
  52. ; - opBol executes, sees DEBUG_TRACE bit set in debugFlags, enters UserInterface
  53. ; - User selects Watchpoint... menu, CmdWatchAdd(WT_Watch) prompts the user
  54. ;   for an expression, parses it to pcode, and inserts it at the end of the
  55. ;   text table.
  56. ; - User selects Watch... menu, CmdWatchAdd(WT_WatchPoint) prompts the user
  57. ;   for an expression, parses it to pcode, and inserts it at the end of the
  58. ;   text table.
  59. ; - We now have with a WATCHPOINT of "A=1" and a WATCH EXPRESSION of "A" and
  60. ;   the pcode looks like:
  61. ;   opBol
  62. ;   opLit1
  63. ;   opIdSt(A)
  64. ;   opBol
  65. ;   opLit2
  66. ;   opIdSt(A)
  67. ;   opEndProg
  68. ;   opIdLd(A)
  69. ;   opLit1
  70. ;   opEQ
  71. ;   opWatchStop
  72. ;   opIdLd(A)
  73. ;   opWatchExp
  74. ;   opEot
  75. ; - User presses single step key.  When UserInterface exits, it sees active
  76. ;   Watch expressions, and sets DEBUG_WATCH in debugFlags.
  77. ; - opLit1 and opIdSt(A) execute
  78. ; - opBol executes, sees bits set in debugFlags, enters UserInterface
  79. ; - UserInterface immediately dispatches to DebugWatch.  DebugWatch sees
  80. ;   iWatch (static counter variable) is UNDEFINED (meaning we weren't executing
  81. ;   Watch pcode), saves current pc in otxWatchSave, sets the
  82. ;   current pc to the 1st watch expression's pcode, sets iWatch to 0,
  83. ;   returns to UserInterface with flags telling it to dispatch.
  84. ; - opIdLd(A), opLit1, and opEQ execute.
  85. ; - opWatchStop executes, sees a TRUE (non-zero) argument on the stack, sets
  86. ;   DEBUG_BREAK in debugFlags.  opWatchStop then falls into opBol which sees
  87. ;   debugFlags non-zero and enters UserInterface.
  88. ; - UserInterface immediately dispatches to DebugWatch.  DebugWatch sees
  89. ;   iWatch is 0, bumps it to 1, sets the current pc to the 2nd watch
  90. ;   expression's pcode, returns to UserInterface with flags telling it to dispatch.
  91. ; - opIdLd(A) executes.
  92. ; - opWatch executes, saves value at [pWatchVal], opWatch then falls into
  93. ;   opBol which sees debugFlags non-zero and enters UserInterface.
  94. ; - UserInterface immediately dispatches to DebugWatch.  DebugWatch sees
  95. ;   iWatch is 1, restores the current pc to otxWatchSave,
  96. ;   returns to UserInterface.
  97. ; - UserInterface then sees DEBUG_BREAK is set, and would have stopped program
  98. ;   execution even if we weren't tracing.  UserInterface then interacts with
  99. ;   the user until the user gives another command.
  100. ; - User presses single step key.  When UserInterface exits, it sees active
  101. ;   Watch expressions, and sets DEBUG_WATCH in debugFlags.
  102. ; - opLit2 and opIdSt(A) execute
  103. ; - opEndProg executes, causing us to once again enter UserInterface
  104. ;
  105. ;---------------------------------------------------------------------------
  106. assumes DS,DATA
  107. assumes ES,NOTHING
  108. assumes SS,DATA
  109. EXTRN B$BEEP:FAR
  110. EXTRN B$IFOUT:FAR
  111. EXTRN B$Pause:FAR
  112. sBegin DATA
  113. EXTRN b$ErrNum:word ;error code for last runtime error
  114. EXTRN b$CurFrame:word ;current frame ptr (for PTRACE)
  115. EXTRN b$MainFrame:word ;base frame ptr
  116. EXTRN fRecord:byte ;set TRUE is /RCD switch seen
  117. EXTRN fPlayBack:word ;TRUE if we're playing back.
  118. ; an event playback file.
  119. EXTRN axMac:byte
  120. externB HelpFlags ; uiint.inc/h
  121. ;Points to space allocated by CallsMenuInit, released by CallsMenuTerm
  122. ;
  123. pbCallsRelease DW 0
  124. ;iWatch is used by several functions involved in drawing the content
  125. ; of the watch window.  It indicates which line in the window is currently
  126. ; being drawn (0 to n)
  127. ;
  128. DbPub iWatch
  129. iWatch DW UNDEFINED
  130. ; iInstWatch is used to keep track of where an Instant Watch entry is
  131. ; in the tWatch table.  The value of iInstWatch is only significant if
  132. ; the value of cInstWatch is non-zero.
  133. DbPub iInstWatch
  134. iInstWatch DW 0
  135. ;fRefreshWatch is set TRUE whenever a WATCH entry is added or removed.
  136. ;It causes us to refresh the WATCH window.
  137. ;
  138. PUBLIC fRefreshWatch
  139. fRefreshWatch DB 0
  140. ;pWatchVal points to valtyp/value structure to be filled in by Watch executors
  141. PUBLIC pWatchVal
  142. pWatchVal DW 0
  143. ;1 entry per watch expression - number of bytes in expression's title
  144. tCbWatchTitle DB (WATCH_MAX+1) DUP (?) ; "+1" is for Instant Watch
  145. otxWatchSave DW 0 ;copy of grs.otxCur while WATCH pcode executes
  146. errnumSave DW 0 ; copy of b$errnum while WATCH pcode executes
  147. bpWatchSave DW 0 ;copy of bp for start of current WATCH expression
  148. fDirectSave DB 0 ;copy of grs.fDirect while WATCH pcode executes
  149. ;Trace modes
  150. ;
  151. TRACE_OFF EQU 0
  152. TRACE_HISTORY EQU 1 ;Debug/History menu item is ON
  153. TRACE_ANIMATE EQU 2 ;Debug/Trace menu item is ON
  154. TRACE_STEP EQU 3 ;F8 was pressed last time in UserInterface
  155. TRACE_PSTEP EQU 4 ;F10 was pressed last time in UserInterface
  156. TRACE_WATCHSTEP EQU 5 ;Used by watch to force watch code to execute.
  157. traceMode DB TRACE_OFF
  158. pStepFrame DW 0
  159. nonStickyBpRs DW 0
  160. nonStickyBpLn DW UNDEFINED
  161. CHIST EQU 20 ;we will remember last 20 statements executed
  162. CBHIST EQU 4 ;number of bytes in 1 history entry
  163. bdHist DB size BD DUP (0)
  164. oHistNext DW 0
  165. oHistShow DW 0
  166. histFlags DB 0
  167. FH_Full equ 01H
  168. FH_NotEmpty equ 02H
  169. szRun DB "RUN",0
  170. sEnd DATA
  171. sBegin CODE
  172. ;Table of opcodes(1) which descanner inserts where it finds return
  173. ; addresses on the stack:
  174. ;
  175. tOpNoList LABEL WORD
  176. opTabStart NOLIST
  177. opTabEntry NOLIST,opNoList1
  178. opTabEntry NOLIST,opEot
  179. sEnd CODE
  180. sBegin UI
  181. assumes cs,UI
  182. ;**************************************************************************
  183. ; DoRunOrCont(ax:fFromStart)
  184. ; Purpose:
  185. ; Setup so program will continue execution.
  186. ; If can't continue then start at begining.
  187. ;
  188. ; Entry:
  189. ; ax = fFromStart - if TRUE start program from the beginning.
  190. ; Exit:
  191. ; fGotCmd is set TRUE (which terminates GetCmd)
  192. ;
  193. ;**************************************************************************
  194. DoCont PROC NEAR
  195. sub ax,ax
  196. DoCont ENDP
  197. ;fall into DoRunOrCont
  198. cProc DoRunOrCont,<NEAR>
  199. cBegin
  200. or ax,ax
  201. jne FromStart
  202. call fCanContUI
  203. jne NotFromStart ;brif can continue
  204. ; FNextStmtDoesIO uses grs.otxCONT to determine if the next statement to
  205. ; execute will do output.  ContContext is called just before FNextStmtDoesIO.
  206. ; if grs.otxCONT is UNDEFINED, ContContext will
  207. ; set grs.otxCONT to the begining of the main module.
  208. ;
  209. FromStart:
  210. call CantCont ;sets [grs.GRS_otxCONT] to UNDEFINED
  211. PUSHI ax,<dataOFFSET szRUN>
  212. call DoCmd
  213. NotFromStart:
  214. mov [fGotCmd],sp
  215. cEnd
  216. ;**************************************************************************
  217. ; SetTronTroff
  218. ; Purpose:
  219. ; Set [traceMode] and set DEBUG_TRACE bit in [debugFlags] if not TRACE_OFF
  220. ; Called by TRON and TROFF opcode executors after they set [fTraceOn]
  221. ; Entry:
  222. ; [fTraceOn] = non-zero if TRON is active
  223. ; [fHistOn] = non-zero if HISTORY is active
  224. ;
  225. ;**************************************************************************
  226. PUBLIC SetTronTroff
  227. SetTronTroff PROC FAR
  228. .errnz TRACE_ANIMATE - 2
  229. mov ax,TRACE_ANIMATE
  230. cmp [fTraceOn],ah
  231. jne NoTrace ;brif TRON (Trace ON) is not active
  232. dec ax ;al = TRACE_HISTORY
  233. .errnz TRACE_HISTORY - 1
  234. cmp [fHistOn],ah
  235. jne NoTrace ;brif History ON is not active
  236. dec ax ;al = TRACE_OFF
  237. .errnz TRACE_OFF
  238. NoTrace:
  239. call SetTraceMode
  240. ret ;can't fall into SetTraceMode, far->near
  241. SetTronTroff ENDP
  242. ;**************************************************************************
  243. ; SetTraceMode
  244. ; Purpose:
  245. ; Set [traceMode] and set DEBUG_TRACE bit in [debugFlags] if not TRACE_OFF
  246. ; Entry:
  247. ; al = new trace mode (TRACE_STEP etc.)
  248. ;
  249. ;**************************************************************************
  250. SetTraceMode PROC NEAR
  251. mov [traceMode],al
  252. or al,al
  253. je GotTroff
  254. .errnz TRACE_OFF
  255. or [debugFlags],DEBUG_TRACE
  256. GotTroff:
  257. ret
  258. SetTraceMode ENDP
  259. ;**************************************************************************
  260. ; CmdGo(fFromStart)
  261. ; Purpose:
  262. ; Continue or start program execution taking into account trace state.
  263. ; This procedure is called in response to the menu items `Run/Run' and
  264. ; `Run/Continue'
  265. ;
  266. ; Entry:
  267. ; fTraceOn - non-zero if TRON is active
  268. ; fFromStart - TRUE if we want to RUN else we want to CONT.
  269. ;
  270. ;**************************************************************************
  271. cProc CmdGo,<PUBLIC,NEAR>
  272. parmW fFromStart
  273. cBegin
  274. call SetTronTroff ;setup based on [fTraceOn]
  275. mov ax,[fFromStart]
  276. call DoRunOrCont ;execute a RUN or CONT command
  277. cEnd
  278. ;**************************************************************************
  279. ; CmdSetNextStmt()
  280. ; Purpose:
  281. ; Reset instruction pointer to statement at cursor.
  282. ;
  283. ;**************************************************************************
  284. cProc CmdSetNextStmt,<PUBLIC,NEAR>,<si,di>
  285. cBegin
  286. call TxtDescan ;descan to SS_PARSE
  287. call GetEditLine ;ax = current edit line (from EditMgr)
  288. push ax
  289. call OtxOfLn  ;ax = text offset to start of line
  290. xchg ax, bx ; bx = otx of pcode to skip.
  291. call TxtSkipOpFar ;ax = otx beyond the opBol[xx] opcode
  292. ;We always enter direct mode after
  293. ;execution of the opBol
  294. xchg si,ax ;si = otx
  295. mov di,[grs.GRS_oRsCur] ;di = oRs of current text table
  296. test [txdCur.TXD_flags],FTX_mrs
  297. je NotInDefFn ;brif we're in a sub/function window
  298. push si ;pass otx
  299. call OPrsOfOtx ;ax = otx of DEF FN
  300. inc ax ;test for UNDEFINED
  301. je NotInDefFn ;brif we're in main-level code
  302. dec ax ;ax = oPrs for DEF FN
  303. or ah,80h ;ax = oRs of DEF FN
  304. xchg di,ax ;di = oRs of DEF FN
  305. NotInDefFn:
  306. call NeedContContext ;grs.oRsCur=grs.oRsCONT or grs.oMrsMain
  307. ;if no main module, uierr is set
  308. je NxtStmtExit ;brif no main module
  309. cmp di,[grs.GRS_oRsCur]
  310. je BranchOk ;brif branching within text table
  311. BadBranch:
  312. PUSHI ax,MSG_BadNextStmt ;"Cannot cross module/procedure boundary"
  313. call SetUiErr
  314. jmp SHORT NxtStmtExit
  315. BranchOk:
  316. mov [grs.GRS_otxCONT],si
  317. call DrawDebugScr ;so new current stmt will be hilighted
  318. NxtStmtExit:
  319. cEnd
  320. ;**************************************************************************
  321. ; CmdRestart()
  322. ; Purpose:
  323. ; Restart program. Like a Step but always starts at begining of program.
  324. ;
  325. ;**************************************************************************
  326. cProc CmdRestart,<PUBLIC,NEAR>
  327. cBegin
  328. mov al,TRACE_STEP
  329. call SetTraceMode
  330. mov ax,sp ;ax = TRUE (non-zero)
  331. call DoRunOrCont
  332. cEnd
  333. ;**************************************************************************
  334. ; PStepReset
  335. ; Purpose:
  336. ; Called whenever executor resets stack pointer.  This guarentees
  337. ; that DebugTrace will stop the next time it is called (even for F10).
  338. ;
  339. ;**************************************************************************
  340. cProc PStepReset,<PUBLIC,FAR>
  341. cBegin
  342. mov [pStepFrame],0
  343. cEnd
  344. ;**************************************************************************
  345. ; CmdStep(fPStep)
  346. ; Purpose:
  347. ; Setup to execute the next program statement.
  348. ; This routine is called in response to the Step and PStep
  349. ; accelerator keys.
  350. ;
  351. ; Entry:
  352. ; fPStep - if TRUE count procedure calls as one statement (F10).
  353. ;
  354. ; Exit:
  355. ; PStepFrame, debugFlags, traceMode, fGotCmd are all updated
  356. ;
  357. ;**************************************************************************
  358. cProc CmdStep,<PUBLIC,NEAR>
  359. parmW fPStep
  360. cBegin
  361. call ContContext ;activate program counter's context
  362. call SkipStop ;skip past opBreakPoint or opStStop
  363. mov ax,[grs.GRS_otxCONT]
  364. inc ax ;test for UNDEFINED
  365. je UseBp ;if Can't continue, stop at next entry
  366. mov ax,[b$CurFrame]  ;get current frame
  367. mov cx,[pGosubLast]  ;get gosub stack value
  368. jcxz UseBp ;zero, use current frame as frame
  369. cmp cx,ax
  370. ja UseBp ; brif no gosubs for this frame
  371. xchg ax,cx ;else use top of stack
  372. UseBp:
  373. mov [pStepFrame],ax  ;and move it in
  374. mov al,TRACE_STEP
  375. cmp [fPStep],FALSE
  376. je CsNotPStep ;brif F8 was pressed (step into proc)
  377. .errnz TRACE_STEP - 3
  378. .errnz TRACE_PSTEP - 4
  379. inc ax ;al = TRACE_PSTEP (F10=step around proc)
  380. CsNotPStep:
  381. call SetTraceMode
  382. call DoCont ;continue program execution
  383. cEnd
  384. ;**************************************************************************
  385. ; CmdToggleBp()
  386. ; Purpose:
  387. ; Toggles the breakpoint setting of the current line.
  388. ; Note: will only be called if the current window contains code.
  389. ;
  390. ; Exit:
  391. ; If an edit window is active a breakpoint is set/reset at the
  392. ; current line.
  393. ; ax active edit line (UNDEFINED if none)
  394. ;
  395. ;**************************************************************************
  396. cProc CmdToggleBp,<PUBLIC,NEAR>
  397. cBegin
  398. call UiGrabSpace
  399. call GetEditLine ;ax = current edit line (from EditMgr)
  400. push ax ;save for return value
  401. inc ax ;test for UNDEFINED
  402. je CsNoEditLine
  403. dec ax
  404. push ax ;pass to ToggleBp
  405. call ToggleBp
  406. mov [uierr],ax ;store possible error code
  407. call DrawDebugScr ;Refresh any lines containing
  408. ;this breakpoint
  409. CsNoEditLine:
  410. call UiReleaseSpace
  411. pop ax ;ax = edit line
  412. cEnd
  413. ;**************************************************************************
  414. ; CmdGoUntilHere()
  415. ; Purpose:
  416. ;  Sets a non-sticky breakpoint at the current line and runs until it
  417. ;  gets there. When the breakpoint is reached it will automatically be cleared.
  418. ;  Note: will only be called if the current window contains code.
  419. ;
  420. ;**************************************************************************
  421. cProc CmdGoUntilHere,<PUBLIC,NEAR>
  422. cBegin
  423. call UiRsActivateWnd  ;activate active window's context
  424. test [mrsCur.MRS_flags2],FM2_Include OR FM2_NoPcode
  425. jne CgExit ;brif not a pcode window
  426. call GetEditLine ;get line number
  427. cCall OtxOfLn,<ax> ;get otx
  428. cCall fBpSet,<ax> ;see if bp is set
  429. or ax,ax
  430. jnz CgGo ;do nothing if bp already set
  431. call CmdToggleBp ;set break point on current line
  432. inc ax ;test for UNDEFINED
  433. je CgExit ;brif no active edit line
  434. dec ax ;restore ax = line number
  435. mov [nonStickyBpLn],ax ;remember to reset break point
  436. mov ax,[grs.GRS_oRsCur]
  437. mov [nonStickyBpRs],ax
  438. CgGo:
  439. call ContContext ;activate program counter's context
  440. call SkipStop ;skip past the opBreakPoint
  441. xor ax,ax
  442. cCall CmdGo,<ax> ;continue program execution
  443. CgExit:
  444. cEnd
  445. ;**************************************************************************
  446. ; ClrNonStickyBp()
  447. ; Purpose:
  448. ; Called on entry to GetCmd()
  449. ; Clears any breakpoint set by CmdGoUntilHere().
  450. ; Exit:
  451. ; Context may be switched to another text table.
  452. ;
  453. ;**************************************************************************
  454. cProc ClrNonStickyBp,<PUBLIC,NEAR>
  455. cBegin
  456. mov ax,[nonStickyBpLn]
  457. inc ax ;test for UNDEFINED
  458. je ClrNoBp
  459. dec ax
  460. push ax ;pass to ToggleBp
  461. push [nonStickyBpRs] ;pass to UiRsActivate
  462. call UiRsActivate
  463. call ToggleBp
  464. mov [nonStickyBpLn],UNDEFINED
  465. call DrawDebugScr ;Refresh any lines containing
  466. ;this breakpoint
  467. ClrNoBp:
  468. cEnd
  469. ;**************************************************************************
  470. ; DebugError()
  471. ; Purpose:
  472. ;  Setup to report a runtime error.
  473. ;
  474. ; Exit:
  475. ;  uierr and txtErr structure are setup so error will be reported in GetCmd.
  476. ;  Returns mask which tells UserInterface to stop for commands.
  477. ;
  478. ;**************************************************************************
  479. PUBLIC DebugError
  480. DebugError PROC NEAR
  481. mov ax,[b$ErrNum]
  482. cmp ax,MSG_GoDirect
  483. je DeExit ;Ignore MSG_GoDirect - it is used
  484. ; when user presses CANCEL button
  485. ; in some dialog.  Easy way to
  486. ; back all the way out of the dialog.
  487. or HelpFlags,HLP_RTERR ; this error came from execution
  488. ;Setup so GetCmd() will call ReportError()
  489. mov dx,ER_UE ;dx = max standard runtimer error code
  490. cmp ax,dx ;see if error was generated by user
  491. ; via ERROR(x) statement
  492. jbe StdRtErr ;brif std runtime error code
  493. xchg ax,dx ;ax = "Unprintable error"
  494. StdRtErr:
  495. mov [uierr],ax ;error will be reported by GetCmd
  496. ; calling ReportError()
  497. mov al,[grs.GRS_fDirect]
  498. mov [txtErr.TXER_fDirect],al
  499. mov ax,[grs.GRS_oRsCur]
  500. mov [txtErr.TXER_oRs],ax
  501. mov ax,[grs.GRS_otxCur]
  502. mov [txtErr.TXER_otx],ax
  503. mov [txtErr.TXER_oSrc],0
  504. DeExit:
  505. mov ax,FDM_GetCmd
  506. jmp SHORT TrOffExit
  507. DebugError ENDP
  508. ;**************************************************************************
  509. ; DebugStop()
  510. ; Purpose:
  511. ;  Setup to report stop statement.
  512. ;
  513. ; Exit:
  514. ;  returns mask which tells UserInterface to show the current statement
  515. ;    and stop for commands.
  516. ;
  517. ;**************************************************************************
  518. PUBLIC DebugStop
  519. DebugStop PROC NEAR
  520. mov ax,FDM_GetCmd OR FDM_ShowStmt
  521. jmp SHORT TrOffExit
  522. DebugStop ENDP
  523. ;**************************************************************************
  524. ; DebugEnd()
  525. ; Purpose:
  526. ;  Called when the program reaches end-of-pcode or END statement
  527. ;
  528. ; Exit:
  529. ;  returns mask which tells UserInterface to stop for commands.
  530. ;
  531. ;**************************************************************************
  532. PUBLIC DebugEnd
  533. DebugEnd PROC NEAR
  534. cmp [fDebugScr],FALSE
  535. jne ShowDeb ;brif debug screen is visible
  536. cmp [fRecord],FALSE
  537. jne ShowDeb ;brif recording a playback file
  538. ; brif not reading a playback file.  Since RUNTIME consumes the
  539. ; keystroke in B$Pause, this would hang the playback file up.
  540. cmp [fPlayBack],FALSE
  541. jne ShowDeb
  542. ; The user has just finished running a program up to an END stmt.
  543. ; The output screen is still visible.  Display the prompt:
  544. ; 'Press any key to return to editor'
  545. ; on the bottom line of the output window and wait for the
  546. ; user to press a key.
  547. call B$Pause
  548. ShowDeb:
  549. cmp [grs.GRS_fDirect],FALSE
  550. jne DeDirMode ;brif end-of-direct mode execution
  551. call EnsShowDebugScr ;init debug screen, make it visible
  552. call DrawDebugScr ;turn off old current stmt highlight
  553. DeDirMode:
  554. mov ax,FDM_GetCmd
  555. TrOffExit:
  556. mov [traceMode],TRACE_OFF
  557. ret
  558. DebugEnd ENDP
  559. ;**************************************************************************
  560. ; DebugTrace()
  561. ; Purpose:
  562. ;   This is invoked when we enter UserInterface with DEBUG_TRACE set in
  563. ;   debugFlags.
  564. ;   Setup to show current statement and depending on the trace mode stop
  565. ;   for commands.
  566. ;
  567. ; Entry:
  568. ;   traceMode = TRACE_HISTORY if we are to do nothing more than record
  569. ;    the pcode address of the instruction for History Playback
  570. ;         TRACE_ANIMATE if we are to show stmt and exit direct mode,
  571. ;               TRACE_STEP if we are stopping for each statement (F8),
  572. ;               TRACE_PSTEP if we are stepping around procedure calls (F10).
  573. ;
  574. ; Exit:
  575. ;   The current statement's location is recorded in the history buffer.
  576. ;   Returns mask to tell UserInterface to show the current statement
  577. ;   and/or tell it to stop and interact with the user.
  578. ;
  579. ;**************************************************************************
  580. cProc DebugTrace,<PUBLIC,NEAR>,<di>
  581. cBegin
  582. call FExecutable ;see if next stmt to be executed
  583. ; contains any executable code
  584. jne ItsExecutable ;brif stmt is executable
  585. sub di,di ;tell UserInterface to take no action
  586. J1_TrSetTraceFlag:
  587. jmp SHORT TrSetTraceFlag
  588. ItsExecutable:
  589. ;set debugFlags, traceMode, fGotCmd, and al (return value) as follows:
  590. ;switch (traceMode)
  591. ;  case TRACE_OFF:
  592. ; fGotCmd remains 0
  593. ;       return al = 0
  594. ;  case TRACE_HISTORY:
  595. ; fGotCmd remains 0
  596. ;       return al = 0
  597. ;  case TRACE_ANIMATE:
  598. ; if alternateListWindow is showing new oRs, activate it
  599. ; if fCantCont, directModeCmd = RUN
  600. ; fGotCmd = TRUE
  601. ;       return al = FDM_ShowStmt
  602. ;  case TRACE_PSTEP:
  603. ; if ([pGosubLast] != 0 && ([pGosubLast] < [pStepFrame])) ||
  604. ;    ([pGosubLast] == 0 && ([b$CurFrame] < [pStepFrame]))
  605. ;    fGotCmd = TRUE
  606. ;          return al = 0
  607. ; else
  608. ;    fall into case TRACE_STEP
  609. ;  case TRACE_WATCHSTEP:
  610. ;  case TRACE_STEP:
  611. ; fGotCmd remains 0
  612. ; traceMode = TRACE_OFF
  613. ; return al = FDM_GetCmd OR (case WATCHSTEP ? 0 :FDM_ShowStmt)
  614. ;end switch
  615. ;if traceMode != TRACE_OFF
  616. ;   debugFlags != DEBUG_TRACE
  617. ;
  618. sub di,di ;tell UserInterface to take no action
  619. sub cx,cx
  620. mov cl,[traceMode] ;cx = traceMode
  621. dec cx
  622. .errnz TRACE_OFF
  623. js SHORT TrSetTraceFlag ;brif traceMode == TRACE_OFF
  624. .errnz TRACE_HISTORY - 1
  625. je TrSetTraceFlag ;brif traceMode == TRACE_HISTORY
  626. loop TrNotAnim ;brif traceMode != TRACE_ANIMATE
  627. .errnz TRACE_ANIMATE - 2
  628. sub ax,ax
  629. push ax
  630. call CmdGo
  631. TrShow:
  632. or di,FDM_ShowStmt
  633. jmp SHORT TrSetTraceFlag
  634. TrNotAnim:
  635. loop TrNotStep ;brif traceMode != TRACE_STEP
  636. .errnz TRACE_STEP - 3
  637. .errnz TRACE_WATCHSTEP - 5
  638. TrStep:
  639. mov di,FDM_ShowStmt
  640. TrWatchStep:
  641. or di,FDM_GetCmd
  642. mov [traceMode],TRACE_OFF
  643. jmp SHORT TrSetTraceFlag
  644. .errnz TRACE_PSTEP - 4
  645. ;traceMode == TRACE_PSTEP
  646. TrNotStep:
  647. loop TrWatchStep
  648. mov ax,[b$CurFrame]  ;get current frame
  649. mov cx,[pGosubLast]  ;get gosub stack value
  650. jcxz TrUseBp ;zero, use current frame as frame
  651. cmp cx,ax
  652. ja TrUseBp  ; brif no gosubs for this frame
  653. xchg ax,cx ;else use top of stack
  654. TrUseBp:
  655. cmp [pStepFrame],ax  ;compare, and if pstepframe
  656. jbe TrStep ;watermark is below or equal, step
  657. TrSkip:
  658. call DoCont ;continue program execution
  659. ;di = FDM_xxx actionMask return value
  660. TrSetTraceFlag:
  661. cmp [traceMode],TRACE_OFF
  662. je TrExit ;leave trace flag 0 if not tracing
  663. or [debugFlags],DEBUG_TRACE
  664. TrExit:
  665. xchg ax,di ;ax = return value
  666. cEnd ;DebugTrace
  667. ;**************************************************************************
  668. ; HistReset()
  669. ; Purpose:
  670. ;   This is called when we Scan/Descan a program to flush the history
  671. ;   buffer.
  672. ;
  673. ;**************************************************************************
  674. cProc HistReset,<PUBLIC,FAR>
  675. cBegin
  676. cEnd
  677. ;**************************************************************************
  678. ; CmdWatchDelAll()
  679. ; Purpose:
  680. ; Called when 'View/Watch Delete' menu is selected.
  681. ; Delete all active WATCH expressions
  682. ;
  683. ;**************************************************************************
  684. cProc CmdWatchDelAll,<PUBLIC,FAR>
  685. cBegin
  686. WDelLoop:
  687. call WatchInfoUI ;make sure cWatch is up-to-date
  688. mov bx,[cWatch]
  689. dec bx
  690. js WDelExit ;brif no watch expressions left
  691. cCall WatchDel,<bx> ;delete watch expression [bx]
  692. jmp SHORT WDelLoop
  693. WDelExit:
  694. cEnd
  695. ;**************************************************************************
  696. ; WatchDeleted
  697. ; Purpose:
  698. ; Called by Text Mgr whenever a Watch expression is deleted.
  699. ; It releases 1 line from the Watch Window in the Debug Screen
  700. ; and remembers to redraw the debug screen.
  701. ;
  702. ;**************************************************************************
  703. cProc WatchDeleted,<PUBLIC,FAR>
  704. cBegin
  705. call WatchRelease ;release any existing WATCH values
  706. call DrawDebugScr ; remember to redraw screen
  707. cEnd
  708. ;**************************************************************************
  709. ; WatchInfoUI
  710. ; Purpose:
  711. ; Given an index for a watch expression, load registers with info
  712. ; about that watch expression.
  713. ; Entry:
  714. ; iWatch = watch index (0 to n)
  715. ; Exit:
  716. ; ax = oRs for text table containing expression
  717. ; bx = pointer to 1 byte valTyp, 8 byte value structure
  718. ; cx = otx to start of expression
  719. ; [cWatch] = number of watch expressions in all loaded modules
  720. ; grs.fDirect is set to FALSE
  721. ;
  722. ;**************************************************************************
  723. PUBLIC WatchInfoUI
  724. WatchInfoUI PROC NEAR
  725. mov bx,[iWatch]
  726. WatchInfoUI ENDP
  727. WatchInfoBx PROC NEAR
  728. call WatchInfo
  729. ret
  730. WatchInfoBx ENDP
  731. ;**************************************************************************
  732. ; WatchName
  733. ; Purpose:
  734. ; Fill bufStdMsg with the title of a watch expression.
  735. ; The text table containing the watch expression is also activated.
  736. ; Entry:
  737. ; ax = oRs for watch pcode
  738. ; cx = otx for watch pcode
  739. ; Exit:
  740. ; entry's register set is activated
  741. ; bufStdMsg = '<context> <expression>: '
  742. ; bx = &bufStdMsg, ax = #bytes in message
  743. ;
  744. ;**************************************************************************
  745. cProc WatchName,<PUBLIC,NEAR>,<si>
  746. localV bdBuf,<size BD>
  747. cBegin
  748. dec cx
  749. dec cx ;back up to opEndProg or prev opWatch
  750. ; ListLine treats these like opBol
  751. mov si,cx ;si = otx for expression
  752. push ax ;preserve ax
  753. push ax ;pass oRs to UiRsActivate
  754. call UiRsActivate
  755. pop ax ;ax = oRs
  756. push ax ;pass oRs to GetRsName
  757. mov al,RSN_fIndent
  758. push ax ;pass GetRsName flags
  759. mov al,20d
  760. push ax ;cbMax = 20
  761. call GetRsName ;fill bufStdMsg with name
  762. ;ax = cbName
  763. mov bx,dataOFFSET bufStdMsg ;bx points to buffer being filled
  764. add bx,ax ;ax points beyond end of context's name
  765. mov BYTE PTR [bx],' '
  766. inc bx ;bx points to dst for expression's name
  767. mov dx,CB_bufStdMsg - 3 ;dx = max chars in context + expression
  768. DbAssertRel CB_bufStdMsg,ae,40d,UI,<WatchName: msg buffer too small>
  769. sub dx,ax ;dx = max chars left for expression
  770. mov [bdBuf.BD_cbLogical],dx ;pass cbMax to ListLine
  771. mov [bdBuf.BD_pb],bx ;pass ptr to buffer to ListLine
  772. push bx ;save ptr to expression's name
  773. lea bx,bdBuf
  774. push si ;pass otx to ListLine
  775. push bx
  776. call ListLine ;ax = #bytes listed
  777. pop bx ;bx points to szExpression
  778. add bx,ax ;bx points to 0-byte terminator
  779. mov ax,dataOFFSET bufStdMsg + 40d
  780. cmp bx,ax
  781. jb LengthOk ;brif length of context+name < 40
  782. xchg bx,ax ;truncate length of name to 40
  783. ; 20 for context, 20 for expression
  784. LengthOk:
  785. mov WORD PTR [bx]," :" ;store ": " at end of expression
  786. inc bx
  787. inc bx ;return ax = new cbMsg
  788. mov BYTE PTR [bx],0 ;store 0-byte terminator
  789. mov ax,dataOFFSET bufStdMsg ;ax points to start of name
  790. xchg ax,bx ;bx points to start of name (ret value)
  791. ;ax points to end of name
  792. sub ax,bx ;ax = length of name (return value)
  793. cEnd
  794. ;**************************************************************************
  795. ; WatchNameId(idWatch)
  796. ; Purpose:
  797. ; Fill bufStdMsg with the title of a watch expression.
  798. ; The text table containing the watch expression is also activated.
  799. ; Entry:
  800. ; idWatch = id of watch expression (0..WATCH_MAX)
  801. ; Exit:
  802. ; entry's register set is activated
  803. ; bufStdMsg = '<context> <expression>: '
  804. ;
  805. ;**************************************************************************
  806. cProc WatchNameId,<PUBLIC,NEAR>
  807. parmW id
  808. cBegin
  809. mov bx,[id]
  810. call WatchInfoBx ;ax = oRs, cx = otx for id
  811. ;bx = ptr to valTyp, value
  812. call WatchName ;fill bufStdMsg with title (id)
  813. ;bx = pbMsg, ax = cbMsg
  814. cEnd
  815. ;**************************************************************************
  816. ; WatchPrint
  817. ; Purpose:
  818. ; Display some information in the Watch window
  819. ;
  820. ; Entry:
  821. ; [iWatch] = 0 to n and identifies an entry in the watch window
  822. ; bx = pbMsg
  823. ; ax = cbMsg
  824. ; cx = ALERT flag (0 for normal, non-zero for WatchBreak value)
  825. ; dx = the type of information as follows:
  826. ;      0:  expression's title
  827. ;      1:  expression's value
  828. ;
  829. ;**************************************************************************
  830. cProc WatchPrint,<PUBLIC,NEAR>,<si,di>
  831. localV rrc,<size _ARC>
  832. cBegin
  833. ;preserve window's current attribute, set it to Watch Window's attr
  834. xchg si,bx ;si = pbMsg
  835. mov di,isaWatchWindow ; [17] di = current isa
  836. jcxz NotAlert
  837. mov di,isaWatchpointHilite
  838. NotAlert:
  839. mov bx,dataOFFSET tCbWatchTitle
  840. add bx,[iWatch] ;bx points to cbTitle field
  841. or dx,dx
  842. je Type0 ;brif not printing Watch Value
  843. mov dl,[bx] ;dx = 1 column beyond title
  844. jmp SHORT DisplayIt
  845. Type0:
  846. mov [bx],al ;tCbWatchTitle[iWatch] = cbMsg
  847. ;ax = byte count
  848. ;dx = 1st column to write
  849. ;si = ptr to string to write
  850. ;
  851. DisplayIt:
  852. mov cx,80d
  853. mov bx,ax
  854. add bx,dx
  855. sub bx,cx
  856. jbe Fits
  857. sub ax,bx
  858. jb WpExit ;if new starting column is negative
  859. Fits:
  860. PUSHI cx,<dataOFFSET wndDebug>
  861. push dx ;pass rx
  862. push [iWatch] ;pass ry
  863. push si ;pass ptr to string
  864. push ax ;pass cch (byte count)
  865. push di ;pass isa
  866. call TextOut
  867. WpExit:
  868. cEnd
  869. ;**************************************************************************
  870. ; WatchValue
  871. ; Purpose:
  872. ; Called by DebugWatch and DrawWatch to list
  873. ; an expression's value into a buffer in ASCII format.
  874. ;
  875. ; [23] Modified to not call WatchPrint (just list to buffer).
  876. ;
  877. ; Entry:
  878. ; bx points to 1 byte valTyp, 8 byte value structure
  879. ; [iWatch] = watch id (0..n)
  880. ; Exit:
  881. ; bx - points to value in display (ASCII) format
  882. ; ax - cb - length of string pointed to by bx.
  883. ; cx - fAlert - TRUE if watch is a watchpoint.
  884. ;
  885. ;**************************************************************************
  886. DbPub WatchValue
  887. cProc WatchValue,<NEAR>
  888. cBegin
  889. mov al,[bx] ;al = value type
  890. inc bx ;bx points to value
  891. xor ah,ah ;ax = 0 if no value
  892. or al,al
  893. je NoValue
  894. js WatchErr ;brif value = standard error code
  895. cmp al,12h
  896. je WValPoint ;brif got watch point
  897. cmp al,24h
  898. je WValStr ;brif got string
  899. push ds
  900. pop es ;es = DGROUP (for B$IFOUT)
  901. ;inputs to B$IFOUT are bx->number, al = type, es=ds
  902. call B$IFOUT  ;bx = adr of ascii string
  903. ;ax = byte count
  904. jmp SHORT WValNoAlert
  905. WValStr:
  906. mov ax,[bx.SD_cb] ;ax = byte count for WatchValue
  907. mov bx,[bx.SD_pb] ;bx = ptr to WatchValue
  908. ;bx = pbMsg, ax = cbMsg
  909. WValNoAlert:
  910. sub cx,cx ;normal, not Alert attribute
  911. jmp SHORT WValPrint
  912. WatchErr:
  913. sub cx,cx ;cx = FALSE (no alert)
  914. mov ax,[bx] ;ax = MSG_xxx (standard error code)
  915. jmp SHORT PrintStdMsg
  916. WValPoint:
  917. sub cx,cx ;cx = FALSE (no alert)
  918. mov ax,MSG_FALSE
  919. cmp WORD PTR [bx],0 ;test boolean's value
  920. je PrintStdMsg ;brif boolean expression is TRUE
  921. .errnz MSG_TRUE - MSG_FALSE - 1
  922. inc ax ;ax = MSG_TRUE
  923. dec cx ;cx = TRUE (alert)
  924. PrintStdMsg:
  925. push cx ;preserve alert flag
  926. push ax ;pass msg id to ListStdMsg
  927. call ListStdMsg ;ax = byte count of msg
  928. pop cx ;restore alert flag
  929. mov bx,dataOFFSET bufStdMsg ;bx points to start of msg
  930. ;bx = pbMsg, ax = cbMsg
  931. ;cx = ALERT flag (0 for normal, non-zero for WatchBreak value)
  932. WValPrint:
  933. NoValue:
  934. cEnd
  935. ;**************************************************************************
  936. ; DrawWatch()
  937. ; Purpose:
  938. ; Called to draw Watch Window whenever the debug screen is being drawn.
  939. ;
  940. ;**************************************************************************
  941. cProc DrawWatch,<PUBLIC,NEAR>
  942. cBegin
  943. mov ax,[cWatch] ;ax = # watch active expressions
  944. ;if      FV_INSTWAT       
  945. ;      sub     ax,[cInstWatch]      ; Leave out any instant watch.
  946. ;endif   ;FV_INSTWAT      
  947. mov [iWatch],ax ;start with bottom WATCH line
  948. DwLoop:
  949. mov ax,[iWatch]
  950. dec ax
  951. mov [iWatch],ax
  952. js DwExit ;brif end of watch expressions
  953. ;i.e. if iWatch == UNDEFINED
  954. call WatchInfoUI ;ax = oRs, cx = otx for iWatch
  955. ;[bx] = ptr to valTyp, value
  956. push bx ;save ptr to watch value
  957. call WatchName ;fill bufStdMsg with title (iWatch)
  958. ;bx = pbMsg, ax = cbMsg
  959. sub dx,dx ;watchInfo = TITLE
  960. sub cx,cx ;not ALERT
  961. call WatchPrint ;display Watch title
  962. pop bx ;bx = ptr to watch value
  963. call WatchValue ;display Watch value on screen
  964. ;bx = pbMsg, ax = cbMsg, cx = fAlert
  965. mov dx,1 ;print value, not title
  966. call WatchPrint
  967. jmp SHORT DwLoop
  968. DwExit:
  969. cEnd
  970. ;**************************************************************************
  971. ; DebugWatch()
  972. ; Purpose:
  973. ; This is called when we enter direct mode while any watch expressions
  974. ; are active.  It updates the display by executing the watch opcodes.
  975. ; Note:
  976. ; Currently, the only watch expressions which get updated are those
  977. ; from the current context (i.e. if a SUB is active, only expressions
  978. ; entered while the SUBs list window was active are updated).
  979. ; If you are tempted to allow all watch expressions to be updated
  980. ; no matter which oRs is active, be warned:  The scanner must
  981. ; prevent function and DEF FN references in WATCH pcode, the
  982. ; most recent BP for the sub must be loaded into BP temporarily
  983. ; (so the most recent incarnation of the SUBs variables can be
  984. ; accessed), error and event trapping would have to be disabled.
  985. ; Entry:
  986. ; [iWatch] = UNDEFINED if UserInterface was entered after executing
  987. ;    user pcode.
  988. ; [iWatch] = 0..n if UserInterface was entered after executing
  989. ;    watch expression [iWatch]
  990. ; Exit:
  991. ; if next pcode to execute is Watch pcode
  992. ;    iWatch is set to 0..n, indicating which Watch pcode is being executed
  993. ;    grs.otxCur is set pointing to the watch pcode to execute
  994. ;    grs.fDirect is set FALSE.
  995. ;    grs.GRS_flags.FG_WatchActive is set
  996. ;    returns TRUE (non-zero)
  997. ; if next pcode to execute is user pcode
  998. ;    iWatch is set to UNDEFINED
  999. ;    grs.otxCur, grs.fDirect, grs.oRsCur are restored from the
  1000. ;       static values which were saved by DebugWatch when the last
  1001. ;       user pcode finished executing
  1002. ;    grs.GRS_flags.FG_WatchActive is clear
  1003. ;    returns FALSE
  1004. ; Condition codes are set based on value in ax
  1005. ;
  1006. ;**************************************************************************
  1007. ;Note:
  1008. ; The code is organized so that the most common path makes no branches
  1009. ; so it is as fast as possible.
  1010. ;
  1011. ;NOTE: This isn't the main entry --- DebugWatch is below.  This is here
  1012. ; for optimal short-jump space.
  1013. ; dl = [debugFlags]
  1014. UserPcode:
  1015. ;If we execute Watch pcode after each direct mode statement, we could
  1016. ;never execute RUN or SYSTEM if one of the Watchpoints was TRUE.
  1017. ;So, we just execute it at the end (opEot) of the direct mode stmt.
  1018. test dl,DEBUG_ERROR OR DEBUG_STOP
  1019. jne J1_DWatchFalse ;brif runtime error in user-pcode
  1020. mov ax,[grs.GRS_otxCur] ;capture cur execution state in ax,bl
  1021. mov bl,[grs.GRS_fDirect]
  1022. or bl,bl
  1023. je SaveState1 ;brif not executing Direct Mode stmts
  1024. test [grs.GRS_flags],FG_allSsExecute
  1025. je J1_DWatchFalse ;can't execute WATCH pcode if some
  1026. ; text table isn't scanned to SS_EXECUTE
  1027. inc ax ;test for UNDEFINED
  1028. je SaveState ;brif just executed an dir mode opEot
  1029. J1_DWatchFalse:
  1030. jmp DWatchFalse ;brif user stmt had an error
  1031. SaveState:
  1032. ;preserve state of user's pcode before we begin executing WATCH pcode
  1033. dec ax ;restore ax = grs.otxCur
  1034. SaveState1:
  1035. mov [bpWatchSave],bp
  1036. mov [otxWatchSave],ax
  1037. mov ax,[b$errnum]
  1038. mov [errnumSave],ax 
  1039. mov [fDirectSave],bl
  1040. sub ax,ax ;initial iWatch is 0
  1041. jmp SHORT ExWatchPcode
  1042. cProc DebugWatch,<PUBLIC,FAR>
  1043. cBegin
  1044. NextWatch:
  1045. mov dl,[debugFlags]
  1046. or dl,dl
  1047. .errnz DEBUG_CANT_CONT - 80h
  1048. js J1_DWatchFalse ;don't try to watch if can't continue
  1049. ; otherwise it screws up error reporting
  1050. mov ax,[iWatch]
  1051. inc ax ;test for UNDEFINED
  1052. je UserPcode ;brif just executed user pcode
  1053. ;ax = index for next WATCH pcode to execute
  1054. ExWatchPcode:
  1055. cmp bp,[bpWatchSave]
  1056. jb WatchInUserFunc ;brif Watch expression is evaluating
  1057. ; a user-pcode function.  Don't execute
  1058. ; watch expressions recursively.
  1059. test [debugFlags],DEBUG_ERROR
  1060. je NoWatchErr ;brif no error in previous watch-pcode
  1061. push ax ;save iWatch for next watch expression
  1062. and [debugFlags],NOT DEBUG_ERROR
  1063. call WatchInfoUI ;bx = ptr to valTyp, value
  1064. ; for watch expression with error
  1065. push bx ;save ptr to watch entry
  1066. push bx ;pass parm = ptr to watch entry
  1067. call ZeroWatchVal ;release string descriptor if any
  1068. pop bx ;bx = ptr to watch entry
  1069. mov BYTE PTR [bx],0FFh ;valtyp = std error code
  1070. sub ax,ax
  1071. xchg ax,[b$ErrNum]
  1072. mov [bx+1],ax ;save error code
  1073. pop ax ;restore ax = iWatch for next expression
  1074. ;ax = index for next WATCH pcode to execute
  1075. NoWatchErr:
  1076. cmp ax,[cWatch]
  1077. jae EndWatch ;brif last watch exp has been executed
  1078. mov [iWatch],ax
  1079. xchg bx,ax ;bx = iWatch
  1080. call WatchInfo ;ax = oRs for text table for iWatch
  1081. ;cx = otx to start of watch pcode
  1082. ;bx = ptr to valTyp, value
  1083. ;grs.fDirect = FALSE
  1084. cmp ax,[grs.GRS_oRsCur]
  1085. jne DOutOfScope ;brif exp isn't from current context
  1086. mov [pWatchVal],bx ;tell executor where to store value
  1087. mov [grs.GRS_otxCur],cx
  1088. mov [grs.GRS_fDirect],0
  1089. or [grs.GRS_flags],FG_WatchActive
  1090. DbAssertTst [grs.GRS_flags],ne,FG_allSsExecute,UI,<DebugWatch err1>
  1091. DWatchTrue:
  1092. mov ax,sp ;return TRUE - tells caller we're
  1093. ; about to execute watch-pcode
  1094. or ax,ax ;set condition codes for caller
  1095. DWatchExit:
  1096. cEnd
  1097. ;bx points to entry in watch table for current watch expression
  1098. DOutOfScope:
  1099. DbHalt UI,<DOutOfScope: Watch code not enabled for LQB>
  1100. or [debugFlags],DEBUG_ERROR
  1101. jmp NextWatch ;go get next watch expression
  1102. ;Watch expression is evaluating a user supplied function
  1103. ;If runtime error occurs within a watch expression, it is untrappable
  1104. ; and reported.
  1105. ;Otherwise, just return and continue executing the function.
  1106. ;This causes TRACE to be disabled during WATCH pcode.
  1107. ;
  1108. WatchInUserFunc:
  1109. test [debugFlags],DEBUG_ERROR OR DEBUG_STOP
  1110. je DWatchTrue ;brif watch expression had no error
  1111. or [debugFlags],DEBUG_CANT_CONT
  1112. ;don't allow user to continue after
  1113. ; error in Watch function
  1114. jmp SHORT DWatchFalse ;let error/breakpoint/stop within
  1115. ;user-function be reported.
  1116. EndWatch:
  1117. cmp [fDebugScr],FALSE
  1118. je NoDebugScr ;brif debug screen not visible
  1119. DebDrawLoop:
  1120. call WatchInfoUI ;bx = ptr to valTyp, value
  1121. call WatchValue ;display Watch value on screen
  1122. mov dx,1 ;print value, not title
  1123. call WatchPrint
  1124. dec [iWatch]
  1125. jns DebDrawLoop
  1126. ;Restore state of user-pcode that was interrupted to execute watch-pcode
  1127. NoDebugScr:
  1128. mov al,[fDirectSave]
  1129. mov [grs.GRS_fDirect],al
  1130. mov ax,[errnumSave]  ;restore value of b$errnum from
  1131. mov [b$errnum],ax ;  before WATCH pcode execution
  1132. mov ax,[otxWatchSave]
  1133. mov [grs.GRS_otxCur],ax
  1134. DbAssertRel bp,e,[bpWatchSave],UI,<DebugWatch: invalid bp>
  1135. DWatchFalse:
  1136. and [grs.GRS_flags],NOT FG_WatchActive
  1137. mov ax,UNDEFINED
  1138. mov [iWatch],ax
  1139. inc ax ;return FALSE - tells caller we're
  1140. jmp SHORT DWatchExit ;about to execute user-pcode
  1141. ;Condition codes are also set for caller
  1142. sEnd UI
  1143. end