📄 txtdeb.asm
字号:
; ever called from anywhere else this will need to be
; reexamined.
;
; WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING
;
; Entry:
; grs.oRsCur, grs.otxCur identify next statment to be executed.
; Exit:
; Returns false if next statement to be executed contains no
; executable pcode. Condition codes are set based on value in ax.
;
;**************************************************************
cProc FExecutable,<PUBLIC,FAR>,<di>
cBegin
DbAssertRelB [grs.GRS_fDirect],e,0,CP,<FExecutable: grs.fDirect=0>
mov ax,[grs.GRS_otxCur]
FExLoop:
push ax ; save otx we're about to use
call GetDescannedOpcode ;ax = opcode at text offset ax
mov di,CPOFFSET tNops ;di -> 1st opcode in table to search
mov cx,CW_TNOPS
push cs
pop es
repne scasw ;search for opcode ax in table pointed
; to by es:di
jnz fExExit ; brif no match (return AX != 0)
sub cx,(CW_TNOPS - 3) ; cx <= 0 if not special match
jbe fExMatch ; brif normal match
pop ax ; get otx we just used
inc cx ; cx = 2 if opLab, 3 if opLabSp
inc cx ; cx = 3 if opLab, 4 if opLabSp
shl cx,1 ; cx = length of opLab[Sp] (6 or 8)
add ax,cx ; bump otx past opLab[Sp]
jmp short FExLoop ; try next opcode
fExMatch:
xor ax,ax ; return false
fExExit:
pop cx ; clean up stack
or ax,ax ; set condition codes
cEnd
; in EB it must be converted to a cProc
;**************************************************************
; boolean FAR fNextStmtDoesIO()
; Purpose:
; Called by User Interface code to determine if we need to
; show the Output Screen before tracing the next statement.
; For example, the following would return TRUE where ^ represents
; grs.otxCur:
; opBol^opPrintEos opBol
; And the following would return FALSE:
; ^opBol opPrintEos opBol
; opBol opPrintEos^opBol
; ^opBol opStClose opBol
; opBol^opStClose opBol
; opBol opStClose^opBol
; Because sometimes, the user interface calls this
; when it is looking beyond the opBos.
; Entry:
; grs.fDirect, grs.oMrsCur, grs.oPrsCur, grs.otxCur
; indicate the next statement to be executed.
; If grs.fDirect is TRUE, this function assumes the
; direct mode buffer is in SS_EXECUTE scan state.
;
; Exit:
; returns TRUE if any opcodes in the next statement can
; cause I/O to the screen/keyboard.
;
;**************************************************************
PUBLIC fNextStmtDoesIO
fNextStmtDoesIO PROC FAR
push [grs.GRS_otxCur]
PUSHI ax,<CODEOFFSET tOpIO>
call TxtFindOp
sub ax,ax ;prepare to return FALSE
cmp dl,IO_bosMin
jae FnExit ;brif stmt can't perform I/O
dec ax ;return UNDEFINED (TRUE)
FnExit:
ret
fNextStmtDoesIO ENDP
;************************************************************
; WatchMoved
; Purpose:
; Called every time text is inserted/deleted/scanned/descanned
; to remember to build table 'tWatch' by scanning all pcode.
;
;************************************************************
PUBLIC WatchMoved
WatchMoved PROC NEAR
mov [fWatchBuild],1
ret
WatchMoved ENDP
;**************************************************************************
; WatchInfo
; Purpose:
; Given an index for a watch expression, load registers with info
; about that watch expression from table tWatch.
; Entry:
; bx = watch index (0 to n)
; Exit:
; ax = oRs for text table containing expression
; cx = otx to start of expression
; dx = otx to end of expression
; bx points to 1 byte valTyp, 8 byte value structure
; grs.fDirect is set to FALSE (because TxtFindNextOp is called)
; [cWatch] = number of watch expressions in all loaded modules
;
;**************************************************************************
cProc WatchInfo,<PUBLIC,FAR>,<si>
cBegin
sub ax,ax
cmp [fWatchBuild],FALSE
je GotWatchInfo
test [flagsTM],FTM_WatchPcode ;is there any watch pcode anywhere?
je GotWatchInfo ;brif not - get out quick
SetfDirect al ;[19]turn off direct mode
and [flagsTM],NOT FTM_WatchPcode ;clear flag, gets reset after
; WatchBuildNext if any pcode is found
push bx ;preserve iWatch
mov [fWatchBuild],al
mov [cWatch],ax
mov ax,dataOFFSET tWatch
mov [pWatch],ax
mov bx,CPOFFSET WatchBuildNext
call ForEachTxtTbl
pop bx ;bx = iWatch
cmp [cWatch],0 ;was any watch pcode found?
je GotWatchInfo ;brif not
or [flagsTM],FTM_WatchPcode ;we have some watch pcode
GotWatchInfo:
mov cl,4
shl bx,cl ;bx = iWatch * 16
.errnz (SIZE WT_ST) - 16
add bx,DATAOFFSET tWatch ;bx points to entry
xchg si,bx ;si points to watch entry
lodsw ;ax = oRs of watch entry
.errnz WT_oRs - 0
push ax
lodsw ;ax = otxStart of watch entry
.errnz WT_otxStart - 2
push ax
lodsw ;ax = otxEnd of watch entry
.errnz WT_otxEnd - 4
xchg dx,ax ;dx = otxEnd
pop cx ;cx = otxStart
pop ax ;ax = oRs
xchg bx,si ;restore caller's si
inc bx ;bx points to WT_valTyp entry
.errnz WT_valTyp - 7
cEnd
;**************************************************************************
; WatchBuildNext
; Purpose:
; Called for every text table by WatchInfo - finds WATCH pcode
; and copies relevant information into table tWatch.
;
;**************************************************************************
cProc WatchBuildNext,<NEAR>,<si,di>
cBegin
sub si,si ;start at beginning of table
mov di,[pWatch]
NwLoop:
push si ;pass otxCur to TxtFindNextOp
PUSHI ax,<CODEOFFSET tOpWatch>
call TxtFindOp ;ax = offset to next watch pcode
;dl = [txtFindIndex]
inc ax
inc ax ;ax now points beyond opWatch opcode
;i.e. it now ax points to expression
xchg si,ax ;si = otxNext, ax=otxPrev
cmp dl,W_opEot
je NwExit ;brif reached opEot
cmp dl,W_opEndProg
je NwLoop ;opEndProg just marks start of table,
;doesn't mean we have a Watch exp
inc [cWatch] ;bump # watch expressions in system
push ds
pop es ;es = DGROUP (for stosw)
push ax ;save otxPrev to start of watch exp
mov ax,[grs.GRS_oRsCur]
stosw ;save oRsCur in WT_oRs field
.errnz WT_oRs - 0
pop ax ;ax = otxPrev
stosw ;save in WT_otxStart field
.errnz WT_otxStart - 2
mov ax,si ;ax = otxNext
stosw ;save in WT_otxEnd field
.errnz WT_otxEnd - 4
inc di ;di points to WT_valTyp field
cmp dl, W_opWatchStop ; Is this a watchpoint?
jne @F
mov al, 12H ; Yes, mark it in watch info.
stosb
dec di
@@:
.errnz WT_valTyp - 7
add di,(SIZE WT_ST) - WT_valTyp
DbAssertRel di,be,<dataOFFSET tWatchEnd>,CP,<WatchInfo err 1>
jmp SHORT NwLoop
NwExit:
mov [pWatch],di ;save for next call
cEnd
;************************************************************
; ZeroWatchVal
; Purpose:
; Zero a particular Watch value, releasing string if necessary
; Called from uidebug.asm and WatchRelease below.
; Entry:
; parm1 points to WT_valTyp field of entry in tWatch
;
;************************************************************
cProc ZeroWatchVal,<PUBLIC,FAR>
ParmW WatchEntry
cBegin ZeroWatchVal
mov bx,[WatchEntry]
sub ax,ax
cmp BYTE PTR [bx],24h ;test for string value
mov [bx],al
je FreeString ;brif str descriptor needs to be freed
.errnz WT_value - WT_valTyp - 1
mov [bx+1],ax ;zero value so if we later assign
mov [bx+3],ax ; won't think garbage is str descriptor
jmp SHORT NotString ; a string to this slot, string mgr
FreeString:
push ax ;push NULL string descriptor
push ax
mov ax,sp ;cant push sp, works different on 86/286
push ax ;pass ptr to NULL string descriptor
.errnz WT_value - WT_valTyp - 1
inc bx ;bx points to WT_value field
push bx ;pass ptr to watch SD
call B$SASS ;release string
pop ax ;pop NULL string descriptor
pop ax
NotString:
cEnd ZeroWatchVal
;************************************************************
; WatchRelease
; Purpose:
; Called before B$RUNINI (runtime initialization),
; and whenever a watch expression is added or deleted.
; It sets all values to 0 and releases any strings
; owned by the WATCH table.
;
;************************************************************
cProc WatchRelease,<PUBLIC,FAR>,<di>
cBegin
mov di,dataOFFSET tWatch
add di,WT_valTyp
ZeroLoop:
cmp di,DATAOFFSET tWatchEnd
jae ZeroDone
push di ;push watch entry
call ZeroWatchVal ;release it
add di,SIZE WT_ST
jmp SHORT ZeroLoop
ZeroDone:
cEnd
;************************************************************
; DebugReset
; Purpose:
; Called by RunInit (just before we call B$RUNINIT) in
; preparation for program execution. It does the following:
; - release any string descriptors owned by Watch table
; - resets history buffer
; Exit:
; Preserves grs.fDirect
;
;************************************************************
cProc DebugReset,<PUBLIC,NEAR>
cBegin
push word ptr [grs.GRS_fDirect] ;preserve for caller
call WatchRelease ;release any existing WATCH values
;causes tWatch strings to be released
sub bx,bx
call WatchInfo ;make sure watch info is up to date
; since we can't build it after
; program execution gets under way,
; because it needs to call TxtFind...
call HistReset ;release History buffer
PopfDirect ax ;restore input setting of this flag
cEnd
;************************************************************
; WatchAdd(fWatchType)
; Purpose:
; Called whenever the user wants to add a WATCH expression
; Entry:
; fWatchType = WT_Watch if watch expression is being added
; WT_WatchPoint if watch point is being added
;if FV_INSTWAT
; WT_InstantWatch if instant watch is being displayed
;endif
; ps.bdpSrc contains the 0-terminated source line to be parsed.
; grs.oMrsCur and grs.oPrsCur identify the scope of the expression.
; Exit:
; flagsTM.FTM_WatchPcode is set to indicate WatchPcode exists
; Same as TxtDirect, except ax is meaningless on exit
;
;************************************************************
cProc WatchAdd,<PUBLIC,FAR>,<si>
parmB fWatchType
cBegin
call WatchRelease ;release any existing WATCH values
call TxtDescanCP ;descan current text table to SS_PARSE
TwRetry:
call OtxDefTypeEot ;fill ps.tEtCur[] with default types
; from end-of-text-table
;While it is tempting to set
; the default types to those of
; grs.otxCONT, we can't do this
; because if we descan to SS_RUDE,
; rude-scanner would use def-types
; of EOT.
mov [ps.PS_flags],PSF_fParseExp
call ParseLine
jnc TwNoParseErr ;brif ParseLine got no error
;See if the parser wants us to try parsing this line again. This can
;happen when:
; We saw something that made us need to ModuleRudeEdit, but part
; of the line's pcode had already been emitted in SS_PARSE
; Variable manager could not add a variable, because variable heap
; was locked (because we can CONTinue). Parser called AskCantCont
; and now wants us to try again (much easier than trying to call
; varmgr again from within parser).
test [ps.PS_flags],PSF_fRetry
jne TwRetry ;brif ParseLine wants us to try again
test [ps.PS_flags],PSF_UndoEdit
je TwErr ;brif user didn't say he wants to back
; out of the edit while we were in
; ParseLine (i.e. ParseLine called
; AskCantCont)
mov ax,UNDEFINED
jmp SHORT TwErrCode ;tell caller to back out of operation
TwNoParseErr:
sub [ps.PS_bdpDst.BDP_pbCur],2
sub [ps.PS_bdpDst.BDP_cbLogical],2
mov ax,opWatchExp
cmp [fWatchType],WT_WatchPoint ; doing a watchpoint?
jne TwEmit ; no, emit opWatchExp
mov ax,opWatchStop ; emit opWatchStop for watchpoint
TwEmit:
call Emit16_AX
mov si,[txdCur.TXD_bdlText_cbLogical]
dec si
dec si ;si = otx to opEot (watch insert point)
call TxtInsert ;insert ps.bdpDst in text table at si
mov ax,ER_OM ;prepare to return out-of-memory error
je TwErrCode ;brif out-of-memory
;else, ps.errCode = 0, return it
TwErr:
mov ax,[ps.PS_errCode]
and ah,(PSERR_fAsciiMsg + PSERR_errCode) / 100h
;mask off parser internal flags
.errnz PSERR_fAsciiMsg - 8000h ;caller assumes this is high bit
TwErrCode:
mov [txtErr.TXER_errCode],ax
mov [txtErr.TXER_oRs],UNDEFINED ;don't try to position cursor
or [flagsTM],FTM_WatchPcode ;We have watch pcode in system
cEnd
;**************************************************************************
; WatchDel
; Purpose:
; Given an index for a watch expression, delete pcode for it
; TxtDelete calls WatchDeleted which causes entry to be discarded
; from DebugScreen
; Entry:
; parm1 = watch index (0 to n)
; grs.fDirect is set to FALSE
; Exit:
; preserves bx
;
;**************************************************************************
cProc WatchDel,<PUBLIC,FAR>,<bx>
parmW idWatch
cBegin
mov bx,[idWatch]
push bx ;save idWatch
call WatchInfo ;ax = oRs
push ax
call RsActivateCP ;activate the text table
call TxtDescanCP ;descan to SS_PARSE before delete pcode
pop bx ;bx = idWatch
call WatchInfo ;cx = otxStart, dx = otxEnd
push cx ;pass otxStart to TxtDelete
push dx ;pass otxEnd to TxtDelete
call TxtDelete ;delete the Watch pcode
cEnd
;**************************************************************************
;ChkWatchErr
;Purpose:
; Called by SystemScan when an error is encountered.
; Modifies txtErr if error is in Watch expression, so
; error will be reported to user in better form.
;Entry:
; txtErr structure contains error information
;Exit:
; txtErr structure contains updated error information
;
;**************************************************************************
cProc ChkWatchErr,<PUBLIC,NEAR>,<si>
cBegin
sub si,si
CwLoop:
mov bx,si ;bx = iWatch for next watch expression
call WatchInfo ;ax = oRs for expression's text table
;bx points to 1 byte valTyp
;cx = otx to start of expression
;dx = otx to end of expression
;we can't do this comparison before calling WatchInfo, because
;calling WatchInfo can update cWatch
cmp si,[cWatch]
jae CwDone
inc si ;bump si for next watch expression
cmp ax,[txtErr.TXER_oRs]
jne CwLoop ;brif not oRs with error
cmp cx,[txtErr.TXER_otx]
ja CwLoop ;brif can't be expression of interest
cmp dx,[txtErr.TXER_otx]
jbe CwLoop ;brif isn't be expression of interest
mov BYTE PTR [bx],0FFh ;valtyp = std error code
mov ax,[txtErr.TXER_errCode]
mov [bx+1],ax ;save error code. Causes it to be
; displayed in watch window.
mov [txtErr.TXER_oRs],UNDEFINED
;so we don't try to position the
; cursor where the error is
CwDone:
cEnd
sEnd CP
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -