uidebug.asm
资源名称:DOS系统的源代码.rar [点击查看]
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:38k
源码类别:
操作系统开发
开发平台:
Visual C++
- TITLE uidebug.asm - User interface to debugger.
- ;***
- ;uidebug.asm
- ;
- ; Copyright <C> 1985-1988, Microsoft Corporation
- ;
- ;Purpose:
- ; Debugging support.
- ;
- ;
- ;*******************************************************************************
- .xlist
- include version.inc
- UIDEBUG_ASM = ON
- ;Include twin interface headers
- include cw/version.inc
- include cw/windows.inc
- include cw/edityp.inc
- ;Next, include QBI's headers
- includeOnce architec
- includeOnce context
- includeOnce executor
- includeOnce heap
- includeOnce lister
- includeOnce opmin
- includeOnce opstmt
- includeOnce parser
- includeOnce qbimsgs
- includeOnce scanner
- includeOnce txtmgr
- includeOnce ui
- includeOnce uiint
- includeOnce util
- includeOnce uimenu
- .list
- ;---------------------------------------------------------------------------
- ;
- ; The following demonstrates how the user interface code interacts with
- ; the executor code to handle watchpoints and watch expressions.
- ; We start the discussion in UserInterface with the following program loaded:
- ; A=1
- ; A=2
- ; The pcode for this program is:
- ; opBol
- ; opLit1
- ; opIdSt(A)
- ; opBol
- ; opLit2
- ; opIdSt(A)
- ; opEndProg
- ;
- ; - User presses single step key, causing UserInterface to exit
- ; - opBol executes, sees DEBUG_TRACE bit set in debugFlags, enters UserInterface
- ; - User selects Watchpoint... menu, CmdWatchAdd(WT_Watch) prompts the user
- ; for an expression, parses it to pcode, and inserts it at the end of the
- ; text table.
- ; - User selects Watch... menu, CmdWatchAdd(WT_WatchPoint) prompts the user
- ; for an expression, parses it to pcode, and inserts it at the end of the
- ; text table.
- ; - We now have with a WATCHPOINT of "A=1" and a WATCH EXPRESSION of "A" and
- ; the pcode looks like:
- ; opBol
- ; opLit1
- ; opIdSt(A)
- ; opBol
- ; opLit2
- ; opIdSt(A)
- ; opEndProg
- ; opIdLd(A)
- ; opLit1
- ; opEQ
- ; opWatchStop
- ; opIdLd(A)
- ; opWatchExp
- ; opEot
- ;
- ; - User presses single step key. When UserInterface exits, it sees active
- ; Watch expressions, and sets DEBUG_WATCH in debugFlags.
- ; - opLit1 and opIdSt(A) execute
- ; - opBol executes, sees bits set in debugFlags, enters UserInterface
- ; - UserInterface immediately dispatches to DebugWatch. DebugWatch sees
- ; iWatch (static counter variable) is UNDEFINED (meaning we weren't executing
- ; Watch pcode), saves current pc in otxWatchSave, sets the
- ; current pc to the 1st watch expression's pcode, sets iWatch to 0,
- ; returns to UserInterface with flags telling it to dispatch.
- ; - opIdLd(A), opLit1, and opEQ execute.
- ; - opWatchStop executes, sees a TRUE (non-zero) argument on the stack, sets
- ; DEBUG_BREAK in debugFlags. opWatchStop then falls into opBol which sees
- ; debugFlags non-zero and enters UserInterface.
- ; - UserInterface immediately dispatches to DebugWatch. DebugWatch sees
- ; iWatch is 0, bumps it to 1, sets the current pc to the 2nd watch
- ; expression's pcode, returns to UserInterface with flags telling it to dispatch.
- ; - opIdLd(A) executes.
- ; - opWatch executes, saves value at [pWatchVal], opWatch then falls into
- ; opBol which sees debugFlags non-zero and enters UserInterface.
- ; - UserInterface immediately dispatches to DebugWatch. DebugWatch sees
- ; iWatch is 1, restores the current pc to otxWatchSave,
- ; returns to UserInterface.
- ; - UserInterface then sees DEBUG_BREAK is set, and would have stopped program
- ; execution even if we weren't tracing. UserInterface then interacts with
- ; the user until the user gives another command.
- ; - User presses single step key. When UserInterface exits, it sees active
- ; Watch expressions, and sets DEBUG_WATCH in debugFlags.
- ; - opLit2 and opIdSt(A) execute
- ; - opEndProg executes, causing us to once again enter UserInterface
- ;
- ;---------------------------------------------------------------------------
- assumes DS,DATA
- assumes ES,NOTHING
- assumes SS,DATA
- EXTRN B$BEEP:FAR
- EXTRN B$IFOUT:FAR
- EXTRN B$Pause:FAR
- sBegin DATA
- EXTRN b$ErrNum:word ;error code for last runtime error
- EXTRN b$CurFrame:word ;current frame ptr (for PTRACE)
- EXTRN b$MainFrame:word ;base frame ptr
- EXTRN fRecord:byte ;set TRUE is /RCD switch seen
- EXTRN fPlayBack:word ;TRUE if we're playing back.
- ; an event playback file.
- EXTRN axMac:byte
- externB HelpFlags ; uiint.inc/h
- ;Points to space allocated by CallsMenuInit, released by CallsMenuTerm
- ;
- pbCallsRelease DW 0
- ;iWatch is used by several functions involved in drawing the content
- ; of the watch window. It indicates which line in the window is currently
- ; being drawn (0 to n)
- ;
- DbPub iWatch
- iWatch DW UNDEFINED
- ; iInstWatch is used to keep track of where an Instant Watch entry is
- ; in the tWatch table. The value of iInstWatch is only significant if
- ; the value of cInstWatch is non-zero.
- DbPub iInstWatch
- iInstWatch DW 0
- ;fRefreshWatch is set TRUE whenever a WATCH entry is added or removed.
- ;It causes us to refresh the WATCH window.
- ;
- PUBLIC fRefreshWatch
- fRefreshWatch DB 0
- ;pWatchVal points to valtyp/value structure to be filled in by Watch executors
- PUBLIC pWatchVal
- pWatchVal DW 0
- ;1 entry per watch expression - number of bytes in expression's title
- tCbWatchTitle DB (WATCH_MAX+1) DUP (?) ; "+1" is for Instant Watch
- otxWatchSave DW 0 ;copy of grs.otxCur while WATCH pcode executes
- errnumSave DW 0 ; copy of b$errnum while WATCH pcode executes
- bpWatchSave DW 0 ;copy of bp for start of current WATCH expression
- fDirectSave DB 0 ;copy of grs.fDirect while WATCH pcode executes
- ;Trace modes
- ;
- TRACE_OFF EQU 0
- TRACE_HISTORY EQU 1 ;Debug/History menu item is ON
- TRACE_ANIMATE EQU 2 ;Debug/Trace menu item is ON
- TRACE_STEP EQU 3 ;F8 was pressed last time in UserInterface
- TRACE_PSTEP EQU 4 ;F10 was pressed last time in UserInterface
- TRACE_WATCHSTEP EQU 5 ;Used by watch to force watch code to execute.
- traceMode DB TRACE_OFF
- pStepFrame DW 0
- nonStickyBpRs DW 0
- nonStickyBpLn DW UNDEFINED
- CHIST EQU 20 ;we will remember last 20 statements executed
- CBHIST EQU 4 ;number of bytes in 1 history entry
- bdHist DB size BD DUP (0)
- oHistNext DW 0
- oHistShow DW 0
- histFlags DB 0
- FH_Full equ 01H
- FH_NotEmpty equ 02H
- szRun DB "RUN",0
- sEnd DATA
- sBegin CODE
- ;Table of opcodes(1) which descanner inserts where it finds return
- ; addresses on the stack:
- ;
- tOpNoList LABEL WORD
- opTabStart NOLIST
- opTabEntry NOLIST,opNoList1
- opTabEntry NOLIST,opEot
- sEnd CODE
- sBegin UI
- assumes cs,UI
- ;**************************************************************************
- ; DoRunOrCont(ax:fFromStart)
- ; Purpose:
- ; Setup so program will continue execution.
- ; If can't continue then start at begining.
- ;
- ; Entry:
- ; ax = fFromStart - if TRUE start program from the beginning.
- ; Exit:
- ; fGotCmd is set TRUE (which terminates GetCmd)
- ;
- ;**************************************************************************
- DoCont PROC NEAR
- sub ax,ax
- DoCont ENDP
- ;fall into DoRunOrCont
- cProc DoRunOrCont,<NEAR>
- cBegin
- or ax,ax
- jne FromStart
- call fCanContUI
- jne NotFromStart ;brif can continue
- ; FNextStmtDoesIO uses grs.otxCONT to determine if the next statement to
- ; execute will do output. ContContext is called just before FNextStmtDoesIO.
- ; if grs.otxCONT is UNDEFINED, ContContext will
- ; set grs.otxCONT to the begining of the main module.
- ;
- FromStart:
- call CantCont ;sets [grs.GRS_otxCONT] to UNDEFINED
- PUSHI ax,<dataOFFSET szRUN>
- call DoCmd
- NotFromStart:
- mov [fGotCmd],sp
- cEnd
- ;**************************************************************************
- ; SetTronTroff
- ; Purpose:
- ; Set [traceMode] and set DEBUG_TRACE bit in [debugFlags] if not TRACE_OFF
- ; Called by TRON and TROFF opcode executors after they set [fTraceOn]
- ; Entry:
- ; [fTraceOn] = non-zero if TRON is active
- ; [fHistOn] = non-zero if HISTORY is active
- ;
- ;**************************************************************************
- PUBLIC SetTronTroff
- SetTronTroff PROC FAR
- .errnz TRACE_ANIMATE - 2
- mov ax,TRACE_ANIMATE
- cmp [fTraceOn],ah
- jne NoTrace ;brif TRON (Trace ON) is not active
- dec ax ;al = TRACE_HISTORY
- .errnz TRACE_HISTORY - 1
- cmp [fHistOn],ah
- jne NoTrace ;brif History ON is not active
- dec ax ;al = TRACE_OFF
- .errnz TRACE_OFF
- NoTrace:
- call SetTraceMode
- ret ;can't fall into SetTraceMode, far->near
- SetTronTroff ENDP
- ;**************************************************************************
- ; SetTraceMode
- ; Purpose:
- ; Set [traceMode] and set DEBUG_TRACE bit in [debugFlags] if not TRACE_OFF
- ; Entry:
- ; al = new trace mode (TRACE_STEP etc.)
- ;
- ;**************************************************************************
- SetTraceMode PROC NEAR
- mov [traceMode],al
- or al,al
- je GotTroff
- .errnz TRACE_OFF
- or [debugFlags],DEBUG_TRACE
- GotTroff:
- ret
- SetTraceMode ENDP
- ;**************************************************************************
- ; CmdGo(fFromStart)
- ; Purpose:
- ; Continue or start program execution taking into account trace state.
- ; This procedure is called in response to the menu items `Run/Run' and
- ; `Run/Continue'
- ;
- ; Entry:
- ; fTraceOn - non-zero if TRON is active
- ; fFromStart - TRUE if we want to RUN else we want to CONT.
- ;
- ;**************************************************************************
- cProc CmdGo,<PUBLIC,NEAR>
- parmW fFromStart
- cBegin
- call SetTronTroff ;setup based on [fTraceOn]
- mov ax,[fFromStart]
- call DoRunOrCont ;execute a RUN or CONT command
- cEnd
- ;**************************************************************************
- ; CmdSetNextStmt()
- ; Purpose:
- ; Reset instruction pointer to statement at cursor.
- ;
- ;**************************************************************************
- cProc CmdSetNextStmt,<PUBLIC,NEAR>,<si,di>
- cBegin
- call TxtDescan ;descan to SS_PARSE
- call GetEditLine ;ax = current edit line (from EditMgr)
- push ax
- call OtxOfLn ;ax = text offset to start of line
- xchg ax, bx ; bx = otx of pcode to skip.
- call TxtSkipOpFar ;ax = otx beyond the opBol[xx] opcode
- ;We always enter direct mode after
- ;execution of the opBol
- xchg si,ax ;si = otx
- mov di,[grs.GRS_oRsCur] ;di = oRs of current text table
- test [txdCur.TXD_flags],FTX_mrs
- je NotInDefFn ;brif we're in a sub/function window
- push si ;pass otx
- call OPrsOfOtx ;ax = otx of DEF FN
- inc ax ;test for UNDEFINED
- je NotInDefFn ;brif we're in main-level code
- dec ax ;ax = oPrs for DEF FN
- or ah,80h ;ax = oRs of DEF FN
- xchg di,ax ;di = oRs of DEF FN
- NotInDefFn:
- call NeedContContext ;grs.oRsCur=grs.oRsCONT or grs.oMrsMain
- ;if no main module, uierr is set
- je NxtStmtExit ;brif no main module
- cmp di,[grs.GRS_oRsCur]
- je BranchOk ;brif branching within text table
- BadBranch:
- PUSHI ax,MSG_BadNextStmt ;"Cannot cross module/procedure boundary"
- call SetUiErr
- jmp SHORT NxtStmtExit
- BranchOk:
- mov [grs.GRS_otxCONT],si
- call DrawDebugScr ;so new current stmt will be hilighted
- NxtStmtExit:
- cEnd
- ;**************************************************************************
- ; CmdRestart()
- ; Purpose:
- ; Restart program. Like a Step but always starts at begining of program.
- ;
- ;**************************************************************************
- cProc CmdRestart,<PUBLIC,NEAR>
- cBegin
- mov al,TRACE_STEP
- call SetTraceMode
- mov ax,sp ;ax = TRUE (non-zero)
- call DoRunOrCont
- cEnd
- ;**************************************************************************
- ; PStepReset
- ; Purpose:
- ; Called whenever executor resets stack pointer. This guarentees
- ; that DebugTrace will stop the next time it is called (even for F10).
- ;
- ;**************************************************************************
- cProc PStepReset,<PUBLIC,FAR>
- cBegin
- mov [pStepFrame],0
- cEnd
- ;**************************************************************************
- ; CmdStep(fPStep)
- ; Purpose:
- ; Setup to execute the next program statement.
- ; This routine is called in response to the Step and PStep
- ; accelerator keys.
- ;
- ; Entry:
- ; fPStep - if TRUE count procedure calls as one statement (F10).
- ;
- ; Exit:
- ; PStepFrame, debugFlags, traceMode, fGotCmd are all updated
- ;
- ;**************************************************************************
- cProc CmdStep,<PUBLIC,NEAR>
- parmW fPStep
- cBegin
- call ContContext ;activate program counter's context
- call SkipStop ;skip past opBreakPoint or opStStop
- mov ax,[grs.GRS_otxCONT]
- inc ax ;test for UNDEFINED
- je UseBp ;if Can't continue, stop at next entry
- mov ax,[b$CurFrame] ;get current frame
- mov cx,[pGosubLast] ;get gosub stack value
- jcxz UseBp ;zero, use current frame as frame
- cmp cx,ax
- ja UseBp ; brif no gosubs for this frame
- xchg ax,cx ;else use top of stack
- UseBp:
- mov [pStepFrame],ax ;and move it in
- mov al,TRACE_STEP
- cmp [fPStep],FALSE
- je CsNotPStep ;brif F8 was pressed (step into proc)
- .errnz TRACE_STEP - 3
- .errnz TRACE_PSTEP - 4
- inc ax ;al = TRACE_PSTEP (F10=step around proc)
- CsNotPStep:
- call SetTraceMode
- call DoCont ;continue program execution
- cEnd
- ;**************************************************************************
- ; CmdToggleBp()
- ; Purpose:
- ; Toggles the breakpoint setting of the current line.
- ; Note: will only be called if the current window contains code.
- ;
- ; Exit:
- ; If an edit window is active a breakpoint is set/reset at the
- ; current line.
- ; ax active edit line (UNDEFINED if none)
- ;
- ;**************************************************************************
- cProc CmdToggleBp,<PUBLIC,NEAR>
- cBegin
- call UiGrabSpace
- call GetEditLine ;ax = current edit line (from EditMgr)
- push ax ;save for return value
- inc ax ;test for UNDEFINED
- je CsNoEditLine
- dec ax
- push ax ;pass to ToggleBp
- call ToggleBp
- mov [uierr],ax ;store possible error code
- call DrawDebugScr ;Refresh any lines containing
- ;this breakpoint
- CsNoEditLine:
- call UiReleaseSpace
- pop ax ;ax = edit line
- cEnd
- ;**************************************************************************
- ; CmdGoUntilHere()
- ; Purpose:
- ; Sets a non-sticky breakpoint at the current line and runs until it
- ; gets there. When the breakpoint is reached it will automatically be cleared.
- ; Note: will only be called if the current window contains code.
- ;
- ;**************************************************************************
- cProc CmdGoUntilHere,<PUBLIC,NEAR>
- cBegin
- call UiRsActivateWnd ;activate active window's context
- test [mrsCur.MRS_flags2],FM2_Include OR FM2_NoPcode
- jne CgExit ;brif not a pcode window
- call GetEditLine ;get line number
- cCall OtxOfLn,<ax> ;get otx
- cCall fBpSet,<ax> ;see if bp is set
- or ax,ax
- jnz CgGo ;do nothing if bp already set
- call CmdToggleBp ;set break point on current line
- inc ax ;test for UNDEFINED
- je CgExit ;brif no active edit line
- dec ax ;restore ax = line number
- mov [nonStickyBpLn],ax ;remember to reset break point
- mov ax,[grs.GRS_oRsCur]
- mov [nonStickyBpRs],ax
- CgGo:
- call ContContext ;activate program counter's context
- call SkipStop ;skip past the opBreakPoint
- xor ax,ax
- cCall CmdGo,<ax> ;continue program execution
- CgExit:
- cEnd
- ;**************************************************************************
- ; ClrNonStickyBp()
- ; Purpose:
- ; Called on entry to GetCmd()
- ; Clears any breakpoint set by CmdGoUntilHere().
- ; Exit:
- ; Context may be switched to another text table.
- ;
- ;**************************************************************************
- cProc ClrNonStickyBp,<PUBLIC,NEAR>
- cBegin
- mov ax,[nonStickyBpLn]
- inc ax ;test for UNDEFINED
- je ClrNoBp
- dec ax
- push ax ;pass to ToggleBp
- push [nonStickyBpRs] ;pass to UiRsActivate
- call UiRsActivate
- call ToggleBp
- mov [nonStickyBpLn],UNDEFINED
- call DrawDebugScr ;Refresh any lines containing
- ;this breakpoint
- ClrNoBp:
- cEnd
- ;**************************************************************************
- ; DebugError()
- ; Purpose:
- ; Setup to report a runtime error.
- ;
- ; Exit:
- ; uierr and txtErr structure are setup so error will be reported in GetCmd.
- ; Returns mask which tells UserInterface to stop for commands.
- ;
- ;**************************************************************************
- PUBLIC DebugError
- DebugError PROC NEAR
- mov ax,[b$ErrNum]
- cmp ax,MSG_GoDirect
- je DeExit ;Ignore MSG_GoDirect - it is used
- ; when user presses CANCEL button
- ; in some dialog. Easy way to
- ; back all the way out of the dialog.
- or HelpFlags,HLP_RTERR ; this error came from execution
- ;Setup so GetCmd() will call ReportError()
- mov dx,ER_UE ;dx = max standard runtimer error code
- cmp ax,dx ;see if error was generated by user
- ; via ERROR(x) statement
- jbe StdRtErr ;brif std runtime error code
- xchg ax,dx ;ax = "Unprintable error"
- StdRtErr:
- mov [uierr],ax ;error will be reported by GetCmd
- ; calling ReportError()
- mov al,[grs.GRS_fDirect]
- mov [txtErr.TXER_fDirect],al
- mov ax,[grs.GRS_oRsCur]
- mov [txtErr.TXER_oRs],ax
- mov ax,[grs.GRS_otxCur]
- mov [txtErr.TXER_otx],ax
- mov [txtErr.TXER_oSrc],0
- DeExit:
- mov ax,FDM_GetCmd
- jmp SHORT TrOffExit
- DebugError ENDP
- ;**************************************************************************
- ; DebugStop()
- ; Purpose:
- ; Setup to report stop statement.
- ;
- ; Exit:
- ; returns mask which tells UserInterface to show the current statement
- ; and stop for commands.
- ;
- ;**************************************************************************
- PUBLIC DebugStop
- DebugStop PROC NEAR
- mov ax,FDM_GetCmd OR FDM_ShowStmt
- jmp SHORT TrOffExit
- DebugStop ENDP
- ;**************************************************************************
- ; DebugEnd()
- ; Purpose:
- ; Called when the program reaches end-of-pcode or END statement
- ;
- ; Exit:
- ; returns mask which tells UserInterface to stop for commands.
- ;
- ;**************************************************************************
- PUBLIC DebugEnd
- DebugEnd PROC NEAR
- cmp [fDebugScr],FALSE
- jne ShowDeb ;brif debug screen is visible
- cmp [fRecord],FALSE
- jne ShowDeb ;brif recording a playback file
- ; brif not reading a playback file. Since RUNTIME consumes the
- ; keystroke in B$Pause, this would hang the playback file up.
- cmp [fPlayBack],FALSE
- jne ShowDeb
- ; The user has just finished running a program up to an END stmt.
- ; The output screen is still visible. Display the prompt:
- ; 'Press any key to return to editor'
- ; on the bottom line of the output window and wait for the
- ; user to press a key.
- call B$Pause
- ShowDeb:
- cmp [grs.GRS_fDirect],FALSE
- jne DeDirMode ;brif end-of-direct mode execution
- call EnsShowDebugScr ;init debug screen, make it visible
- call DrawDebugScr ;turn off old current stmt highlight
- DeDirMode:
- mov ax,FDM_GetCmd
- TrOffExit:
- mov [traceMode],TRACE_OFF
- ret
- DebugEnd ENDP
- ;**************************************************************************
- ; DebugTrace()
- ; Purpose:
- ; This is invoked when we enter UserInterface with DEBUG_TRACE set in
- ; debugFlags.
- ; Setup to show current statement and depending on the trace mode stop
- ; for commands.
- ;
- ; Entry:
- ; traceMode = TRACE_HISTORY if we are to do nothing more than record
- ; the pcode address of the instruction for History Playback
- ; TRACE_ANIMATE if we are to show stmt and exit direct mode,
- ; TRACE_STEP if we are stopping for each statement (F8),
- ; TRACE_PSTEP if we are stepping around procedure calls (F10).
- ;
- ; Exit:
- ; The current statement's location is recorded in the history buffer.
- ; Returns mask to tell UserInterface to show the current statement
- ; and/or tell it to stop and interact with the user.
- ;
- ;**************************************************************************
- cProc DebugTrace,<PUBLIC,NEAR>,<di>
- cBegin
- call FExecutable ;see if next stmt to be executed
- ; contains any executable code
- jne ItsExecutable ;brif stmt is executable
- sub di,di ;tell UserInterface to take no action
- J1_TrSetTraceFlag:
- jmp SHORT TrSetTraceFlag
- ItsExecutable:
- ;set debugFlags, traceMode, fGotCmd, and al (return value) as follows:
- ;switch (traceMode)
- ; case TRACE_OFF:
- ; fGotCmd remains 0
- ; return al = 0
- ; case TRACE_HISTORY:
- ; fGotCmd remains 0
- ; return al = 0
- ; case TRACE_ANIMATE:
- ; if alternateListWindow is showing new oRs, activate it
- ; if fCantCont, directModeCmd = RUN
- ; fGotCmd = TRUE
- ; return al = FDM_ShowStmt
- ; case TRACE_PSTEP:
- ; if ([pGosubLast] != 0 && ([pGosubLast] < [pStepFrame])) ||
- ; ([pGosubLast] == 0 && ([b$CurFrame] < [pStepFrame]))
- ; fGotCmd = TRUE
- ; return al = 0
- ; else
- ; fall into case TRACE_STEP
- ; case TRACE_WATCHSTEP:
- ; case TRACE_STEP:
- ; fGotCmd remains 0
- ; traceMode = TRACE_OFF
- ; return al = FDM_GetCmd OR (case WATCHSTEP ? 0 :FDM_ShowStmt)
- ;end switch
- ;if traceMode != TRACE_OFF
- ; debugFlags != DEBUG_TRACE
- ;
- sub di,di ;tell UserInterface to take no action
- sub cx,cx
- mov cl,[traceMode] ;cx = traceMode
- dec cx
- .errnz TRACE_OFF
- js SHORT TrSetTraceFlag ;brif traceMode == TRACE_OFF
- .errnz TRACE_HISTORY - 1
- je TrSetTraceFlag ;brif traceMode == TRACE_HISTORY
- loop TrNotAnim ;brif traceMode != TRACE_ANIMATE
- .errnz TRACE_ANIMATE - 2
- sub ax,ax
- push ax
- call CmdGo
- TrShow:
- or di,FDM_ShowStmt
- jmp SHORT TrSetTraceFlag
- TrNotAnim:
- loop TrNotStep ;brif traceMode != TRACE_STEP
- .errnz TRACE_STEP - 3
- .errnz TRACE_WATCHSTEP - 5
- TrStep:
- mov di,FDM_ShowStmt
- TrWatchStep:
- or di,FDM_GetCmd
- mov [traceMode],TRACE_OFF
- jmp SHORT TrSetTraceFlag
- .errnz TRACE_PSTEP - 4
- ;traceMode == TRACE_PSTEP
- TrNotStep:
- loop TrWatchStep
- mov ax,[b$CurFrame] ;get current frame
- mov cx,[pGosubLast] ;get gosub stack value
- jcxz TrUseBp ;zero, use current frame as frame
- cmp cx,ax
- ja TrUseBp ; brif no gosubs for this frame
- xchg ax,cx ;else use top of stack
- TrUseBp:
- cmp [pStepFrame],ax ;compare, and if pstepframe
- jbe TrStep ;watermark is below or equal, step
- TrSkip:
- call DoCont ;continue program execution
- ;di = FDM_xxx actionMask return value
- TrSetTraceFlag:
- cmp [traceMode],TRACE_OFF
- je TrExit ;leave trace flag 0 if not tracing
- or [debugFlags],DEBUG_TRACE
- TrExit:
- xchg ax,di ;ax = return value
- cEnd ;DebugTrace
- ;**************************************************************************
- ; HistReset()
- ; Purpose:
- ; This is called when we Scan/Descan a program to flush the history
- ; buffer.
- ;
- ;**************************************************************************
- cProc HistReset,<PUBLIC,FAR>
- cBegin
- cEnd
- ;**************************************************************************
- ; CmdWatchDelAll()
- ; Purpose:
- ; Called when 'View/Watch Delete' menu is selected.
- ; Delete all active WATCH expressions
- ;
- ;**************************************************************************
- cProc CmdWatchDelAll,<PUBLIC,FAR>
- cBegin
- WDelLoop:
- call WatchInfoUI ;make sure cWatch is up-to-date
- mov bx,[cWatch]
- dec bx
- js WDelExit ;brif no watch expressions left
- cCall WatchDel,<bx> ;delete watch expression [bx]
- jmp SHORT WDelLoop
- WDelExit:
- cEnd
- ;**************************************************************************
- ; WatchDeleted
- ; Purpose:
- ; Called by Text Mgr whenever a Watch expression is deleted.
- ; It releases 1 line from the Watch Window in the Debug Screen
- ; and remembers to redraw the debug screen.
- ;
- ;**************************************************************************
- cProc WatchDeleted,<PUBLIC,FAR>
- cBegin
- call WatchRelease ;release any existing WATCH values
- call DrawDebugScr ; remember to redraw screen
- cEnd
- ;**************************************************************************
- ; WatchInfoUI
- ; Purpose:
- ; Given an index for a watch expression, load registers with info
- ; about that watch expression.
- ; Entry:
- ; iWatch = watch index (0 to n)
- ; Exit:
- ; ax = oRs for text table containing expression
- ; bx = pointer to 1 byte valTyp, 8 byte value structure
- ; cx = otx to start of expression
- ; [cWatch] = number of watch expressions in all loaded modules
- ; grs.fDirect is set to FALSE
- ;
- ;**************************************************************************
- PUBLIC WatchInfoUI
- WatchInfoUI PROC NEAR
- mov bx,[iWatch]
- WatchInfoUI ENDP
- WatchInfoBx PROC NEAR
- call WatchInfo
- ret
- WatchInfoBx ENDP
- ;**************************************************************************
- ; WatchName
- ; Purpose:
- ; Fill bufStdMsg with the title of a watch expression.
- ; The text table containing the watch expression is also activated.
- ; Entry:
- ; ax = oRs for watch pcode
- ; cx = otx for watch pcode
- ; Exit:
- ; entry's register set is activated
- ; bufStdMsg = '<context> <expression>: '
- ; bx = &bufStdMsg, ax = #bytes in message
- ;
- ;**************************************************************************
- cProc WatchName,<PUBLIC,NEAR>,<si>
- localV bdBuf,<size BD>
- cBegin
- dec cx
- dec cx ;back up to opEndProg or prev opWatch
- ; ListLine treats these like opBol
- mov si,cx ;si = otx for expression
- push ax ;preserve ax
- push ax ;pass oRs to UiRsActivate
- call UiRsActivate
- pop ax ;ax = oRs
- push ax ;pass oRs to GetRsName
- mov al,RSN_fIndent
- push ax ;pass GetRsName flags
- mov al,20d
- push ax ;cbMax = 20
- call GetRsName ;fill bufStdMsg with name
- ;ax = cbName
- mov bx,dataOFFSET bufStdMsg ;bx points to buffer being filled
- add bx,ax ;ax points beyond end of context's name
- mov BYTE PTR [bx],' '
- inc bx ;bx points to dst for expression's name
- mov dx,CB_bufStdMsg - 3 ;dx = max chars in context + expression
- DbAssertRel CB_bufStdMsg,ae,40d,UI,<WatchName: msg buffer too small>
- sub dx,ax ;dx = max chars left for expression
- mov [bdBuf.BD_cbLogical],dx ;pass cbMax to ListLine
- mov [bdBuf.BD_pb],bx ;pass ptr to buffer to ListLine
- push bx ;save ptr to expression's name
- lea bx,bdBuf
- push si ;pass otx to ListLine
- push bx
- call ListLine ;ax = #bytes listed
- pop bx ;bx points to szExpression
- add bx,ax ;bx points to 0-byte terminator
- mov ax,dataOFFSET bufStdMsg + 40d
- cmp bx,ax
- jb LengthOk ;brif length of context+name < 40
- xchg bx,ax ;truncate length of name to 40
- ; 20 for context, 20 for expression
- LengthOk:
- mov WORD PTR [bx]," :" ;store ": " at end of expression
- inc bx
- inc bx ;return ax = new cbMsg
- mov BYTE PTR [bx],0 ;store 0-byte terminator
- mov ax,dataOFFSET bufStdMsg ;ax points to start of name
- xchg ax,bx ;bx points to start of name (ret value)
- ;ax points to end of name
- sub ax,bx ;ax = length of name (return value)
- cEnd
- ;**************************************************************************
- ; WatchNameId(idWatch)
- ; Purpose:
- ; Fill bufStdMsg with the title of a watch expression.
- ; The text table containing the watch expression is also activated.
- ; Entry:
- ; idWatch = id of watch expression (0..WATCH_MAX)
- ; Exit:
- ; entry's register set is activated
- ; bufStdMsg = '<context> <expression>: '
- ;
- ;**************************************************************************
- cProc WatchNameId,<PUBLIC,NEAR>
- parmW id
- cBegin
- mov bx,[id]
- call WatchInfoBx ;ax = oRs, cx = otx for id
- ;bx = ptr to valTyp, value
- call WatchName ;fill bufStdMsg with title (id)
- ;bx = pbMsg, ax = cbMsg
- cEnd
- ;**************************************************************************
- ; WatchPrint
- ; Purpose:
- ; Display some information in the Watch window
- ;
- ; Entry:
- ; [iWatch] = 0 to n and identifies an entry in the watch window
- ; bx = pbMsg
- ; ax = cbMsg
- ; cx = ALERT flag (0 for normal, non-zero for WatchBreak value)
- ; dx = the type of information as follows:
- ; 0: expression's title
- ; 1: expression's value
- ;
- ;**************************************************************************
- cProc WatchPrint,<PUBLIC,NEAR>,<si,di>
- localV rrc,<size _ARC>
- cBegin
- ;preserve window's current attribute, set it to Watch Window's attr
- xchg si,bx ;si = pbMsg
- mov di,isaWatchWindow ; [17] di = current isa
- jcxz NotAlert
- mov di,isaWatchpointHilite
- NotAlert:
- mov bx,dataOFFSET tCbWatchTitle
- add bx,[iWatch] ;bx points to cbTitle field
- or dx,dx
- je Type0 ;brif not printing Watch Value
- mov dl,[bx] ;dx = 1 column beyond title
- jmp SHORT DisplayIt
- Type0:
- mov [bx],al ;tCbWatchTitle[iWatch] = cbMsg
- ;ax = byte count
- ;dx = 1st column to write
- ;si = ptr to string to write
- ;
- DisplayIt:
- mov cx,80d
- mov bx,ax
- add bx,dx
- sub bx,cx
- jbe Fits
- sub ax,bx
- jb WpExit ;if new starting column is negative
- Fits:
- PUSHI cx,<dataOFFSET wndDebug>
- push dx ;pass rx
- push [iWatch] ;pass ry
- push si ;pass ptr to string
- push ax ;pass cch (byte count)
- push di ;pass isa
- call TextOut
- WpExit:
- cEnd
- ;**************************************************************************
- ; WatchValue
- ; Purpose:
- ; Called by DebugWatch and DrawWatch to list
- ; an expression's value into a buffer in ASCII format.
- ;
- ; [23] Modified to not call WatchPrint (just list to buffer).
- ;
- ; Entry:
- ; bx points to 1 byte valTyp, 8 byte value structure
- ; [iWatch] = watch id (0..n)
- ; Exit:
- ; bx - points to value in display (ASCII) format
- ; ax - cb - length of string pointed to by bx.
- ; cx - fAlert - TRUE if watch is a watchpoint.
- ;
- ;**************************************************************************
- DbPub WatchValue
- cProc WatchValue,<NEAR>
- cBegin
- mov al,[bx] ;al = value type
- inc bx ;bx points to value
- xor ah,ah ;ax = 0 if no value
- or al,al
- je NoValue
- js WatchErr ;brif value = standard error code
- cmp al,12h
- je WValPoint ;brif got watch point
- cmp al,24h
- je WValStr ;brif got string
- push ds
- pop es ;es = DGROUP (for B$IFOUT)
- ;inputs to B$IFOUT are bx->number, al = type, es=ds
- call B$IFOUT ;bx = adr of ascii string
- ;ax = byte count
- jmp SHORT WValNoAlert
- WValStr:
- mov ax,[bx.SD_cb] ;ax = byte count for WatchValue
- mov bx,[bx.SD_pb] ;bx = ptr to WatchValue
- ;bx = pbMsg, ax = cbMsg
- WValNoAlert:
- sub cx,cx ;normal, not Alert attribute
- jmp SHORT WValPrint
- WatchErr:
- sub cx,cx ;cx = FALSE (no alert)
- mov ax,[bx] ;ax = MSG_xxx (standard error code)
- jmp SHORT PrintStdMsg
- WValPoint:
- sub cx,cx ;cx = FALSE (no alert)
- mov ax,MSG_FALSE
- cmp WORD PTR [bx],0 ;test boolean's value
- je PrintStdMsg ;brif boolean expression is TRUE
- .errnz MSG_TRUE - MSG_FALSE - 1
- inc ax ;ax = MSG_TRUE
- dec cx ;cx = TRUE (alert)
- PrintStdMsg:
- push cx ;preserve alert flag
- push ax ;pass msg id to ListStdMsg
- call ListStdMsg ;ax = byte count of msg
- pop cx ;restore alert flag
- mov bx,dataOFFSET bufStdMsg ;bx points to start of msg
- ;bx = pbMsg, ax = cbMsg
- ;cx = ALERT flag (0 for normal, non-zero for WatchBreak value)
- WValPrint:
- NoValue:
- cEnd
- ;**************************************************************************
- ; DrawWatch()
- ; Purpose:
- ; Called to draw Watch Window whenever the debug screen is being drawn.
- ;
- ;**************************************************************************
- cProc DrawWatch,<PUBLIC,NEAR>
- cBegin
- mov ax,[cWatch] ;ax = # watch active expressions
- ;if FV_INSTWAT
- ; sub ax,[cInstWatch] ; Leave out any instant watch.
- ;endif ;FV_INSTWAT
- mov [iWatch],ax ;start with bottom WATCH line
- DwLoop:
- mov ax,[iWatch]
- dec ax
- mov [iWatch],ax
- js DwExit ;brif end of watch expressions
- ;i.e. if iWatch == UNDEFINED
- call WatchInfoUI ;ax = oRs, cx = otx for iWatch
- ;[bx] = ptr to valTyp, value
- push bx ;save ptr to watch value
- call WatchName ;fill bufStdMsg with title (iWatch)
- ;bx = pbMsg, ax = cbMsg
- sub dx,dx ;watchInfo = TITLE
- sub cx,cx ;not ALERT
- call WatchPrint ;display Watch title
- pop bx ;bx = ptr to watch value
- call WatchValue ;display Watch value on screen
- ;bx = pbMsg, ax = cbMsg, cx = fAlert
- mov dx,1 ;print value, not title
- call WatchPrint
- jmp SHORT DwLoop
- DwExit:
- cEnd
- ;**************************************************************************
- ; DebugWatch()
- ; Purpose:
- ; This is called when we enter direct mode while any watch expressions
- ; are active. It updates the display by executing the watch opcodes.
- ; Note:
- ; Currently, the only watch expressions which get updated are those
- ; from the current context (i.e. if a SUB is active, only expressions
- ; entered while the SUBs list window was active are updated).
- ; If you are tempted to allow all watch expressions to be updated
- ; no matter which oRs is active, be warned: The scanner must
- ; prevent function and DEF FN references in WATCH pcode, the
- ; most recent BP for the sub must be loaded into BP temporarily
- ; (so the most recent incarnation of the SUBs variables can be
- ; accessed), error and event trapping would have to be disabled.
- ; Entry:
- ; [iWatch] = UNDEFINED if UserInterface was entered after executing
- ; user pcode.
- ; [iWatch] = 0..n if UserInterface was entered after executing
- ; watch expression [iWatch]
- ; Exit:
- ; if next pcode to execute is Watch pcode
- ; iWatch is set to 0..n, indicating which Watch pcode is being executed
- ; grs.otxCur is set pointing to the watch pcode to execute
- ; grs.fDirect is set FALSE.
- ; grs.GRS_flags.FG_WatchActive is set
- ; returns TRUE (non-zero)
- ; if next pcode to execute is user pcode
- ; iWatch is set to UNDEFINED
- ; grs.otxCur, grs.fDirect, grs.oRsCur are restored from the
- ; static values which were saved by DebugWatch when the last
- ; user pcode finished executing
- ; grs.GRS_flags.FG_WatchActive is clear
- ; returns FALSE
- ; Condition codes are set based on value in ax
- ;
- ;**************************************************************************
- ;Note:
- ; The code is organized so that the most common path makes no branches
- ; so it is as fast as possible.
- ;
- ;NOTE: This isn't the main entry --- DebugWatch is below. This is here
- ; for optimal short-jump space.
- ; dl = [debugFlags]
- UserPcode:
- ;If we execute Watch pcode after each direct mode statement, we could
- ;never execute RUN or SYSTEM if one of the Watchpoints was TRUE.
- ;So, we just execute it at the end (opEot) of the direct mode stmt.
- test dl,DEBUG_ERROR OR DEBUG_STOP
- jne J1_DWatchFalse ;brif runtime error in user-pcode
- mov ax,[grs.GRS_otxCur] ;capture cur execution state in ax,bl
- mov bl,[grs.GRS_fDirect]
- or bl,bl
- je SaveState1 ;brif not executing Direct Mode stmts
- test [grs.GRS_flags],FG_allSsExecute
- je J1_DWatchFalse ;can't execute WATCH pcode if some
- ; text table isn't scanned to SS_EXECUTE
- inc ax ;test for UNDEFINED
- je SaveState ;brif just executed an dir mode opEot
- J1_DWatchFalse:
- jmp DWatchFalse ;brif user stmt had an error
- SaveState:
- ;preserve state of user's pcode before we begin executing WATCH pcode
- dec ax ;restore ax = grs.otxCur
- SaveState1:
- mov [bpWatchSave],bp
- mov [otxWatchSave],ax
- mov ax,[b$errnum]
- mov [errnumSave],ax
- mov [fDirectSave],bl
- sub ax,ax ;initial iWatch is 0
- jmp SHORT ExWatchPcode
- cProc DebugWatch,<PUBLIC,FAR>
- cBegin
- NextWatch:
- mov dl,[debugFlags]
- or dl,dl
- .errnz DEBUG_CANT_CONT - 80h
- js J1_DWatchFalse ;don't try to watch if can't continue
- ; otherwise it screws up error reporting
- mov ax,[iWatch]
- inc ax ;test for UNDEFINED
- je UserPcode ;brif just executed user pcode
- ;ax = index for next WATCH pcode to execute
- ExWatchPcode:
- cmp bp,[bpWatchSave]
- jb WatchInUserFunc ;brif Watch expression is evaluating
- ; a user-pcode function. Don't execute
- ; watch expressions recursively.
- test [debugFlags],DEBUG_ERROR
- je NoWatchErr ;brif no error in previous watch-pcode
- push ax ;save iWatch for next watch expression
- and [debugFlags],NOT DEBUG_ERROR
- call WatchInfoUI ;bx = ptr to valTyp, value
- ; for watch expression with error
- push bx ;save ptr to watch entry
- push bx ;pass parm = ptr to watch entry
- call ZeroWatchVal ;release string descriptor if any
- pop bx ;bx = ptr to watch entry
- mov BYTE PTR [bx],0FFh ;valtyp = std error code
- sub ax,ax
- xchg ax,[b$ErrNum]
- mov [bx+1],ax ;save error code
- pop ax ;restore ax = iWatch for next expression
- ;ax = index for next WATCH pcode to execute
- NoWatchErr:
- cmp ax,[cWatch]
- jae EndWatch ;brif last watch exp has been executed
- mov [iWatch],ax
- xchg bx,ax ;bx = iWatch
- call WatchInfo ;ax = oRs for text table for iWatch
- ;cx = otx to start of watch pcode
- ;bx = ptr to valTyp, value
- ;grs.fDirect = FALSE
- cmp ax,[grs.GRS_oRsCur]
- jne DOutOfScope ;brif exp isn't from current context
- mov [pWatchVal],bx ;tell executor where to store value
- mov [grs.GRS_otxCur],cx
- mov [grs.GRS_fDirect],0
- or [grs.GRS_flags],FG_WatchActive
- DbAssertTst [grs.GRS_flags],ne,FG_allSsExecute,UI,<DebugWatch err1>
- DWatchTrue:
- mov ax,sp ;return TRUE - tells caller we're
- ; about to execute watch-pcode
- or ax,ax ;set condition codes for caller
- DWatchExit:
- cEnd
- ;bx points to entry in watch table for current watch expression
- DOutOfScope:
- DbHalt UI,<DOutOfScope: Watch code not enabled for LQB>
- or [debugFlags],DEBUG_ERROR
- jmp NextWatch ;go get next watch expression
- ;Watch expression is evaluating a user supplied function
- ;If runtime error occurs within a watch expression, it is untrappable
- ; and reported.
- ;Otherwise, just return and continue executing the function.
- ;This causes TRACE to be disabled during WATCH pcode.
- ;
- WatchInUserFunc:
- test [debugFlags],DEBUG_ERROR OR DEBUG_STOP
- je DWatchTrue ;brif watch expression had no error
- or [debugFlags],DEBUG_CANT_CONT
- ;don't allow user to continue after
- ; error in Watch function
- jmp SHORT DWatchFalse ;let error/breakpoint/stop within
- ;user-function be reported.
- EndWatch:
- cmp [fDebugScr],FALSE
- je NoDebugScr ;brif debug screen not visible
- DebDrawLoop:
- call WatchInfoUI ;bx = ptr to valTyp, value
- call WatchValue ;display Watch value on screen
- mov dx,1 ;print value, not title
- call WatchPrint
- dec [iWatch]
- jns DebDrawLoop
- ;Restore state of user-pcode that was interrupted to execute watch-pcode
- NoDebugScr:
- mov al,[fDirectSave]
- mov [grs.GRS_fDirect],al
- mov ax,[errnumSave] ;restore value of b$errnum from
- mov [b$errnum],ax ; before WATCH pcode execution
- mov ax,[otxWatchSave]
- mov [grs.GRS_otxCur],ax
- DbAssertRel bp,e,[bpWatchSave],UI,<DebugWatch: invalid bp>
- DWatchFalse:
- and [grs.GRS_flags],NOT FG_WatchActive
- mov ax,UNDEFINED
- mov [iWatch],ax
- inc ax ;return FALSE - tells caller we're
- jmp SHORT DWatchExit ;about to execute user-pcode
- ;Condition codes are also set for caller
- sEnd UI
- end