;       SCCSID = @(#)debtrap.asm        6.4 91/09/03
PAGE    ,132
NAME    DEBTRAP
TITLE   DEBTRAP.ASM - Debug trap handlers and go, trace and ptrace commands.

.286p

;***    DEBTRAP.ASM
;
;       Debug trap handlers and go, trace and ptrace commands.
;
;       SCCSID = @(#)debtrap.asm        6.4 91/09/03
;
;----------------------------------------------------------------------------
;****************************************************************************
;* Change log flagged with a @#nnnx                                    ;
;*   where the nnn is any unique number                                ;
;*   where the x is n for new code or a for added code                 ;
;*                  d for deleted code(commented out old code)         ;
;*                  c for changed code                                 ;
;*                                                                     ;
;*  @#001 MTH 09/03/91 Changes made for PTR PB725079                   ;
;*  - added fixes so 'BT' command would work in 2.0, see 'DGE'         ;@#001n
;*                                                                     ;
;*---------------------------------------------------------------------
;*
;****************************************************************************

.xlist
        include dosseg.inc
        include basemaca.inc
        include osmaca.inc
        include debseg.inc
        include debmac.inc
        include debequ.inc
        include debinit.inc
        include debdesc.inc
        include protmode.inc

.list
        EXTRNFAR        NWDRestoreWatchdogNMI
        EXTRNFAR        NWDDisableWatchdogNMI

DataSegmentStart

Extern DebData,         WORD
Extern DefType,         WORD
Extern RegSA,           WORD
Extern StackTop,        WORD
Extern InDebugger,      BYTE
Extern BPcount,         WORD
Extern DefaultCmd,      BYTE
Extern opbuf,           BYTE
Extern CmdInputBuffer,  BYTE
Extern pTXT,            WORD
Extern pRegSA,          WORD
Extern DisAddr,         BYTE
Extern btatab,          BYTE
Extern TraceCallsStack, BYTE
Extern TraceCallsDepth, WORD
Extern TraceCallsFirst, WORD
Extern TraceCallsSecond, WORD
Extern ContextStartAddr,BYTE
Extern ContextEndAddr,  BYTE
Extern ContextEndAddr2, BYTE

IFDEF   KDP
Extern fKDPEnabled,     BYTE
Extern fKDPPacketMode,  BYTE
Extern fKDPRaw,         BYTE
ENDIF

        ReferGlobal     _CpuType,BYTE			;; 148688
        ReferGlobal     _CpuVendor, DWORD               ; 157841

Global TrapNumber,      LABEL,  WORD    ; 16 bit trap number
Global TrapNumber32     DWORD,  0       ; 32 bit trap number
Global ErrorCode,       WORD,   0       ; error code from stack
Global fRegDisp,        BYTE,   1       ; 1 => display registers on trace/go
Global fExecTrap,       BYTE,   0       ; execute trap handler if !0
Global Tcount           WORD,   0       ; number of steps to trace or ptrace
Global TraceAddr,       STRUC,  AddrS,  <>      ; Address to trace to
Global fTraceAddr,      BYTE,   0       ; !0 => tracing to an address
Global fTraceCount,     BYTE,   0       ; !0 => Just count instructions
Global fDoTraceBad,     BYTE,   0       ; !0 => Trace "bad" sections
Global fTraceSpecial,   BYTE,   0       ; !0 => Print CALL/RET insts
Global fTraceSpecial2,  BYTE,   0       ; !0 => Special instruction
Global InstCount,       DWORD,  0       ; # instructions traced w/ fTraceCount
Global fDoGoSpecial,    BYTE,   0       ; Go w/ timing? (G S)

Static EntrySS,         WORD,   0       ; SS:ESP on entry to debugger
Static EntryESP,        DWORD,  0       ;
Static TmpAddr,         STRUC,  AddrS, <>
Static ReturnAddr,      WORD,   0       ; caller's return address
Static FarReturnAddr,   DWORD,  0       ; caller's far return address
Static Trash,           WORD,   0       ; word to pop trash into
Static fSSPushF,        BYTE,   0       ; TRUE if just Single Stepped PushF
Static ContFlag,        BYTE,   0       ; continue flag
Static BPointTrace,     BYTE,   0       ; TRUE if tracing over a breakpoint

; Text strings for each 286/386 CPU fault type for messages

Static Trap00Msg, STRING, "Trap 0 - Divide Error Exception"
Static Trap02Msg, STRING, "Trap 2 - NMI Interrupt"
Static Trap04Msg, STRING, "Trap 4 - INTO Detected Overflow Exception"
Static Trap05Msg, STRING, "Trap 5 - BOUND Range Exceeded Exception"
Static Trap06Msg, STRING, "Trap 6 - Invalid Opcode Exception"
Static Trap07Msg, STRING, "Trap 7 - Processor Extension Not Available Exception"
Static Trap08Msg, STRING, "Trap 8 - Double Exception Detected"
Static Trap09Msg, STRING, "Trap 9 - Processor Extension Segment Overrun"
Static Trap10Msg, STRING, "Trap 10 (0AH) - Invalid TSS"
Static Trap11Msg, STRING, "Trap 11 (0BH) - Segment Not Present"
Static Trap12Msg, STRING, "Trap 12 (0CH) - Stack Segment Overrun or Not Present"
Static Trap13Msg, STRING, "Trap 13 (0DH) - General Protection Fault"
Static Trap14Msg, STRING, "Trap 14 (0EH) - Page Fault"

; Trap information table

TrapTbl label byte
TrapTblS <dataOFFSET Trap00Msg,codeOFFSET Trap00,codeOFFSET Trap0032,0>
TrapTblS <0,                   codeOFFSET Trap01,codeOFFSET Trap0132,0>
TrapTblS <dataOFFSET Trap02Msg,codeOFFSET Trap02,codeOFFSET Trap0232,0>
TrapTblS <0,                   codeOFFSET Trap03,codeOFFSET Trap0332,0>
TrapTblS <dataOFFSET Trap04Msg,codeOFFSET Trap04,codeOFFSET Trap0432,0>
TrapTblS <dataOFFSET Trap05Msg,codeOFFSET Trap05,codeOFFSET Trap0532,0>
TrapTblS <dataOFFSET Trap06Msg,codeOFFSET Trap06,codeOFFSET Trap0632,0>
TrapTblS <dataOFFSET Trap07Msg,codeOFFSET Trap07,codeOFFSET Trap0732,0>
TrapTblS <dataOFFSET Trap08Msg,codeOFFSET Trap08,codeOFFSET Trap0832,TRAP_ERRCD>
TrapTblS <dataOFFSET Trap09Msg,codeOFFSET Trap09,codeOFFSET Trap0932,0>
TrapTblS <dataOFFSET Trap10Msg,codeOFFSET Trap10,codeOFFSET Trap1032,TRAP_ERRCD>
TrapTblS <dataOFFSET Trap11Msg,codeOFFSET Trap11,codeOFFSET Trap1132,TRAP_ERRCD>
TrapTblS <dataOFFSET Trap12Msg,codeOFFSET Trap12,codeOFFSET Trap1232,TRAP_ERRCD>
TrapTblS <dataOFFSET Trap13Msg,codeOFFSET Trap13,codeOFFSET Trap1332,TRAP_ERRCD>
TrapTblS <dataOFFSET Trap14Msg,codeOFFSET Trap14,codeOFFSET Trap1432,TRAP_ERRCD>

Static TrapEXTMsg,      STRING, ", External"
Static TrapIDTMsg,      STRING, ", IDT Gate"
Static TrapGDTMsg,      STRING, ", GDT"
Static TrapLDTMsg,      STRING, ", LDT"
Static TrapNPMsg,       STRING, ", Not Present"
Static TrapReadMsg,     STRING, ", Read Access"
Static TrapWriteMsg,    STRING, ", Write Access"
Static TrapUserMsg,     STRING, ", User Mode"
Static TrapSuperMsg,    STRING, ", Supervisor"

TrapDecode label word
    dw  0                       ; if (err & 1) == 0
    dw  dataOFFSET TrapEXTMsg   ; if (err & 1) == 1
    dw  0                       ; if (err & 2) == 0
    dw  dataOFFSET TrapIDTMsg   ; if (err & 2) == 1
    dw  dataOFFSET TrapGDTMsg   ; if (err & 4) == 0
    dw  dataOFFSET TrapLDTMsg   ; if (err & 4) == 1

TrapEDecode label word
    dw  dataOFFSET TrapNPMsg    ; if (err & 1) == 0
    dw  0                       ; if (err & 1) == 1
    dw  dataOFFSET TrapReadMsg  ; if (err & 2) == 0
    dw  dataOFFSET TrapWriteMsg ; if (err & 2) == 1
    dw  dataOFFSET TrapSuperMsg ; if (err & 4) == 0
    dw  dataOFFSET TrapUserMsg  ; if (err & 4) == 1

DataSegmentEnd

CodeSegmentStart

;**     Traps
;
;       These entry points are for internally generated exceptions,
;       such as a general protection fault. They do not handle
;       external hardware interrupts, or user software interrupts.
;
;       ENTRY   On entry the stack looks like:
;                       [SS]
;                       [SP]
;                       flags
;                       CS
;                       IP
;               ss:sp-> [error]
;
;               The cpu saves the previous SS:SP, flags, and CS:IP on the
;               new stack if there was a privilige transition. If no priv
;               transition occurred, then there is no saved SS:SP.
;
;               Some exceptions save an error code, others do not.
;
;       EXIT    All registers and flags preserved.
;
;       DESCRIPTION
;
;       All this routine does is get the stack into a standard form
;       and determine whether there was a saved error code and a saved
;       SS:SP or not. Then an external routine is called to actually
;       process the error.
;
;       The common stack format for all exceptions is:
;
;               [SS]    (may not be there)
;               [SP]    (may not be there)
;               Flags
;               CS
;               IP
;               Error
;               Trap Number
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

; Trap 0 - Divide Error Exception

DefProc Trap00, NEAR, LOCAL
        push    NO_ERROR                ; push error code
        push    0                       ; push trap number
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0032, NEAR, LOCAL
        push    NO_ERROR                ; push error code
        push    NO_ERROR
        push    0
        push    0                       ; push trap number
        jmp     TrapEntry32
EndProc NoGen

; Trap 1 - Single Step Interrupt

DefProc Trap01, NEAR, LOCAL
        push    NO_ERROR
        push    SINGLE_STEP_TRAP
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0132, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    SINGLE_STEP_TRAP
        jmp     TrapEntry32
EndProc NoGen

; Trap 2 - NMI Interrupt

DefProc Trap02, NEAR, LOCAL
        push    ds                      ; save registers
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   EnableNMI
        test    InDebugger,0ffh         ; check if got NMI in debugger
        pop     ds
        jnz     short nmi1              ; jump if already in debugger
        push    NO_ERROR
        push    NMI_TRAP
        jmp     TrapEntry               ; break into debugger

nmi1:   iret
EndProc NoGen

DefProc Trap0232, NEAR, LOCAL
.386p
        push    ds                      ; save registers
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   EnableNMI
        test    InDebugger,0ffh         ; check if got NMI in debugger
        pop     ds
        jnz     short nmi2              ; jump if already in debugger
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    NMI_TRAP
        jmp     TrapEntry32             ; break into debugger

nmi2:   iretd
.286p
EndProc NoGen

; Trap 3 - Breakpoint Interrupt

DefProc Trap03, NEAR, LOCAL
        push    NO_ERROR
        push    BREAK_POINT_TRAP
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0332, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    BREAK_POINT_TRAP
        jmp     TrapEntry32
EndProc NoGen

; Trap 4 - INTO Detected Overflow Exception

DefProc Trap04, NEAR, LOCAL
        push    NO_ERROR
        push    4
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0432, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    4
        jmp     TrapEntry32
EndProc NoGen

; Trap 5 - BOUND Range Exceeded Exception

DefProc Trap05, NEAR, LOCAL
        push    NO_ERROR
        push    5
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0532, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    5
        jmp     TrapEntry32
EndProc NoGen

; Trap 6 - Invalid Opcode Exception

DefProc Trap06, NEAR, LOCAL
        push    NO_ERROR
        push    6
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0632, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    6
        jmp     TrapEntry32
EndProc NoGen

; Trap 7 - Processor Extension Not Available Exception

DefProc Trap07, NEAR, LOCAL
        push    NO_ERROR
        push    7
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0732, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    7
        jmp     TrapEntry32
EndProc NoGen

; Trap 8 - Double Exception Detected

DefProc Trap08, NEAR, LOCAL
        push    8
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0832, NEAR, LOCAL
        push    0
        push    8
        jmp     TrapEntry32
EndProc NoGen

; Trap 9 - Processor Extension Segment Overrun Interrupt

DefProc Trap09, NEAR, LOCAL
        push    NO_ERROR
        push    9
        jmp     TrapEntry
EndProc NoGen

DefProc Trap0932, NEAR, LOCAL
        push    NO_ERROR
        push    NO_ERROR
        push    0
        push    9
        jmp     TrapEntry32
EndProc NoGen

; Trap 10 (0A) - Invalid TSS

DefProc Trap10, NEAR, LOCAL
        push    10
        jmp     TrapEntry
EndProc NoGen

DefProc Trap1032, NEAR, LOCAL
        push    0
        push    10
        jmp     TrapEntry32
EndProc NoGen

; Trap 11 (0B) - Segment Not Present

DefProc Trap11, NEAR, LOCAL
        push    11
        jmp     TrapEntry
EndProc NoGen

DefProc Trap1132, NEAR, LOCAL
        push    0
        push    11
        jmp     TrapEntry32
EndProc NoGen

; Trap 12 (0C) - Stack Segment Overrun or Not Present

DefProc Trap12, NEAR, LOCAL
        push    12
        jmp     TrapEntry
EndProc NoGen

DefProc Trap1232, NEAR, LOCAL
        push    0
        push    12
        jmp     TrapEntry32
EndProc NoGen

; Trap 13 (0D) - General Protection Fault

DefProc Trap13, NEAR, LOCAL
        Pcall   IsDebProtMode
        jc      short gpf1              ; jump if protected mode
        push    NO_ERROR                ; if GP fault in real mode push error
gpf1:   push    13
        jmp     TrapEntry
EndProc NoGen

DefProc Trap1332, NEAR, LOCAL
        push    0
        push    13
        jmp     TrapEntry32
EndProc NoGen

; Trap 14 (0E) - Page Fault

DefProc Trap14, NEAR, LOCAL
        push    14
        jmp     TrapEntry
EndProc NoGen

DefProc Trap1432, NEAR, LOCAL
        push    0
        push    14
        jmp     TrapEntry32
EndProc NoGen

;***    TrapEntry32 - 32 bit entry from local hardware trap handlers only
;
;       We come here when we catch an exception or interrupt in
;       protected mode.
;
;       ENTRY   [ss pad]    WORD
;               [ss]        WORD
;               [esp]       DWORD
;               eflags      DWORD
;               cs pad      WORD
;               cs          WORD
;               eip         DWORD
;               error code  DWORD
;       esp->   trap number DWORD
;
;       EXIT    Jumps to command processor loop.
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING
.386p

trapframe32     struc
        tfd_ebp         dd      ?
        tfd_ebp2        dd      ?
        tfd_trapnum     dd      ?
        tfd_errcode     dd      ?
        tfd_eip         dd      ?
        tfd_cs          dw      ?
        tfd_cspad       dw      ?
        tfd_eflags      dd      ?
trapframe32     ends

Entry   TrapEntry32, NEAR, LOCAL        ; internal to debtrap.asm
        cli                             ; disable interrupts
        push    ebp                     ; push "tfd_ebp2"
        push    ebp                     ; push "tfd_ebp"
        mov     ebp,esp                 ; (BP) = trapframe32
        movzx   ebp,bp                  ; (EBP) = trapframe32
        push    ds
        push    bx
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   GetTrapTblEntry, <word ptr [ebp].tfd_trapnum>

        test    [bx].TrapTblFlag,(TRAP_PM_TEMP + TRAP_RM_TEMP)
        jnz     short tpd5              ; always enter the debugger

        test    [ebp].tfd_eflags,F_VM
        jnz     short tpd4              ; jump if v86 mode

        test    [ebp].tfd_cs,RPL_MASK
        jnz     short tpd5              ; jump if ring 3 or 2

        test    [bx].TrapTblFlag,TRAP_PM_HARD
        jnz     short tpd5              ; jump if hard trap intercept

tpd1:   test    [bx].TrapTblFlag,TRAP_ERRCD
        jnz     short tpd2              ; jump if trap has error code
        add     ebp,4

tpd2:   push    [bx].TrapTblPMsave.GateExtOffset
        push    [bx].TrapTblPMsave.GateOffset
        pop     [ebp + 4].Offst32
        mov     bx,[bx].TrapTblPMsave.GateSelector
        mov     [ebp + 4].Segmt32,bx

;              Before         Current         Current
;            errcode test   with errcode   without errcode
;            --------------------------------------------
;               eflags          eflags          eflags
;               cs              cs              cs
;               eip             eip             eip
;               errcode         errcode         new cs
;               trapnum         new cs          new eip
;               tfd_ebp2        new eip   ebp-> tfd_ebp2
;         ebp-> tfd_ebp   ebp-> tfd_ebp         tfd_ebp
;               ds              ds              ds
;         esp-> bx        esp-> bx        esp-> bx

tpd3:   pop     bx
        pop     ds

;       Point esp to "tfd_ebp2" if no error code else do nothing.

        mov     esp,ebp
        pop     ebp
        db      OPER_OVERRIDE
        retf                            ; return to "new cs:eip"

tpd4:   test    [bx].TrapTblFlag,TRAP_V86_USED
        jz      short tpd1              ; jump if don't trap in v86 mode

tpd5:   pop     bx
        pop     ds
        pop     ebp                     ; remove "tfd_ebp"
        pop     ebp                     ; remove "tfd_ebp2"

;***    Debug_Trap32 - exception entry point for 32 bit gates
;
;       We come here when we catch an exception or interrupt in
;       protected mode from the kernel.
;
;       ENTRY   [ss pad]    WORD
;               [ss]        WORD
;               [esp]       DWORD
;               eflags      DWORD
;               cs pad      WORD
;               cs          WORD
;               eip         DWORD
;               error code  DWORD
;       esp->   trap number DWORD
;
;       EXIT    Jumps to command processor loop.
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry   Debug_Trap32, FAR, PUBLIC, FAR16
        Pcall   EnterDebugIRETD
    assumeDATA  <ds, es, ss>
        Pcall   CheckCtrlC
        Pcall   CheckBeep
        jmp     BreakEntry
.286p

;***    TrapEntry - 16 bit entry from local hardware trap handlers only
;
;       We come here when we catch an exception or interrupt in
;       protected mode from the local 16 bit trap handlers.
;
;       ENTRY   [ss]         WORD
;               [sp]         WORD
;               flags        WORD
;               cs           WORD
;               ip           WORD
;               error code   WORD
;       sp->    trap number  WORD
;
;       EXIT    Jumps to command processor loop.
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

trapframe       struc
        tf_bp           dw      ?
        tf_bp2          dw      ?
        tf_trapnum      db      ?
        tf_trapflag     db      ?
        tf_errcode      dw      ?
        tf_ip           dw      ?
        tf_cs           dw      ?
        tf_flags        dw      ?
trapframe       ends

Entry   TrapEntry, NEAR, LOCAL          ; internal to debtrap.asm
        cli                             ; disable interrupts
        push    bp                      ; push "tf_bp2"
        push    bp                      ; push "tf_bp"
        mov     bp,sp                   ; (BP) = trapframe

        Pcall   IsDebProtMode
        jc      tpe1                    ; jump if protected mode

        cmp     [bp].tf_trapnum,INVALID_OPCODE_TRAP
        jne     tpe5                    ; jump if not invalid opcode exception

        push    ds
        push    bx
        lds     bx,dword ptr [bp].tf_ip ; (DS:BX) = debuggee's CS:IP
        cmp     byte ptr ds:[bx],LOADALL_OP1
        jne     tpe4                    ; jump to regular trap entry
        cmp     byte ptr ds:[bx+1],LOADALL_OP2
        jne     tpe4                    ; jump to regular trap entry

        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   GetTrapTblEntry, <word ptr [bp].tf_trapnum>

        test    [bx].TrapTblFlag,(TRAP_PM_TEMP + TRAP_RM_TEMP)
        jnz     short tpe4              ; always enter the debugger

        test    [bx].TrapTblFlag,TRAP_RM_USED
        jz      short tpe4              ; jump if no new CS:IP in trap table

        add     bp,2                    ; skip error code
        push    [bx].TrapTblRMsave.Offst16
        pop     [bp + 2].Offst16        ; put new CS:IP on stack
        mov     bx,[bx].TrapTblRMsave.Segmt16
        mov     [bp + 2].Segmt16,bx
        jmp     short tpe3

tpe1:   test    [bp].tf_cs,RPL_MASK
        jnz     short tpe5              ; jump if not ring 0

        push    ds
        push    bx
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   GetTrapTblEntry, <word ptr [bp].tf_trapnum>

        test    [bx].TrapTblFlag,TRAP_PM_HARD
        jnz     short tpe4              ; jump if hard trap intercept

        test    [bx].TrapTblFlag,TRAP_ERRCD
        jnz     short tpe2              ; jump if trap has error code
        add     bp,2

tpe2:   push    [bx].TrapTblPMsave.GateOffset
        pop     [bp + 2].Offst16
        mov     bx,[bx].TrapTblPMsave.GateSelector
        mov     [bp + 2].Segmt16,bx

;              Before         Current         Current
;            errcode test   with errcode   without errcode
;            --------------------------------------------
;               flags           flags           flags
;               cs              cs              cs
;               ip              ip              ip
;               errcode         errcode         new cs
;               trapnum         new cs          new ip
;               tf_bp2          new ip     bp-> tf_bp2
;          bp-> tf_bp      bp-> tf_bp           tf_bp
;               ds              ds              ds
;          sp-> bx         sp-> bx         sp-> bx

tpe3:   pop     bx
        pop     ds

;       Point sp to "tf_bp2" if no error code else do nothing.

        mov     sp,bp
        pop     bp
        retf                            ; return to "new cs:ip"

tpe4:   pop     bx
        pop     ds
tpe5:   pop     bp                      ; remove "tf_bp"
        pop     bp                      ; remove "tf_bp2"

;***    Debug_Trap - exported 16 bit protected mode exception entry point
;***    BreakEntry - entry for code that is already entered the debugger
;
;       We come here when we catch an exception or interrupt
;       in protected mode from the kernel.
;
;       We want to print out helpful messages, such as what kind of trap
;       we took, and so on. If we took a breakpoint trap, we back the
;       instruction pointer to the instruction that caused the trap. We
;       clear the trace flag in the saved flags word.  If the trap caused
;       a ring transition, we clean the user ss and user sp off of the
;       stack, so that the stack is clean
;
;       ENTRY   [ss]         WORD
;               [sp]         WORD
;               flags        WORD
;               cs           WORD
;               ip           WORD
;               error code   WORD
;       sp->    trap number  WORD
;
;       EXIT    Jumps to command processor loop.
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Trap, FAR, PUBLIC         ; outside the debugger entry point
        Pcall   EnterDebugIRET
    assumeDATA  <ds, es, ss>

        Pcall   CheckCtrlC
        Pcall   CheckBeep

Entry   BreakEntry, NEAR, PUBLIC
        cmp     TrapNumber,BREAK_POINT_TRAP
        je      short trp00
        cmp     TrapNumber,SINGLE_STEP_TRAP
        je      short trp00
        jmp     trp80                   ; jump to do default cmd

;       Continue if tracing over a breakpoint

;
; If we were timing a go, print out the time.
;
trp00:  cmp     TrapNumber,BREAK_POINT_TRAP     ; Did we come in via INT3?
        jne     trp05                           ; No. Don't print time.
        cmp     fDoGoSpecial,0                  ; Special go?
        je      trp05                           ; No.

        mov     fDoGoSpecial,0                  ; Clear special Go flag
        Pcall   DisplayGoTime                   ; Print the time

;
; Check to see if we single-stepped over a PushF. If so, edit the stack
; to remove the trace flag from the pushed image.
;

trp05:  xor     al,al
        xchg    fSSPushF,al             ; Did we SS a PushF?
        or      al,al
        jz      short trp15
        mov     bx, dataOFFSET TmpAddr
        Pcall   FillDefAddr, <bx, RegSA.SSsav, RegSA.ESPsav.LowWord, RegSA.ESPsav.HighWord>
        cmp     [DefType],EXPR_SIZE_DWORD       ; PushFD?
        jne     short trp10                     ; No, just a PushF

        Pcall   GetDword                ; AX:DX = EFlags
        and     DX,NOT F_TRACE          ; Remove trap flag from saved state
        Pcall   PutDword
        jmp     short trp15

trp10:  Pcall   GetWord                 ; DX = Flags
        and     DX,NOT F_TRACE          ; Remove trap flag from saved state
        Pcall   PutWord

trp15:  xor     al,al
        xchg    BPointTrace,al          ; were we tracing over a break point?
        or      al,al
        jz      short trp25
        Pcall   ZeroGoTime

;       This fixes a premature break when "GOing" from a PUSHF or
;       REPE/REPNE string instruction with a sticky BP on it.  Normally
;       when there is BP at the current CS:IP the instruction is traced
;       and then the BPs are installed.  In the PUSHF or REPE/REPNE string
;       instruction case, tracing can't be done.  A temporary BP is placed
;       after the instruction and execution continued.  This temporary BP
;       has to be cleared after it is hit.

        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   ChkBPaddr               ; (SI) = pointer to BP entry
        jnz     short trp20             ; jump if no breakpoints at CS:IP
        jc      short trp20             ; jump if sticky BP at CS:IP
        test    [si].BpFlag,BP_TMP
        jz      short trp20             ; jump if a GO BP (instead of temp BP)
        mov     [si].BpFlag,0           ; clear temporary BP
trp20:  jmp     ExitDebug               ; put all BPs back and continue

; Start of change DGE @#001
;
;       Check for Time Stamp breakpoints

trp25:  mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   ChkBPaddr               ; is there a break point here
        jnz     short CheckTraceCount   ; jump if no breakpoints
        jnc     short CheckTraceCount   ; jump if not sticky
        test    [si].BpFlag,BP_TIMESTAMP ; time stamp breakpoint?
        jz      short trp29             ; jump if not a time stamp breakpoint
        Pcall   TimeStampBP             ; time stamp, cx=break point number
        jmp     SetBPsAndGo

;       Check for passcount breakpoints

trp29:  cmp     [si].BrkCntr,1          ; pass count done
; End of change DGE

        jbe     short CheckTraceCount   ;
        dec     [si].BrkCntr
        cmp     TrapNumber,BREAK_POINT_TRAP     ; did we break here?
        jne     short CheckTraceCount
        mov     Tcount,0                ; continue
        jmp     SetBPsAndGo             ;

;       Check if trace or ptrace count. We also get here when a non-sticky
;       BP is hit. In the latter case it might be reset if it is the
;       trace-special BP.

Entry   CheckTraceCount, NEAR, LOCAL

        cmp     fTraceSpecial,0         ; In special tracing mode
        je      trp40                   ; No.
        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET ContextEndAddr>
        jz      trp30                   ; Yes.
        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET ContextEndAddr2>
        jc      trp40                   ;  Can't compare. Assume No.
        jnz     trp40                   ;  No.

trp30:  Pcall   CompareContext          ; Back in original context?
        jnz     trp35                   ; No. Just reset bps and go

        printf  <"   ...Back in context">
        Pcall   crlf

        mov     BPcount,0               ; Clear all the TMP breakpoints
        jmp     short trp40

trp35:  mov     bx,dataOFFSET ContextEndAddr    ; No. Reset Breakpoints
        xor     dx,dx
        Pcall   SetTmpBP
        mov     bx,dataOFFSET ContextEndAddr2   ; No. Reset Breakpoints
        xor     dx,dx
        Pcall   SetTmpBP
        jmp     SetBPsAndGo

trp40:  .386p
        inc     InstCount       ; In case we're counting...
        .286p

        cmp     fTraceAddr,0
        je      short trp45
        Pcall   CompareAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET TraceAddr>
        jc      short trp50             ; Error in address
        jnz     short trp50             ; Not at end-trace address
        mov     [fTraceAddr],0
        mov     [fTraceSpecial],0
        mov     [fTraceCount],1         ; Print total instructions.
        jmp     short trp60             ; Execute default command

trp45:  cmp     Tcount,0
        je      short trp60
        dec     Tcount
        jz      short trp60             ; is this the last trace count
trp50:  cmp     fTraceCount,0           ; Are we just counting insts?
        .386p
        jne     SetTraceAndGo           ; Yes. No default command
        .286p
        mov     si,dataOFFSET DefaultCmd
        Pcall   DoCommand
        cmp     ContFlag,PTRACECMD
        je      short trp55
        jmp     SetTraceAndGo           ; trace again

trp55:  jmp     PtraceAgain             ; ptrace again

;       Check if there is a break point command to execute

trp60:  cmp     TrapNumber,SINGLE_STEP_TRAP
        jne     short trp65

        Pcall   CheckDRBP               ; (SI) = sticky BP table entry
        jc      short trp70             ; jump if DR BP
        jmp     short trp80

trp65:  cmp     TrapNumber,BREAK_POINT_TRAP
        jne     short trp80
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   ChkBPaddr
        jnz     short trp80
        jnc     short trp80

trp70:  mov     al,[si].BrkFlag         ; (AL) = bp flags
        and     [si].BrkFlag,not BP_TMP
        test    al,BP_TMP               ; don't exec bp commands if tmp bp also
        jnz     short trp80

        cmp     [si].BrkCmd,0           ; any commands in brk cmd buffer
        je      short trp80

        lea     si,[si].BrkCmd
        Pcall   DoCommand

        IFDEF   KDP
        cmp     fKDPPacketMode,0        ; if packet mode
        je      trp75
        cmp     fKDPRaw,0               ; .&& !raw command
        jne     trp75

        mov     ax,TrapNumber
        Jump    KDPEvent                ; .goto packet event handler
trp75:
        ENDIF

        Jump    command

;       Execute the default command

trp80:  cmp     fTraceCount,0           ; Are we doing a trace count?
        je      short trp85             ;  No.
        mov     fTraceCount,0
        .386p
        mov     edx, dword ptr InstCount
        printf  <"Total traced instructions: %ld (decimal)">, <edx>
        .286p
        Pcall   crlf

trp85:  IFDEF   KDP
        cmp     fKDPPacketMode,0        ; if packet mode
        je      trp90
        cmp     fKDPRaw,0               ; .&& !raw command
        jne     trp90
        mov     ax,TrapNumber
        Jump    KDPEvent                ; .goto packet event handler
trp90:
        ENDIF

        mov     si,dataOFFSET DefaultCmd
        Pcall   DoCommand
        Jump    command
EndProc NoGen

;***    Debug_Fatal - check if the trap is to be caught by debugger
;
;       For process fatal fatals this routine decides whether to put
;       the normal OS/2 popup or call the debugger.  The VSF/VCF commands
;       control this function.
;
;       ENTRY:  AX = trap number
;
;       EXIT:   Carry clear,
;                   handle fatal normally.
;               Carry set,
;                   call to debugger.
;
;       USES:   Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Fatal, FAR16, PUBLIC
        push    ax
        push    bx
        push    ds
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        Pcall   GetTrapTblEntry, <ax>
        mov     ax,[bx].TrapTblFlag
        and     [bx].TrapTblFlag,not TRAP_FATAL_DISABLE
        test    ax,TRAP_FATAL_DISABLE   ; is the disable flag set?
        jnz     short dbfx              ;  yes, carry clear by test
        test    ax,TRAP_FATAL           ; is the fatal flag set?
        jz      short dbfx              ;  yes, carry clear by test
        stc                             ;  no, call debbugger
dbfx:   pop     ds
        pop     bx
        pop     ax
EndProc

;***    ExEnterDebugIRET - Debugger extension version of EnterDebugIRET
;
;       ENTRY:  far return address
;               trap number and flags
;               trap error code
;               user's IP
;               user's CS
;               user's Flags
;               [user's SP]
;               [user's SS]
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc ExEnterDebugIRET, FAR, PUBLIC
        cli                             ; make sure interrupts are disabled
        push    ds
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        pop     RegSA.DSsav             ; get ds off stack
        pop     FarReturnAddr.Offst16   ; save caller's return address
        pop     FarReturnAddr.Segmt16
        Pcall   EnterDebugIRET2
        push    FarReturnAddr.Segmt16   ; restore caller's return address
        push    FarReturnAddr.Offst16
EndProc

;***    ExEnterDebugRETF - Debugger extension version of EnterDebugRETF
;
;       ENTRY:  far return address
;               user's IP
;               user's CS
;               [user's SP]
;               [user's SS]
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc ExEnterDebugRETF, FAR, PUBLIC
        pushf                           ; save user's flags
        push    ds                      ; save user's DS
        cli                             ; make sure interrupts are disabled
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        pop     RegSA.DSsav             ; get ds off stack
        pop     RegSA.Fsav              ; get user's flags
        pop     FarReturnAddr.Offst16   ; save caller's return address
        pop     FarReturnAddr.Segmt16
        Pcall   EnterDebugINIT
        push    FarReturnAddr.Segmt16   ; restore caller's return address
        push    FarReturnAddr.Offst16
EndProc

;***    EnterDebugRETFD - enter debugger with an 32 bit far RET frame on stack
;
;       ENTRY:  near return address
;               user's EIP   (DWORD)
;               user's CS    (DWORD)
;               [user's ESP] (DWORD)
;               [user's SS]  (DWORD)
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING
.386p
Entry   EnterDebugRETFD, NEAR, PUBLIC
        pushfd                          ; save user's flags
        push    ds                      ; save user's DS
        cli                             ; make sure interrupts are disabled
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        mov     [InDebugger],TRUE       ; set that we are in debugger
        pop     [RegSA.DSsav]           ; get ds off stack
        pop     [RegSA.EFsav]           ; get user's flags

        pop     [ReturnAddr]            ; caller's return address
        pop     [RegSA.EIPsav]          ; get user's cs:eip
        pop     [RegSA.CSsav]
        pop     [Trash]                 ; discard SS.HighWord
        mov     [TrapNumber],NO_TRAPNUM ; no trap number, flags or error code
        mov     [ErrorCode],0           ;
        Pcall   SaveState386            ; save register state
        jmp     etd10

;***    EnterDebugIRETD - enter debugger with an 32 bit IRET frame on stack
;
;       ENTRY:  near return address
;               trap number     DWORD
;               trap error code DWORD
;               user's IP       DWORD
;               user's CS       DWORD
;               user's Flags    DWORD
;               [user's SP]     DWORD
;               [user's SS]     DWORD
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry   EnterDebugIRETD, NEAR, PUBLIC
        cli                             ; make sure interrupts are disabled
        push    ds
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        mov     [InDebugger],TRUE       ; set that we are in debugger
        pop     [RegSA.DSsav]           ; get ds off stack
        pop     [ReturnAddr]            ; caller's return address
        pop     [TrapNumber32]          ; get trap number
        pop     [ErrorCode]             ; get error code
        pop     [Trash]                 ; discard error code pad

        pop     [RegSA.EIPsav]          ; get iret frame
        pop     [RegSA.CSsav]
        pop     [Trash]                 ; discard CS.HighWord
        pop     [RegSA.EFsav]

        Pcall   SaveState386            ; save register state
        Pcall   WhatIsClientMode
        jc      short etd10             ; clean off prot-mode stack

;       V86 stack frame

        mov     ax,EXPR_SIZE_DWORD_W + EXPR_TYPE_SEG_W ; (AX) = CS address type
        pop     [RegSA.ESPsav]          ; stack was switched
        pop     [RegSA.SSsav]           ; get previous frame from stack
        pop     [Trash]                 ; discard SS.HighWord
        pop     [RegSA.ESsav]           ; get saved V86 segments
        pop     [Trash]                 ; discard ES.HighWord
        pop     [RegSA.DSsav]
        pop     [Trash]                 ; discard DS.HighWord
        pop     [RegSA.FSsav]
        pop     [Trash]                 ; discard FS.HighWord
        pop     [RegSA.GSsav]
        pop     [Trash]                 ; discard GS.HighWord
        jmp     short etd20

;       32 bit protected stack frame

etd10:  mov     ax,EXPR_SIZE_DWORD_W + EXPR_TYPE_SEL_W
        mov     [RegSA.ESPsav],esp
        mov     [RegSA.SSsav],ss
        test    [RegSA.CSsav],RPL_MASK  ; if came from lower priv level
        jz      short etd20
        pop     [RegSA.ESPsav]          ; stack was switched
        pop     [RegSA.SSsav]           ; get previous frame from stack
        pop     [Trash]                 ; discard SS.HighWord

etd20:  mov     [EntryESP],esp          ; save entry SS:ESP
        mov     [EntrySS],ss            ;
        movzxESP                        ; zero the high word of ESP       ;whs
        jmp     EnterDebug
.286p

;***    EnterDebugRETF - enter debugger with an far RET frame on stack
;
;       ENTRY:  near return address
;               user's IP       WORD
;               user's CS       WORD
;               [user's SP]     WORD
;               [user's SS]     WORD
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry   EnterDebugRETF, NEAR, PUBLIC
        pushf                           ; save user's flags
        push    ds                      ; save user's DS
        cli                             ; make sure interrupts are disabled
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        pop     [RegSA.DSsav]           ; get ds off stack
        pop     [RegSA.Fsav]            ; get user's flags

;***    EnterDebugINIT - enter debugger from initialization code
;
;       ENTRY:  (DS) = debugger data segment
;               (RegSA.Fsav) = user's flags
;               (RegSA.DSsav) = user's DS
;               near return address
;               user's IP
;               user's CS
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        assumeDATA ds
        ASSUME  ES:NOTHING, SS:NOTHING

Entry   EnterDebugINIT, NEAR, PUBLIC
        cli                             ; make sure interrupts are disabled
        mov     [InDebugger],TRUE       ; set that we are in debugger
        pop     [ReturnAddr]            ; caller's return address
        pop     [RegSA.IPsav]           ; get user's cs:ip
        pop     [RegSA.CSsav]
        mov     [TrapNumber],NO_TRAPNUM ; no trap number or error code
        mov     [ErrorCode],0           ;
        jmp     short EnterDebug16

;***    EnterDebugIRET - enter debugger with an IRET frame on stack
;
;       ENTRY:  near return address
;               trap number     WORD
;               trap error code WORD
;               user's IP       WORD
;               user's CS       WORD
;               user's Flags    WORD
;               [user's SP]     WORD
;               [user's SS]     WORD
;
;       EXIT:   DS = ES = SS = debugger data segment
;
;       USES:   ALL
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc EnterDebugIRET, NEAR, PUBLIC
        cli                             ; make sure interrupts are disabled
        push    ds
        Pcall   GetDebuggerDS           ; (DS) = debugger data
    assumeDATA  ds
        pop     [RegSA.DSsav]           ; get ds off stack

Entry   EnterDebugIRET2, NEAR, LOCAL
        mov     [InDebugger],TRUE       ; set that we are in debugger
        pop     [ReturnAddr]            ; caller's return address
        pop     [TrapNumber]            ; get trap number
        pop     [ErrorCode]             ; get error code
        pop     [RegSA.IPsav]           ; get iret frame
        pop     [RegSA.CSsav]           ;
        pop     [RegSA.Fsav]            ;

Entry   EnterDebug16, NEAR, LOCAL
        test    [DebData.InitFlag],INIT_CPU386
        jnz     short erd10
        Pcall   SaveState286            ; save 286 register state
        jmp     short erd20

erd10:  Pcall   SaveState386            ; save 386 register state
erd20:  mov     [RegSA.ESPsav.HighWord],0
        mov     [RegSA.EIPsav.HighWord],0
        mov     [RegSA.EFsav.HighWord],0
        mov     [EntryESP.HighWord],0

        mov     [RegSA.SPsav],sp
        mov     [RegSA.SSsav],ss

        mov     ax,EXPR_SIZE_DWORD_W + EXPR_TYPE_SEG_W
        Pcall   WhatIsClientMode        ; jump if not protected mode
        jnc     short erd25     ;
        mov     ax,EXPR_SIZE_DWORD_W + EXPR_TYPE_SEL_W

        test    [RegSA.CSsav],RPL_MASK  ; if came from lower priv level
        jz      short erd25
        pop     [RegSA.SPsav]           ; stack was switched
        pop     [RegSA.SSsav]           ; get previous frame from stack

erd25:  mov     [EntryESP.LowWord],sp
        mov     [EntrySS],ss

;       (AX) = CS address type

Entry   EnterDebug, NEAR, LOCAL
        CALLFAR NWDDisableWatchdogNMI
        mov     [DefType],ax            ; set default address type
        mov     [RegSA.CSIPsav.AddrTypeSize],ax
        mov     [StackTop],sp           ; save incoming SP
        cmp     [TrapNumber],SINGLE_STEP_TRAP   ; Are we single stepping?
        je      erd27                   ; Yes, don't clear fTraceCount
        cmp     [TrapNumber],BREAK_POINT_TRAP   ; Is this a BP?
        je      erd27                   ; Yes, don't clear fTraceCount

erd27:  mov     ax,ds                   ; (AX) = debugger's data segment
        mov     cx,ss                   ; (CX) = incoming SS
        cmp     ax,cx                   ; already on the debugger's stack?
        je      short erd30             ;  yes, don't reset to the begining
        mov     [StackTop],dataOFFSET StackTop
erd30:  mov     ss,ax                   ; (SS) = debugger's data segment
        mov     es,ax                   ; (ES) = debugger's data segment
        mov     sp,[StackTop]           ; (SP) = debugger's stack
        cld
    assumeDATA  <ds, es, ss>
        Pcall   DebCallOut, <DEB_CALLOUT_DEBENTRY>
        Pcall   GetCurrTask             ; (AX) = current task number
        mov     [RegSA.CSIPsav.AddrTask],ax
        Pcall   EnterMem                ; initialize the memory routines
        Pcall   CheckAllIdt             ; check real and prot IDTs for changes

;       Turn off trace bit in flag save area

        and     [RegSA.Fsav],not F_TRACE

;       Set up debugger defaults (like default address for
;       unassemble) and default address type.

        Pcall   SetDefaults

        cmp     [TrapNumber],BREAK_POINT_TRAP
        jne     short erd40

;       Need to decrement instruction pointer so it points to location
;       where breakpoint actually occured.

        dec     [RegSA.IPsav]

;       Restore the break point locations - must be done after the
;       user's cs:ip is corrected.

erd40:  Pcall   RestoreBPoints          ; restore break points
        push    [ReturnAddr]            ; put return address back on stack
EndProc

;***    PrintTrapMsg
;
;       Prints a trap message from trap message table.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, DX
;
        assumeDATA <ds, es, ss>

DefProc PrintTrapMsg, NEAR, PUBLIC
        mov     bx,[TrapNumber]                 ; (BX) = get trap number
        cmp     bx,NO_TRAPNUM
        jnz     short ptm00                     ; jmp if trap number
        jmp     ptmx                            ; jmp if no trap number

ptm00:  cmp     bx,SINGLE_STEP_TRAP
        jne     short ptm20
        Pcall   CheckDRhit
        jnc     ptm10                           ; jump if no DR reg hit
        putstr  "Debug register hit"
        jmp     ptm90

ptm10:  cmp     ContFlag,PTRACECMD
        je      short ptm20
        cmp     ContFlag,TRACECMD
        je      short ptm20
        putstr  "Trap 1 - Unexpected trace interrupt"
        jmp     short ptm90

ptm20:  cmp     bx,NUMBER_TRAPS
        jae     short ptmx
        Pcall   GetTrapTblEntry, <bx>
        mov     dx,[bx].TrapTblMsg              ; get address from table
        or      dx,dx                           ; if address is zero, don't
        jz      short ptmx                      ;  print trap message
        Pcall   rprbuf                          ; print trap message
        test    [bx].TrapTblFlag,TRAP_ERRCD     ; if trap flag zero then don't
        jz      short ptm70                     ;  print error code.
        Pcall   blank
        mov     dx,ErrorCode                    ; print error code
        Pcall   out16                           ;

        mov     bx,dataOFFSET TrapEDecode
        cmp     [TrapNumber],0eh                ; was it a page fault?
        jz      short ptm40
        or      dx,dx
        jz      short ptm70
        mov     bx,dataOFFSET TrapDecode
ptm40:  mov     ax,dx                           ; (AX) = error code
        push    cx
        mov     cx,3                            ; error codes have 3 bits
ptm45:  mov     dx,[bx]                         ; get 'bit-clear' message
        shr     ax,1
        jnc     short ptm50
        mov     dx,[bx+2]                       ; get 'bit-set' message
ptm50:  or      dx,dx
        jz      short ptm55
        Pcall   rprbuf                          ; print trap message
        cmp     dx,dataOFFSET TrapIDTMsg
        jz      short ptm60
ptm55:  add     bx,4                            ; skip two message pointers
        loop    ptm45
ptm60:  pop     cx

ptm70:  mov     ax,DebData.CSsel                ; (AX) = debugger selector
        Pcall   IsDebProtMode
        jc      short ptm80                     ; jump if protected mode
        mov     ax,DebData.CSseg                ; (AX) = debugger segment
ptm80:  cmp     ax,RegSA.CSsav
        jne     short ptm90                     ; jump if not in debugger
        putstr  " - In Debugger"
ptm90:  Pcall   crlf
ptmx:
EndProc

;***    Go
;
;       Jump to program, setting up registers according to the
;       save area. up to 10 breakpoint addresses may be specified.
;
        assumeDATA <ds, es, ss>

DefProc Go, NEAR, PUBLIC
        Pcall   GoSpecialCheck          ; get "S" option
        Pcall   ExecTrapOptionCheck     ; get "T" option
        Pcall   SetAdd                  ; get potential starting point
        mov     BPcount,0               ; clear GO breakpoint count
        mov     Tcount,0                ; clear trace count
        mov     fRegDisp,1              ; register display enabled
        mov     fTraceAddr,0            ; disable trace address mode
        mov     fTraceCount,0           ; disable trace count mode

go1:    Pcall   ScanP
        jz      go2
        mov     bx,dataOFFSET TmpAddr
        Pcall   EvalAddr, <dataOFFSET RegSA.CSIPsav, bx>
        Pcall   CheckAddr, <bx>
        Pcall   SetGoBP                 ; get the GO breakpoint
        jmp     go1

go2:    Pcall   ExecuteTrapHandler
        jnc     go3                     ; jump if no trap handler to execute
        mov     BPointTrace,TRUE
go3:    mov     ContFlag,GOCMD
        jmp     SetBPsAndGo
EndProc NoGen

IFDEF   KDP
;***    Go
;
;       Jump to program, setting up registers according to the
;       save area. up to 10 breakpoint addresses may be specified.
;
        assumeDATA <ds, es, ss>

DefProc KDPGo, NEAR, PUBLIC, C
        mov     BPcount,0               ; clear GO breakpoint count
        mov     Tcount,0                ; clear trace count
        mov     fRegDisp,1              ; register display enabled
        mov     ContFlag,GOCMD
        jmp     SetBPsAndGo
EndProc NoGen
ENDIF

;***    Ptrace
;
;       just like trace except skips OVER next INT or CALL.
;
        assumeDATA <ds, es, ss>

DefProc Ptrace, NEAR, PUBLIC
        Pcall   RegDispCheck            ; get "N" option
        Pcall   ExecTrapOptionCheck     ; get "T" option
        Pcall   SetAdd                  ; get potential starting point
        mov     BPcount,0               ; clear GO breakpoint count
        mov     Tcount,0                ; clear trace count
        mov     fTraceAddr,0            ; disable trace address mode
        mov     fTraceCount,0           ; disable trace count mode
        Pcall   ScanP
        jz      short ptr1
        Pcall   EvalWord                ; get trace count
        mov     Tcount,dx               ; save trace count
ptr1:   Pcall   ExecuteTrapHandler

Entry   PtraceAgain, NEAR, LOCAL
        mov     ContFlag,PTRACECMD
        Pcall   GetInstPrefix
        jc      short ptr2              ; jump if error

;       (AL) = opcode at CS:IP + DX
;       (BX) = CS:IP AddrS pointer
;       (DX) = number of prefixes
;       (CX) = number of repe/repne prefixes

        cmp     al,0E8h                 ; direct intra call
        je      short ptr4
        cmp     al,9Ah                  ; direct inter call
        je      short ptr4
        cmp     al,0FFh                 ; indirect?
        je      short ptr3              ; yes, go figure length
        cmp     al,0CCh                 ; short interrupt?
        je      short PtraceInt3
        cmp     al,0CDh                 ; long interrupt?
        je      short ptr4
        cmp     al,11100010b            ; LOOP
        je      short ptr4
        cmp     al,11100001b            ; LOOPZ/LOOPE
        je      short ptr4
        cmp     al,11100000b            ; LOOPNZ/LOOPNE
        je      short ptr4
        jcxz    ptr2                    ; jump if no rep/repne prefixes
        and     al,11111110b            ; ignore w bit
        cmp     al,10100100b            ; MOVS
        je      short ptr4
        cmp     al,10100110b            ; CMPS
        je      short ptr4
        cmp     al,10101110b            ; SCAS
        je      short ptr4
        cmp     al,10101100b            ; LODS
        je      short ptr4
        cmp     al,10101010b            ; STOS
        je      short ptr4
ptr2:   jmp     SetTraceAndGo           ; bogus, do single step

;       Ptrace INT 3's not put in by the debugger

Entry   PtraceInt3, NEAR, LOCAL
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   AddAddr, <1, 0>         ; advance over INT 3
        mov     TrapNumber,SINGLE_STEP_TRAP
        jmp     CheckTraceCount

;       Indirect near or far call

ptr3:   inc     dx
        Pcall   GetByteOff, <dx, 0>     ; (AL) = byte at cs:ip + dx
        jc      short ptr2              ; jump if error
        mov     ah,al
        and     al,11000000b            ; get mod
        and     ah,00111000b            ; get type
        cmp     ah,00010000b
        je      ptr4                    ; Brif Intra indirect
        cmp     ah,00011000b            ; Inter indirect?
        jne     ptr2                    ; Not a CALL instr

;       Ptrace instruction

ptr4:   Ccall   disasm, <dataOFFSET opbuf, dataOFFSET RegSA.CSIPsav>
        mov     dx,ax                   ; (DX) = size of instruction to ptrace
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   SetTmpBP
        jmp     SetBPsAndGo
EndProc NoGen

;***    Trace
;
;       Trace 1 instruction or the number of instruction specified
;       by the parameter using 8086 trace mode. Registers are all
;       set according to values in save area
;
        assumeDATA <ds, es, ss>

DefProc Trace, NEAR, PUBLIC
        Pcall   TraceAddrCheck          ; get "A" option
        Pcall   TraceCountCheck         ; get "C" option
        Pcall   RegDispCheck            ; get "N" option
        Pcall   TraceSpecialCheck       ; get "S" option
        Pcall   ExecTrapOptionCheck     ; get "T" option
        Pcall   TraceBadCheck           ; get "X" option
        Pcall   SetAdd                  ; get potential starting point
        mov     BPcount,0               ; clear GO breakpoint count
        mov     Tcount,0                ; clear trace count
        Pcall   ScanP
        jnz     short trc10
        mov     fTraceAddr,0            ; No count/addr, so turn off fTraceAddr
        jmp     short trc20

trc10:  cmp     fTraceAddr,0            ; Tracing to an address?
        je      short trc15             ;  No. Don't compare

        mov     fTraceAddr,0            ; In case anything goes wrong
        mov     bx,dataOFFSET TraceAddr
        Pcall   EvalAddr, <dataOFFSET RegSA.CSIPsav, bx>
        Pcall   CheckAddr, <bx>
        inc     fTraceAddr
        jmp     short trc20

trc15:  Pcall   EvalWord                ; get trace count
        mov     Tcount,dx               ; set trace count

trc20:  mov     ContFlag,TRACECMD
        Pcall   ExecuteTrapHandler
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   GetByte                 ; (AL) = byte at cs:ip
        jc      short trc30             ; jump if error
        cmp     al,INT3_OP              ; short interrupt?
        je      short trc40             ; jump if INT 3
trc30:  jmp     SetTraceAndGo

trc40:  jmp     PtraceInt3              ; go to ptrace int 3 code
EndProc NoGen

IFDEF   KDP
;***    KDPTrace
;
;       Trace 1 instruction or the number of instruction specified
;       by the parameter using 8086 trace mode. Registers are all
;       set according to values in save area
;
        assumeDATA <ds, es, ss>

DefProc KDPTrace,NEAR, PUBLIC,C
        mov     BPcount,0               ; clear GO breakpoint count
        mov     Tcount,0                ; clear trace count
        mov     ContFlag,TRACECMD
        jmp     SetTraceAndGo
EndProc NoGen
ENDIF

;***    RegDispCheck - check for supressed register display
;
;       Examines command line to see if register display is disabled.
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over N option if present
;               [fRegDisp] = 0 if N option
;               [fRegDisp] = 1 if no N option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc RegDispCheck, NEAR, LOCAL
        mov     fRegDisp,1              ; presume reg disp
        Pcall   PeekChr
        jz      short rdcx
        cmp     al,'N'                  ; is this trace-no-display?
        jne     short rdcx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        mov     fRegDisp,0              ; indicate no register display
rdcx:
EndProc

;***    TraceAddrCheck - check for tracing to an address
;
;       Examines command line to see if tracing to an address is enabled
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over A option if present
;               [fTraceAddr] = 1 if A option
;               [fTraceAddr] = 0 if no A option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc TraceAddrCheck, NEAR, LOCAL
        mov     fTraceAddr,0            ; presume reg disp
        Pcall   PeekChr
        jz      short tacx
        cmp     al,'A'                  ; is this trace-no-display?
        jne     short tacx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        inc     fTraceAddr              ; indicate no register display
tacx:
EndProc

;***    TraceCountCheck - check for tracing count only
;
;       Examines command line to see if tracing count only is enabled
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over C option if present
;               [fTraceCount] = 1 if C option
;               [fTraceCount] = 0 if no C option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc TraceCountCheck, NEAR, LOCAL
        mov     fTraceCount,0           ; presume reg disp
        Pcall   PeekChr
        jz      short tccx
        cmp     al,'C'                  ; is this trace-no-display?
        jne     short tccx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        inc     fTraceCount             ; indicate count only
        inc     fTraceAddr              ; indicate end address needed
        .386p
        mov     InstCount,0             ; Zero out instruction count
        .286p
tccx:
EndProc

;***    TraceBadCheck - check for tracing "bad" regions
;
;       Examines command line to see if tracing bad regions is enabled
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over X option if present
;               [fDoTraceBad] = 1 if X option
;               [fDoTraceBad] = 0 if no X option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc TraceBadCheck, NEAR, LOCAL
        mov     fDoTraceBad,0           ; presume sensible tracing
        Pcall   PeekChr
        jz      short tbcx
        cmp     al,'X'                  ; is this trace-no-display?
        jne     short tbcx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        inc     fDoTraceBad             ; indicate bad region trace
tbcx:
EndProc

;***    TraceSpecialCheck - check for printing "Special" instructions
;
;       Examines command line to see if tracing special inst. is enabled
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over S option if present
;               [fDoTraceBad] = 1 if S option
;               [fDoTraceBad] = 0 if no S option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc TraceSpecialCheck, NEAR, LOCAL
        mov     fTraceSpecial,0         ; presume normal tracing
        Pcall   PeekChr
        jz      short tscx
        cmp     al,'S'                  ; is this trace-no-display?
        jne     short tscx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        inc     fTraceSpecial           ; indicate bad region trace
        inc     fTraceCount             ; indicate count only
        inc     fTraceAddr              ; indicate end address needed
        .386p
        mov     InstCount,0             ; Zero out instruction count
        .286p
        mov     TraceCallsDepth,0       ; Start out w/ empty stack
tscx:
EndProc

;***    GoSpecialCheck - check for printing "Special" instructions
;
;       Examines command line to see if special Go mode enabled
;
;       ENTRY   pTXT points to command line
;
;       EXIT    pTXT advanced over S option if present
;               [fDoGoSpecial] = 1 if S option
;               [fDoGoSpecial] = 0 if no S option
;
;       USES    AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc GoSpecialCheck, NEAR, LOCAL
        mov     fDoGoSpecial,0          ; presume normal tracing
        Pcall   PeekChr
        jz      short gscx
        cmp     al,'S'                  ; is this trace-no-display?
        jne     short gscx              ; no, go process remainder
        Pcall   SkipB                   ; eat character
        inc     fDoGoSpecial            ; indicate bad region trace
        Pcall   ZeroGoTime
gscx:
EndProc

;***    ExecTrapOptionCheck - check for execute trap handler option flag
;
;       Check for the "T" option.
;
;       ENTRY:  NONE
;
;       EXIT:   [fExecTrap] == 0, if no T option
;               [fExecTrap] != 0, if T option found
;
;       USES:   AX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc ExecTrapOptionCheck, NEAR, LOCAL
        mov     fExecTrap,0
        Pcall   PeekChr                 ; (AL) = first char on cmd line
        jz      short etox              ; jump if EOL
        cmp     al,"T"
        jne     short etox              ; jump if not "T" option
        Pcall   SkipB
        inc     fExecTrap
etox:
EndProc

;***    SetAdd
;
;       Set a CSsav:IPsav address to go, trace or ptrace.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX
;
        assumeDATA <ds, es, ss>

DefProc SetAdd, NEAR, LOCAL
        Pcall   ScanP
        cmp     al,"="
        jnz     sa2
        Pcall   GetChrI
        jnz     sa1
sa0:    Jump    perror

sa1:    mov     bx,dataOFFSET TmpAddr
        Pcall   EvalAddr,<dataOFFSET RegSA.CSIPsav, bx>
        Pcall   CheckAddr, <bx>
        Pcall   GetAddrType             ; (AL) = AddrType from [bx]
        cmp     al,DefType.LowByte
        jne     sa0
        Pcall   CopyAddr,<bx, dataOFFSET RegSA.CSIPsav>
sa2:
EndProc

;***    ExecuteTrapHandler
;
;       The "T" option on the go, trace or ptrace allows trapped
;       exceptions to continued or traced at the original address
;       that was in the IDT before the debugger intercepted the
;       exception.  This is done by restoring the IDT vector, but
;       leaving the trap table flags set.  A temporary breakpoint
;       is set at the original exception address retrieved from the
;       trap table.  This is done to re-entry the debugger to restore
;       the trap's IDT entry (and to stop in the trace or ptrace
;       case).  Since the trap table flags indicate that the vector
;       is set, the CheckAllIdt routine (done whenever we entry the
;       kernel) resets the IDT to point back to the debugger.
;
;       ENTRY:  NONE
;
;       EXIT:   If carry clear, no trap handler to execute
;               If carry set, setup to execute trap handler
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc ExecuteTrapHandler, NEAR, LOCAL
        cmp     fExecTrap,0                     ; check if "T" option specified
        je      short eth10
        mov     cx,TrapNumber                   ; (CX) = trap number
        cmp     cx,NO_TRAPNUM
        je      short eth10                     ; jump if not trap entry
        Pcall   GetTrapTblEntry, <cx>           ; (BX) = trap table index
        Pcall   CopyAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET TmpAddr>
        Pcall   IsDebProtMode
        jc      short eth20                     ; jump if protected mode

        test    [bx].TrapTblFlag,TRAP_RM_USED
        jz      short eth10                     ; jump if trap not set

        mov     ax,[bx].TrapTblRMsave.Offst16
        mov     TmpAddr.AddrOff.LowWord,ax
        mov     TmpAddr.AddrOff.HighWord,0
        mov     ax,[bx].TrapTblRMsave.Segmt16
        mov     TmpAddr.AddrSeg,ax
        mov     dx,TRAP_RM_FORCE
        jmp     short eth40

eth10:  clc
        jmp     short ethx

eth20:  test    [bx].TrapTblFlag,TRAP_FATAL
        jz      short eth30                     ; jump if fatal trap clear
        or      [bx].TrapTblFlag,TRAP_FATAL_DISABLE

eth30:  test    [bx].TrapTblFlag,(TRAP_PM_USED + TRAP_V86_USED)
        jz      short eth10                     ; jump if trap clear

        mov     ax,[bx].TrapTblPMsave.GateOffset
        mov     TmpAddr.AddrOff.LowWord,ax
        mov     ax,[bx].TrapTblPMsave.GateExtOffset
        mov     TmpAddr.AddrOff.HighWord,ax
        mov     ax,[bx].TrapTblPMsave.GateSelector
        mov     TmpAddr.AddrSeg,ax
        mov     dx,TRAP_PM_FORCE

;       (CX) = trap number
;       (BX) = trap table entry pointer
;       (DX) = RestIdtEntry flags

eth40:  Pcall   RestIdtEntry, <dx, cx>
        xor     dx,dx
        mov     bx,dataOFFSET TmpAddr
        Pcall   SetTmpBP
        stc
ethx:
EndProc

;***    SetBPsAndGo
;
;       Set all the breakpoints in breakpoint table and return
;       to the debugged code. This entry doesn't set a breakpoint
;       at CS:IP, but instead traces over the instruction and then
;       goes with all the BP's set.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE - the debugged code is returned to.
;
        assumeDATA <ds, es, ss>

Entry   SetBPsAndGo, NEAR, LOCAL
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   ChkBPaddr
        jz      short sbg1              ; jump if a BP at current CS:IP
        jmp     PutBPsAndGo             ; just go to user code

;       See if there is a repe/repne string opcode at the breakpoint

sbg1:   Pcall   GetInstPrefix
        jc      short sbg3              ; jump if error

;       (AL) = opcode at CS:IP + DX
;       (BX) = CS:IP AddrS pointer
;       (DX) = number of prefixes
;       (CX) = number of repe/repne prefixes

        jcxz    short sbg3              ; jump if no repe/repne prefixes
        and     al,11111110b            ; ignore w bit
        cmp     al,10100100b            ; MOVS
        je      short sbg2
        cmp     al,10100110b            ; CMPS
        je      short sbg2
        cmp     al,10101110b            ; SCAS
        je      short sbg2
        cmp     al,10101100b            ; LODS
        je      short sbg2
        cmp     al,10101010b            ; STOS
        jne     short sbg3              ; jump if not a string opcode

;       There is a breakpoint on a repe/repne string opcode. Set a
;       single breakpoint after it and then go.

sbg2:   inc     dx
        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   SetTmpBP
        mov     BPointTrace,TRUE        ; set continue after hitting BP flag
        jmp     PutBPsAndGo             ;

sbg3:   mov     BPointTrace,TRUE        ; trace over instruction and then GO

;***    SetTraceAndGo
;
;       Set trace bit in debuggee's flags and return, single stepping
;       one instruction.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE - the debugged code is returned to.
;
        assumeDATA <ds, es, ss>

Entry   SetTraceAndGo, NEAR, LOCAL

;       Check if tracing over an PUSHF

        Pcall   GetInstPrefix
        .386p
        jc      stg45
        .286p

;       (AL) = opcode at CS:IP + DX
;       (BX) = CS:IP AddrS pointer
;       (DX) = number of prefixes

        cmp     al,PUSHF_OP
        .386p
        je      stg80
        .286p

        cmp     fTraceSpecial,0         ; Special tracing
        je      stg25                    ; No.

        cmp     BPointTrace,TRUE        ; Don't print traced BP's
        .386p
stg25:  je      stg45
        .286p

; Trace Special will only trace in a single context. So if a context switch
; is about to occur we set a breakpoint at the end of the switch and then
; will leave that BP set until TraceSpecial is turned off or the same
; context is hit again.

        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET ContextStartAddr>
        jc      stg30
        jnz     stg30                   ;  No.
        Pcall   SaveContext

        printf  <"Switching context... ">
        Pcall   crlf

        mov     bx, dataOFFSET ContextEndAddr   ; BX = Where to start tracing
        xor     dx,dx                           ; DX = offset from BX address
        Pcall   SetTmpBP                        ; Put a BP There
        mov     bx, dataOFFSET ContextEndAddr2  ; BX = Where to start tracing
        xor     dx,dx                           ; DX = offset from BX address
        Pcall   SetTmpBP                        ; Put a BP There
        jmp     PutBPsAndGo                     ; And go

;
; Check to see if the return address on the top of the trace stack is hit.
;

stg30:  mov     bx, dataOFFSET TraceCallsStack
        mov     ax, size AddrS
        mov     cx, TraceCallsDepth
        or      cx,cx                   ; If 0 then nothing on stack
        jz      stg33                   ;  So don't compare addresses

        mov     bx, TraceCallsFirst     ; BX = Offset of most recent expected
                                        ;      return address
        Pcall   CompareAddr, <dataOFFSET RegSA.CSIPsav, bx>
        jc      stg35                   ; Error. Assume different address
        jnz     stg35                   ; Not same address. Do nothing.

;
; We get here when the address at the top of the trace stack is hit.
;
        dec     TraceCallsDepth
        mov     cx, TraceCallsSecond
        mov     TraceCallsFirst, cx
        sub     cx, size AddrS
        mov     TraceCallsSecond, cx
        .386p
        mov     edx, dword ptr InstCount
        printf  <"Exit: %ld">, <edx>
        .286p
        Pcall   crlf
stg33:  jmp     stg40

;
; This second check is to make sure something really bogus didn't happen
; and we missed the first return address. Of course looking for the
; second frame is no guarantee either but it increases the odds of
; re-syncing. Note that this method of looking for return addresses will
; get confused by mutually recursive procedures. Oh well. Such is life...
;

stg35:  mov     cx, TraceCallsDepth
        cmp     cx,2                    ; Enough call frames in trace stack?
        jl      stg40                   ;  No. Don't check.

        mov     bx, TraceCallsSecond    ; BX = Offset of second RET
        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, bx>
        jc      stg40                   ; Compare error. Assume no.
        jnz     stg40                   ; Not same address. Do nothing.

        sub     TraceCallsDepth,2
        mov     bx,TraceCallsSecond
        sub     bx, size AddrS
        mov     TraceCallsFirst, bx
        sub     bx, size AddrS
        mov     TraceCallsSecond, bx


        printf  <"...Special exit follows...">  ; Just for reference...
        Pcall   crlf
        .386p
        mov     edx, dword ptr InstCount
        printf  <"Exit: %ld">, <edx>
        .286p
        Pcall   crlf
        .386p
        printf  <"Exit: %ld">, <edx>
        .286p
        Pcall   crlf

;
; The following section of code looks for CALL instuctions. When a CALL is
; found, the address of the instruction *following* the call is recorded
; on the assumption that when we hit that address the call is over. This
; method is safer then looking for a matching RET because calls and returns
; don't always match. You get two RETs per call when using a hybrid entry
; point in the kernel and no returns for a CALL when a jump is made back
; to the caller (PM does this).
;

stg40:  Pcall   GetInstPrefix
        jc      short stg45

;       (AL) = opcode at CS:IP + DX
;       (BX) = CS:IP AddrS pointer
;       (DX) = number of prefixes


        cmp     al,09Ah                 ; CALL instruction?
        je      stg43
        cmp     al,0E8h                 ; CALL instruction?
        je      stg43
        cmp     al,0FFh                 ; 2-byte CALL instruction?
        jne     stg45
        inc     dx                      ; Look at next byte
        Pcall   GetByteOff, <dx, 0>
        jc      stg45
        and     al,00111000b            ; Isolate opcode bits
        cmp     al,00010000b
stg43:  je      stg85
        cmp     al,00011000b
        je      stg85

;       Set trace bit and return to debuggee's code

stg45:  cmp     fDoTraceBad,0           ; Trace through bad code?
        jne     short stg75             ;  Yes.

;
; Check for tracing within know "bad" sections of code. When tracing in
; one, set a temporary breakpoint following the region and Go to that
; breakpoint.
;
        mov     cx, dataOFFSET btatab   ; (CX) = bad address table
        mov     dx, MAX_BAD_TRACE       ; (DX) = number of entries

stg50:  or      dx,dx                   ; Finished w/ table?
        jz      short stg75

        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, cx>
        jc      short stg55
        cmp     ax,-1                   ; CS:EIP < bad start address?
        je      short stg55             ;  Yes. Not a problem

        add     cx, size AddrS          ; (CX) at an end address
        Pcall   CompareLinAddr, <dataOFFSET RegSA.CSIPsav, cx>
        jc      short stg55
        cmp     ax,-1                   ; CS:EIP < bad end address?
        jne     short stg60             ;  No. Not a problem

; We get here if the CS:EIP falls in a bad range. So set a breakpoint at
; the end of the range and go.

        mov     bx,cx                   ; BX = where BP should be set
        xor     dx,dx                   ; DX = 0 offset from AddrS in BX
        Pcall   SetTmpBP                ; Don't trace through it!
        mov     fTraceSpecial2,0
        jmp     PutBPsAndGo

stg55:  add     cx, size AddrS
stg60:  add     cx, size AddrS
stg65:  dec     dx
        jmp     short stg50

stg75:  cmp     fTraceSpecial2,0        ; Set the trace flag?
        je      stg73                   ;  Yes.
        mov     fTraceSpecial2,0        ;  No. Zero extra flat
        jmp     PutBPsAndGo             ;      and go.
stg73:  or      RegSA.Fsav,F_TRACE
        jmp     PutBPsAndGo

stg80:  mov     [fSSPushF],TRUE         ; Stepping over a PushF
        jmp     stg45

;
;       Verify that there is room on the trace stack for the return address.
;       If there is, then stick the new address on the stack.
;

stg85:  cmp     TraceCallsDepth, MAX_TRACE_CALLS        ; Is there room?
        jl      stg90                                   ;  Yes.

        printf  <"Warning: Out of TS stack space.">
        Pcall   crlf
        jmp     stg45

;
;       DisAssemble and print the CALL instruction.
;
        .386p
stg90:  mov     edx, dword ptr InstCount
        printf  <"   Instruction Count: %ld">, <edx>
        .286p
        Pcall   crlf
        Pcall   CopyAddr, <dataOFFSET RegSA.CSIPsav, dataOFFSET DisAddr>
        Pcall   disasln                 ; Disassemble one line
        or      ax,ax
        .386p
        jz      stg45
        .286p
        Ccall   decodeop, <dataOFFSET opbuf>    ; Decode operands into buffer
        mov     dx,dataOFFSET opbuf
        Pcall   rprbuf                  ; Print disassembled instructions
        Pcall   crlf


        mov     bx, dataOFFSET TraceCallsStack
        mov     ax, size AddrS
        mul     TraceCallsDepth
        add     bx,ax                   ; BX = First unused stack address
        Pcall   CopyAddr, <dataOFFSET DisAddr, bx>
        inc     TraceCallsDepth
        mov     cx,TraceCallsFirst
        mov     TraceCallsSecond, cx
        mov     TraceCallsFirst, bx

        jmp     stg45

;***    PutBPsAndGo
;
;       Puts the breakpoints from the sticky and GO breakpoint
;       tables except any that are at CS:IP.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE - the debugged code is returned to.
;
        assumeDATA <ds, es, ss>

Entry   PutBPsAndGo, NEAR, LOCAL
        Pcall   PutBPoints, <FALSE>     ; don't set a BP at CS:IP

;       Check if there is a INT 3 at CS:IP. If there is then this
;       is a INT 3 put in by the user and will be skipped.

        mov     bx,dataOFFSET RegSA.CSIPsav
        Pcall   GetByte                 ; (AL) = byte at cs:ip
        jc      short pbg1

        cmp     al,INT3_OP
        jne     short pbg1

        Pcall   AddAddr, <1, 0>         ; advance over INT 3
pbg1:   jmp     short ExitDebugNoBP

;***    ExitDebug - return to user code
;
;       The basic technique is to build, on the appropriate stack,
;       an valid iret frame, and then do an 'iret' back to the interrupted
;       code.
;
;       Set all the breakpoints in breakpoint tables and return
;       to the debugged code. This includes a breakpoint at
;       CS:IP.
;
;       In real address mode, life is simple; we never need to change
;       stacks during an iret. In protected mode, one of two conditions obtains.
;               1.  We are returning to code in the same ring as we
;                   are currently executing.  This is analogous to the
;                   real address situation, in that we are going to stay
;                   on the same stack.
;               2.  We are doing an outward return.  In this case, we build
;                   the frame with the ss:sp to be picked up on the stack.
;
;       ENTRY:  the state of the machine is in RegSA, interrupts disable.
;
;       EXIT:   NONE - the debugged code is returned to.
;
        assumeDATA <ds, es, ss>
.386p
DefProc ExitDebug, NEAR, PUBLIC
        Pcall   PutBPoints, <TRUE>              ; set all BPs

Entry   ExitDebugNoBP, NEAR, PUBLIC

        cmp     fDoGoSpecial,0
        je      exb1
        Pcall   CheckGoTime

exb1:   CALLFAR NWDRestoreWatchdogNMI
        test    [DebData.InitFlag],INIT_CPU386  ; 386?
        jnz     short exb10                     ; jmp if so
        Pcall   ExitDebugIRET
        iret                                    ; return to debugged code

exb10:  Pcall   ExitDebugIRETD
        iretd                                   ; return to debugged code
EndProc NoGen
.286p
;***    ExitDebugIRET - 286 exit routine
;
;       Restores the user state and returns to call.  All that is
;       is an 16 bit IRET frame on the user's stack.
;
;       ENTRY:  NONE
;
;       EXIT:   All user registers restored
;
;       USES:   ALL
;
        assumeDATA <ds, es, ss>

DefProc ExitDebugIRET, NEAR, PUBLIC

exi1:   pop     [ReturnAddr]
        Pcall   DebCallOut, <DEB_CALLOUT_DEBEXIT>
        Pcall   ExitAllIdt
        Pcall   RestState286                    ; restore 286 registers
        Pcall   WhatIsClientMode
        jz      short exi10                     ; jump if real-mode

; We get the start time (in case of "GS" timing) at the *last* moment.

        cmp     fDoGoSpecial,0                  ; Special go?
        je      exi5                            ;  No.
        Pcall   MarkGoTime

;       Build 286 protected mode frame

exi5:   test    [RegSA.CSsav],RPL_MASK          ; check if privilege level
        jz      short exi10                     ;  is greater than ring zero

        mov     ss,[EntrySS]
        mov     sp,[EntryESP.LowWord]           ; (SS:SP) = SS:SP on entry

        push    [RegSA.SSsav]                   ; prepare to switch stacks
        push    [RegSA.SPsav]                   ; by pushing long iret frame
        jmp     short exi20

;       Build real-mode stack frame

exi10:  mov     ss,[RegSA.SSsav]                ; point to the target stack
        mov     sp,[RegSA.SPsav]

exi20:  push    [RegSA.Fsav]                    ; build 16 bit iret frame
        push    [RegSA.CSsav]
        push    [RegSA.IPsav]
        push    [ReturnAddr]

        mov     [InDebugger],FALSE
        mov     ds,[RegSA.DSsav]                ; point to the target data seg
EndProc

;***    ExitDebugIRETD - 386 exit routine
;
;       Restores the user state and returns to call.  All that is
;       is an 32 bit IRET frame on the user's stack.
;
;       ENTRY:  NONE
;
;       EXIT:   All user registers restored
;
;       USES:   ALL
;
        assumeDATA <ds, es, ss>
.386p
DefProc ExitDebugIRETD, NEAR, PUBLIC

exd1:   pop     [ReturnAddr]
        Pcall   DebCallOut, <DEB_CALLOUT_DEBEXIT>
        Pcall   ExitAllIdt
        Pcall   RestState386                    ; restore 386 registers
        mov     ss,[EntrySS]
        mov     esp,[EntryESP]                  ; (SS:ESP) = SS:ESP on entry
        Pcall   WhatIsClientMode
        jz      short exd30                     ; jump if real-mode
        jc      short exd10                     ; protected mode

;       Build 386 V86 stack frame

        push    0
        push    [RegSA.GSsav]
        push    0
        push    [RegSA.FSsav]
        push    0
        push    [RegSA.DSsav]
        push    0
        push    [RegSA.ESsav]
        jmp     short exd20                     ; Finish setting up frame

;       Build 386 protected mode stack frame

; We get the start time (in case of "GS" timing) at the *last* moment.

exd10:  cmp     fDoGoSpecial,0                  ; Special go?
        je      short exd15                     ;  No.
        Pcall   MarkGoTime

exd15:  test    [RegSA.CSsav],RPL_MASK          ; check if privilege level
        jz      short exd30                     ;  is greater than ring zero

exd20:  push    0                               ; prepare to switch stacks
        push    [RegSA.SSsav]
        push    [RegSA.ESPsav]                  ; by pushing long iret frame
        jmp     short exd40

exd30:  mov     ss,[RegSA.SSsav]                ; point to the target stack
        mov     esp,[RegSA.ESPsav]

exd40:  push    [RegSA.EFsav]                   ; build 32 bit iret frame
        push    0
        push    [RegSA.CSsav]
        push    [RegSA.EIPsav]
        push    [ReturnAddr]
        mov     [InDebugger],FALSE
        Pcall   WhatIsClientMode
        ja      short exdx                      ; V86, don't restore segs
        mov     ds,[RegSA.DSsav]                ; restore ds
exdx:
EndProc
.286p

;***    SaveState286
;
;       Saves a 286 machine's state in save area.
;
;       ENTRY:  DS = debugger's data segment.
;
;       EXIT:   All the registers saved except DS, SS, SP, IP, CS & Flags.
;
;       USES:   ES, FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;                The client's flags must have been already saved in RegSA.Fsav.
;
        assumeDATA ds
        ASSUME  ES:NOTHING, SS:NOTHING

DefProc SaveState286, NEAR, LOCAL
        mov     [RegSA.AXsav],ax                        ; No, do 286
        mov     [RegSA.BXsav],bx
        mov     [RegSA.CXsav],cx
        mov     [RegSA.DXsav],dx
        mov     [RegSA.BPsav],bp
        mov     [RegSA.SIsav],si
        mov     [RegSA.DIsav],di
        mov     [RegSA.ESsav],es
        smsw    [RegSA.MSWsav]                  ; save msw
        mov     [RegSA.CR0sav.HighWord],0
        mov     [RegSA.GDTsav.DTRBaseExt],0     ; clear high byte for 286
        sgdt    [RegSA.GDTsav]                  ; save gdt register
        mov     [RegSA.IDTsav.DTRBaseExt],0     ; clear high byte for 286
        sidt    [RegSA.IDTsav]                  ; save idt register
        Pcall   SaveCommonState
EndProc

;***    SaveState386
;
;       Saves 386 machine's state in save area.
;
;       ENTRY:  DS = debugger's data segment.
;
;       EXIT:   All the registers saved except DS, SS, SP, IP, CS & Flags.
;
;       USES:   ES, FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;                The client's flags must have been already saved in RegSA.Fsav.
;
        assumeDATA ds
        ASSUME  ES:NOTHING, SS:NOTHING
.386p
DefProc SaveState386, NEAR, LOCAL
        mov     [RegSA.EAXsav],eax
        mov     [RegSA.EBXsav],ebx
        mov     [RegSA.ECXsav],ecx
        mov     [RegSA.EDXsav],edx
        mov     [RegSA.EBPsav],ebp
        mov     [RegSA.ESIsav],esi
        mov     [RegSA.EDIsav],edi
        mov     [RegSA.ESsav],es
        mov     [RegSA.FSsav],fs
        mov     [RegSA.GSsav],gs
        mov     eax,cr0
        mov     [RegSA.CR0sav],eax
        mov     eax,cr2
        mov     [RegSA.CR2sav],eax
        mov     eax,dr0
        mov     [RegSA.DR0sav],eax
        mov     eax,dr1
        mov     [RegSA.DR1sav],eax
        mov     eax,dr2
        mov     [RegSA.DR2sav],eax
        mov     eax,dr3
        mov     [RegSA.DR3sav],eax

;       If the BS bit is set, we are entering the kernel debugger because
;       of a single step trap.  Now that we're here, we clear BS to prevent
;       handling the single step twice.

        mov     eax,dr6
        and     eax,not (mask DR6_BS)           ; clear BS bit in DR6 image
        mov     [RegSA.DR6sav],eax
        mov     eax,dr7
        mov     [RegSA.DR7sav],eax
        mov     [RegSA.DR7sav2],eax

;       The TR6, TR7 and CR3 registers have to be read
;       after the debug registers (DR7) are disabled because
;       of some 386 errata.

        and     eax,not (mask DR7_G0 + mask DR7_G1 + mask DR7_G2 + mask DR7_G3)
        mov     dr7,eax                         ; disable any debug registers

;;      The save/restore of TR6 and TR7 is currently disabled. The restore code
;;      below would not work anway, so there is no point in saving. The way of
;;      accessing tr6/tr7 changes in an incompatible manner for the P5 also,
;;      which breaks us. Paul.
;;      mov     eax,tr6
;;      mov     [RegSA.TR6sav],eax
;;      mov     eax,tr7
;;      mov     [RegSA.TR7sav],eax

        mov     eax,cr3
        mov     [RegSA.CR3sav],eax

	push	ds			; 157841 
	DosContext <ds>,ax              ; 157841
        cmp     [_CpuVendor],CPU_CYRIX  ; 157841 is this and IBM/CYRIX CPU
	pop	ds			; 157841
        assumeDATA ds                   ; 157841
        jz      @F                      ; 157841 yes, don't do cr4 instruction

	push	ds									; 148688
	DosContext <ds>,ax              ;						; 148688
        cmp     [_CpuType],CPU_PENTIUM  ; check for Pentium				; 148688
	pop	ds									; 148688
        assumeDATA ds
        jne     @F									; 148688
;       mov     eax, cr4               	;						; 148688
        db      00fh,020h,0e0h		;						; 148688
        mov     [RegSA.CR4sav],eax							; 148688
@@:											; 148688	

;       Must have a operand override to save all 32 bits

        db      OPER_OVERRIDE
        sgdt    [RegSA.GDTsav]                  ; save gdt register
        db      OPER_OVERRIDE
        sidt    [RegSA.IDTsav]                  ; save idt register
        Pcall   SaveCommonState
EndProc
.286p

;***    SaveCommonState - save state common between 286 and 386
;
;       Saves machine's state in save area.
;
;       ENTRY:  DS = debugger's data segment.
;
;       EXIT:   All the registers saved except DS, SS, SP, IP, CS & Flags.
;
;       USES:   ES, FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;                The client's flags must have been already saved in RegSA.Fsav.
;
        assumeDATA ds
        ASSUME  ES:NOTHING, SS:NOTHING

DefProc SaveCommonState, NEAR, LOCAL
        Pcall   IsDebProtMode
        jnc     short scsx                      ; jump if real mode

;       Save the address of the GDT and IDT when in protected mode
;       for the memory fetch/setroutines. In real mode the last GDT
;       or IDT address used in protected mode is the one used.

        push    ds
        pop     es                              ; (ES) = debugger data segment

        cld
        mov     si,dataOFFSET RegSA.GDTsav
        mov     di,dataOFFSET DebData.GDTaddr
        movsw
        movsw
        movsw                                   ; copy GDTsav to  GDTaddr

        mov     si,dataOFFSET RegSA.IDTsav
        mov     di,dataOFFSET DebData.ProtIDTaddr
        movsw
        movsw
        movsw                                   ; copy IDTsav to ProtIDTaddr

        sldt    [RegSA.LDTsav]                  ; save ldt selector
        str     [RegSA.TRsav]                   ; save tss register
scsx:
EndProc

;***    RestState286
;
;       Restores the state of the 286 machine from save area.
;
;       ENTRY:  NONE
;
;       EXIT:   All registers restored except DS, SS, SP, CS, IP & Flags.
;
;       USES:   FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;
        assumeDATA <ds, es, ss>

DefProc RestState286, NEAR, LOCAL
        Pcall   ExitMem                         ; cleanup memory routines
        lgdt    [RegSA.GDTsav]                  ; restore GDT and IDT
        lidt    [RegSA.IDTsav]                  ;
        Pcall   RestoreCommonState
        mov     es,[RegSA.ESsav]
        mov     ax,[RegSA.AXsav]
        mov     bx,[RegSA.BXsav]
        mov     cx,[RegSA.CXsav]
        mov     dx,[RegSA.DXsav]
        mov     bp,[RegSA.BPsav]
        mov     si,[RegSA.SIsav]
        mov     di,[RegSA.DIsav]
        lmsw    [RegSA.MSWsav]                  ; restore MSW
EndProc

;***    RestState386
;
;       Restores the state of the 386 machine from save area.
;
;       ENTRY:  NONE
;
;       EXIT:   All registers restored except DS, SS, SP, CS, IP & Flags.
;
;       USES:   FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;
        assumeDATA <ds, es, ss>
.386p
DefProc RestState386, NEAR, LOCAL
        Pcall   ExitMem                         ; cleanup memory routines
        db      OPER_OVERRIDE                   ; restore GDT and IDT
        lgdt    [RegSA.GDTsav]
        db      OPER_OVERRIDE                   ; assumes 16 bit segment
        lidt    [RegSA.IDTsav]
        Pcall   RestoreCommonState
        mov     ebx,[RegSA.EBXsav]
        mov     ecx,[RegSA.ECXsav]
        mov     edx,[RegSA.EDXsav]
        mov     ebp,[RegSA.EBPsav]
        mov     esi,[RegSA.ESIsav]
        mov     edi,[RegSA.EDIsav]
        Pcall   WhatIsClientMode
        ja      short rst10                     ; V86, don't restore segs
        mov     es,[RegSA.ESsav]
        mov     fs,[RegSA.FSsav]
        mov     gs,[RegSA.GSsav]

rst10:  mov     eax,[RegSA.CR2sav]
        mov     cr2,eax
        mov     eax,[RegSA.CR3sav]
        mov     cr3,eax

	push	ds									; 148688
	DosContext <ds>,ax              ;						; 148688
        cmp     [_CpuType],CPU_PENTIUM  ; check for Pentium				; 148688
	pop	ds									; 148688
        assumeDATA ds
        jne     @F									; 148688
        mov     eax,[RegSA.CR4sav]							; 148688
;       mov     cr4,eax                 ;						; 148688
        db      00fh,022h,0e0h		;						; 148688
@@:											; 148688	

        mov     eax,[RegSA.DR0sav]
        mov     dr0,eax
        mov     eax,[RegSA.DR1sav]
        mov     dr1,eax
        mov     eax,[RegSA.DR2sav]
        mov     dr2,eax
        mov     eax,[RegSA.DR3sav]
        mov     dr3,eax
        mov     eax,[RegSA.DR6sav]
        mov     dr6,eax
        mov     eax,[RegSA.DR7sav]
        mov     dr7,eax

;; The resetting of TR6 and TR7 is disabled for the present since
;; resetting them incorrectly (ie. TR6 R/W bit set to read) will
;; cause the processor to go into an inconsistent state and prevent
;; return to DOS from the debugger.  At some time in the future these
;; registers may be allowed to change by installing code to change
;; them immediately upon reciept of the rtr7/rtr6 commands or by using
;; conditional code to allow new values to be set into them on exit only
;; when the TR6 R/W bit is set.  In any case, they should never be
;; restored the way the following disabled code does it.  GLT
;;
;;      mov     eax,[RegSA.TR6sav]
;;      mov     tr6,eax
;;      mov     eax,[RegSA.TR7sav]
;;      mov     tr7,eax

        mov     eax,[RegSA.CR0sav]              ; must be (almost) last!!
        mov     cr0,eax
        mov     eax,[RegSA.EAXsav]
EndProc
.286p

;***    RestoreCommonState - common state between a 286 and 386
;
;       Restores the TR register.
;
;       ENTRY:  NONE
;
;       EXIT:   TR load with user value
;
;       USES:   FLAGS
;
;       WARNING: Can be called in either mode. Interrupts must be disabled.
;
        assumeDATA <ds, es, ss>

DefProc RestoreCommonState, NEAR, LOCAL
        Pcall   IsDebProtMode                   ; carry set if protected mode
        jnc     short rcsx
        lldt    [RegSA.LDTsav]                  ; load ldt selector

;       To load the task register the TSS descriptor must have
;       it's busy bit clear before it's loaded. This code saves
;       the access byte of the TSS's descriptor, clears the busy
;       bit in the descriptor GDT entry, loads the task register
;       with the descriptor and restores the access byte.

        mov     es,[DebData.GDTalias]           ; (ES) = pointer to GDT
    ASSUME   ES:NOTHING
        mov     bx,[RegSA.TRsav]
        and     bl,SEL_LOW_MASK
        mov     al,es:[bx].DescAccess
        and     es:[bx].DescAccess,not D_TSS_BUSY_BIT
        ltr     [RegSA.TRsav]                   ; load ltr selector
        mov     es:[bx].DescAccess,al
        DataContext <es>,ax
rcsx:
EndProc

;***    GetInstPrefix - skip instruction prefixes
;
;       ENTRY:  NONE
;
;       EXIT:   if carry clear,
;                    (AL) = opcode at CS:IP + DX
;                    (BX) = CS:IP AddrS pointer
;                    (DX) = number of prefixes (0 if none)
;                    (CX) = number of repe/repne prefixes (0 if none)
;               if carry set,
;                    (AX) = error code
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc GetInstPrefix, NEAR, LOCAL
        mov     bx,dataOFFSET RegSA.CSIPsav
        xor     dx,dx
        xor     cx,cx

;       (BX) = CSIP AddrS pointer
;       (DX) = number of prefixes
;       (CX) = repe/repne flag (!0 = repe/repne prefix)

gip1:   Pcall   GetByteOff, <dx, 0>     ; (AL) = byte at cs:ip + dx
        jc      short gipx
        cmp     al,2eh                  ; CS: override
        je      short gip2              ; Brif so
        cmp     al,3eh                  ; DS: override?
        je      short gip2              ;  yes, branch
        cmp     al,26h                  ; ES: override
        je      short gip2              ; Brif so
        cmp     al,64h                  ; FS: override?
        je      short gip2              ;  yes, branch
        cmp     al,65h                  ; GS: override?
        je      short gip2              ;  yes, branch
        cmp     al,36h                  ; SS: override?
        je      short gip2              ;  yes, branch
        cmp     al,66h                  ; Operand size override?
        je      short gip2              ;  yes, branch
        cmp     al,67h                  ; Address size override?
        je      short gip2              ;  yes, branch
        mov     ah,al
        and     ah,11111110b            ; check for rep
        cmp     ah,11110010b
        jne     short gip3              ; not repe/repne
        inc     cx                      ; repe/repne found
gip2:   inc     dx                      ; override found
        jmp     short gip1              ; loop back to get next byte

gip3:   clc
gipx:
EndProc

;***    CheckAllIdt - check all idt entries
;
;       Checks all IDT entries changed by the debugger.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc CheckAllIdt, NEAR, LOCAL
        push    si
        xor     si,si
cai1:   Pcall   CheckIdtEntry, <si>
        inc     si
        cmp     si,NUMBER_TRAPS
        jne     short cai1
        pop     si
EndProc

;***    CheckIdtEntry - check if idt entry changed
;
;       This function checks if the protected mode or real mode
;       IDT entries the debugger is intercepting have changed.  If
;       an entry has, the vector is reset.
;
;       This function also grabs the IDT entry even though the vector
;       isn't set by the vector command.  This is used on the way
;       into the debugger and the IDT is restored to the V command
;       state on the way out.
;
;       Pcall   CheckIdtEntry, <Intnum>
;
;       ENTRY:  (Intnum) = interrupt number to set.
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, FLAGS
;
        assumeDATA <ds, es, ss>

DefProc CheckIdtEntry, NEAR, LOCAL

ArgVar  Intnum, WORD
LocVar  IDTaddr, <size AddrS>
LocVar  IDTdata, <size Desc>

BeginProc
        SaveReg <si, di>
        Pcall   GetTrapTblEntry, <Intnum>       ; (BX) = trap table index
        and     [bx].TrapTblFlag,not TRAP_FATAL_DISABLE
        Pcall   IsDebProtMode                   ; only do check in prot mode
        jnc     short cie40                     ; jump if real mode

;       (BX) = trap table index

        test    [bx].TrapTblFlag,(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jz      short cie30                     ; jump if not set

        push    bx
        lea     di,IDTdata                      ; (DI) = buffer to put IDT entry
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetPMIDTaddr
        mov     ax,Intnum
        mov     cx,size Desc
        mul     cx                              ; (DX:AX) = offset into IDT

;       (DX:AX) = offset into IDT
;       (BX) = pointer to AddrS structure for IDT entry
;       (DI) = pointer to put IDT entry
;       (CX) = size of descriptor

        Pcall   GetBuffOff, <ax, dx>
        pop     bx                              ; (BX) = ptr to idt tbl entry
        jc      short ciex

        mov     ax,DebData.CSsel
        mov     dx,[bx].TrapTblEntry            ; (DX) = 16 bit trap routine
        test    [bx].TrapTblFlag,TRAP_32_USED
        jz      short cie10
        mov     dx,[bx].TrapTblEntry32          ; (DX) = 32 bit trap routine
        cmp     IDTdata.GateExtOffset,0         ; is the highword of gate 0?
        jne     short cie20                     ;  no, grab the vector

cie10:  cmp     IDTdata.GateOffset,dx
        jne     short cie20
        cmp     IDTdata.GateSelector,ax
        je      short cie30                     ; jump if IDT entry ok

cie20:  Pcall   SetIdtEntry, <TRAP_PM_FORCE, Intnum>
cie30:  Pcall   SetIdtEntry, <TRAP_PM_TEMP, Intnum>
        jmp     short ciex

;       (BX) = pointer to trap table entry

cie40:  cmp     [Intnum],NUMBER_RM_TRAPS
        jae     short ciex

        test    [bx].TrapTblFlag,(TRAP_RM_USED + TRAP_RM_TEMP)
        jz      short cie60                     ; jump if not set

        push    bx
        lea     di,IDTdata                      ; (DI) = buffer to put entry
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetRMIDTaddr
        mov     ax,Intnum
        mov     cx,4
        mul     cx                              ; (DX:AX) = offset into IDT

;       (DX:AX) = offset into interrupt vector table
;       (BX) = pointer to AddrS structure for IDT entry
;       (DI) = pointer to put IDT entry
;       (CX) = size of real mode vector entry

        Pcall   GetBuffOff, <ax, dx>
        pop     bx                              ; (BX) = ptr to idt tbl entry
        jc      short ciex

        mov     ax,DebData.CSseg                ; (AX) = debugger code segment
        mov     dx,[bx].TrapTblEntry            ; (DX) = trap routine address

        cmp     IDTdata.Segmt16,ax
        jne     short cie50                     ; jump if the vector changed
        cmp     IDTdata.Offst16,dx
        je      short cie60                     ; jump if the vector same

cie50:  Pcall   SetIdtEntry, <TRAP_RM_FORCE, Intnum>
cie60:  Pcall   SetIdtEntry, <TRAP_RM_TEMP, Intnum>
ciex:   RestReg <di, si>
EndProc

;***    ExitAllIdt - restore all idt entries on debugger exit
;
;       Restores all IDT entries changed by the debugger on
;       the way in by CheckAllIdt.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc ExitAllIdt, NEAR, LOCAL
        push    si
        xor     si,si
eai10:  Pcall   RestIdtEntry, <TRAP_PM_TEMP + TRAP_RM_TEMP, si>
        inc     si
        cmp     si,NUMBER_TRAPS
        jne     short eai10
        pop     si
EndProc

;***    SetIdtEntry - set idt entry
;
;       Pcall   SetIdtEntry, <Flag, Intnum>
;
;       ENTRY:  (Flag) = TRAP_PM_USED  sets ring 3/2 prot mode traps
;                        TRAP_PM_HARD  sets all ring prot mode traps
;                        TRAP_V86_USED sets v86 mode traps
;                        TRAP_RM_USED  sets real mode traps
;                        TRAP_FATAL    sets process fatal traps
;                        TRAP_PM_TEMP  sets temporary prot mode traps
;                        TRAP_RM_TEMP  sets temporary real mode traps
;                        TRAP_PM_FORCE forces the prot mode IDT entry updated
;                        TRAP_RM_FORCE forces the real mode IDT entry updated
;               (Intnum) = interrupt number to set.
;
;       EXIT:   If carry clear, vector set ok.
;               If carry set, (AX) = error code.
;
;       USES:   AX, BX, CX, DX, FLAGS, other regs preserved
;
        assumeDATA <ds, es, ss>

DefProc SetIdtEntry, NEAR, PUBLIC

ArgVar  Flag,   WORD
ArgVar  Intnum, WORD
LocVar  IDTaddr, <size AddrS>
LocVar  IDTdata, <size Desc>

BeginProc
        SaveReg <si, di>
        Pcall   GetTrapTblEntry, <Intnum>       ; (BX) = trap table index

;       (BX) = trap table index

        test    [Flag],TRAP_PM_FORCE
        jnz     short sie10

        test    [Flag],(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jz      short sie40                     ; jump if not protected mode

        test    [bx].TrapTblFlag,(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jnz     short sie40                     ; if already set

sie10:  push    bx
        lea     di,[bx].TrapTblPMsave
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetPMIDTaddr
        mov     ax,Intnum
        mov     cx,size Desc
        mul     cx                              ; (DX:AX) = offset into IDT
        Pcall   AddAddr, <ax, dx>

;       (BX) = pointer to AddrS structure for IDT entry
;       (DI) = pointer to put/get IDT entry
;       (CX) = size of descriptor

        Pcall   GetBuff
        pop     bx                              ; (BX) = ptr to idt tbl entry
        jnc     short sie20
        jmp     siex

sie20:  lea     si,IDTdata                      ; (SI) = new gate buffer
        mov     al,[bx].TrapTblPMsave.GateAccess; (AL) = original access byte
        mov     ah,al                           ; (AH) = saved access byte
        mov     dx,[bx].TrapTblEntry            ; (DX) = 16 bit trap routine
        and     al,D_PRIV
        or      al,D_INT0                       ; default is 16 bit int gate
        mov     [si].GateAccess,al

;       BUGBUG - mikem 12/21/87 - doesn't handle task gates (for trap 8's).

        mov     al,ah                           ; (AL) = saved access byte
        and     al,(D_TYPEMASK and not D_32)    ; maskoff everything but type
        cmp     al,D_INTGATE
        je      sie25                           ; can handle INT gates
        cmp     al,D_TRAPGATE
        je      sie25                           ; and TRAP gates
        stc
        jmp     siex

sie25:  and     [bx].TrapTblFlag,not TRAP_32_USED
        test    ah,D_32                         ; test saved access byte
        jz      short sie30

        or      [bx].TrapTblFlag,TRAP_32_USED   ; indicate 32 bit gate
        or      [si].GateAccess,D_32            ; make gate 32 bits
        mov     dx,[bx].TrapTblEntry32          ; (DX) = 32 bit trap routine

sie30:  mov     [si].GateOffset,dx
        mov     ax,DebData.CSsel
        mov     [si].GateSelector,ax
        mov     [si].GateWordCount,0
        mov     [si].GateExtOffset,0

;       (SI) = pointer to put/get IDT entry
;       (CX) = size of descriptor

        push    bx
        lea     bx,IDTaddr
        Pcall   PutBuff
        pop     bx
        jc      short siex

sie40:  test    [Flag],TRAP_RM_FORCE
        jnz     short sie45

        test    [Flag],(TRAP_RM_USED + TRAP_RM_TEMP)
        jz      short sie50                     ; jump if not protected mode

        test    [bx].TrapTblFlag,(TRAP_RM_USED + TRAP_RM_TEMP)
        jnz     short sie50

sie45:  push    bx
        lea     di,[bx].TrapTblRMsave           ; (SI) = place to put desc
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetRMIDTaddr
        mov     ax,Intnum
        mov     cx,4
        mul     cx                              ; (DX:AX) = offset into IDT
        Pcall   AddAddr, <ax, dx>

;       (BX) = pointer to AddrS structure for IDT entry
;       (DI) = pointer to put IDT entry
;       (CX) = size of real mode vector entry

        Pcall   GetBuff
        pop     bx                              ; (BX) = ptr to idt tbl entry
        jc      short siex

        lea     si,IDTdata
        mov     ax,DebData.CSseg
        mov     dx,[bx].TrapTblEntry            ; (DX) = trap routine address
        mov     [si].Segmt16,ax
        mov     [si].Offst16,dx

        push    bx
        lea     bx,IDTaddr
        Pcall   PutBuff
        pop     bx
        jc      short siex

sie50:  mov     ax,[Flag]
        and     ax,not (TRAP_PM_FORCE + TRAP_RM_FORCE)
        or      [bx].TrapTblFlag,ax
        clc
siex:   RestReg <di, si>
EndProc

;***    RestAllIdt - restore all idt entries
;
;       Restores all IDT entries changed by the debugger.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc RestAllIdt, NEAR, PUBLIC
        push    si
        xor     si,si
rai10:  Pcall   RestIdtEntry, <(TRAP_PM_USED + TRAP_PM_HARD + TRAP_V86_USED + \
                                TRAP_RM_USED + TRAP_BEEP), si>
        inc     si
        cmp     si,NUMBER_TRAPS
        jne     short rai10
        pop     si
EndProc

;***    RestIdtEntry - restore idt entry
;
;       Pcall   RestIdtEntry, <Flag, Intnum>
;
;       ENTRY:  (Flag) = TRAP_PM_USED  clears ring 3/2 prot mode trap
;                        TRAP_PM_HARD  clears all ring prot mode trap
;                        TRAP_V86_USED clears v86 mode trap
;                        TRAP_RM_USED  clears real mode trap
;                        TRAP_FATAL    clears process fatal trap
;                        TRAP_PM_TEMP  clears temporary prot mode trap
;                        TRAP_RM_TEMP  clears temporary real mode trap
;                        TRAP_PM_FORCE forces the prot mode IDT entry updated
;                        TRAP_RM_FORCE forces the real mode IDT entry updated
;               (Intnum) = interrupt number to restore.
;
;       EXIT:   If carry clear, no error
;               If carry set, (AX) = error code
;
;       USES:   AX, BX, CX, DX, FLAGS, other regs preserved
;
        assumeDATA <ds, es, ss>

DefProc RestIdtEntry, NEAR, PUBLIC

ArgVar  Flag,   WORD
ArgVar  Intnum, WORD
LocVar  IDTaddr, <size AddrS>

BeginProc
        SaveReg <si, di>
        Pcall   GetTrapTblEntry, <Intnum>       ; (BX) = trap table index

        test    [Flag],TRAP_PM_FORCE
        jnz     short rie10

        test    [Flag],(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jz      short rie20

        test    [bx].TrapTblFlag,(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jz      short rie20                     ; jump if not set

        mov     ax,[Flag]                       ; (AX) = flags
        not     ax
        and     ax,[bx].TrapTblFlag             ; (AX) = new flags
        test    ax,(TRAP_PM_USED + TRAP_V86_USED + TRAP_PM_TEMP)
        jnz     short rie20                     ; jump if one still set

rie10:  push    bx
        lea     si,[bx].TrapTblPMsave           ; restore protect mode IDT gate
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetPMIDTaddr
        mov     ax,Intnum
        mov     cx,size Desc
        mul     cx                              ; (DX:AX) = offset into IDT

;       (DX:AX) = offset into IDT
;       (BX) = pointer to AddrS structure for IDT entry
;       (SI) = pointer to get IDT entry
;       (CX) = size of descriptor

        Pcall   PutBuffOff, <ax, dx>
        pop     bx                              ; (BX) = trap table pointer
        jc      short riex

;       Clear trap used flags and always clear TRAP_PM_HARD

rie20:  test    [Flag],TRAP_RM_FORCE
        jnz     short rie30

        test    [Flag],(TRAP_RM_USED + TRAP_RM_TEMP)
        jz      short rie40

        test    [bx].TrapTblFlag,(TRAP_RM_USED + TRAP_RM_TEMP)
        jz      short rie40

        mov     ax,[Flag]                       ; (AX) = flags
        not     ax
        and     ax,[bx].TrapTblFlag             ; (AX) = new flags
        test    ax,(TRAP_RM_USED + TRAP_RM_TEMP)
        jnz     short rie40                     ; jump if one still set

rie30:  lea     si,[bx].TrapTblRMsave           ; restore protect mode IDT gate
        push    bx
        lea     bx,IDTaddr                      ; (BX) = ptr to AddrS struc
        Pcall   GetRMIDTaddr
        mov     ax,Intnum
        mov     cx,4
        mul     cx                              ; (DX:AX) = offset into IDT

;       (DX:AX) = offset into interrupt vector table
;       (BX) = pointer to AddrS structure for IDT entry
;       (SI) = pointer to get IDT entry
;       (CX) = real mode vector entry

        Pcall   PutBuffOff, <ax, dx>
        pop     bx                              ; (BX) = trap table pointer
        jc      short riex

rie40:  mov     ax,[Flag]
        not     ax
        and     [bx].TrapTblFlag,ax
        clc
riex:   RestReg <di, si>
EndProc

;***    CheckBeep - check if should beep
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, CX, DX, Flags
;
        assumeDATA <ds, es, ss>

DefProc CheckBeep, NEAR, LOCAL
        Pcall   GetTrapTblEntry, <[TrapNumber]>
        test    [bx].TrapTblFlag,TRAP_BEEP
        jz      short ckbx

ckb10:  mov     bx,500                  ; BX = 500 HZ
        mov     cx,500                  ; CX = duration
        Pcall   DebCallOut, <DEB_CALLOUT_BEEP>
        jnc     short ckb10
ckbx:
EndProc

;***    GetTrapTblEntry
;
;       Pcall   GetTrapTblEntry, <Intnum>
;
;       Gets the address of the idt table entry.
;
;       ENTRY:  (Intnum) = interrupt number of entry.
;
;       EXIT:   BX = address of table entry.
;
;       USES:   BX, FLAGS, other regs preserved
;
        assumeDATA ds
        ASSUME  ES:NOTHING, SS:NOTHING

DefProc GetTrapTblEntry, NEAR, PUBLIC

ArgVar  Intnum, BYTE

BeginProc
        mov     bl,Intnum                       ; get index into trap table
        xor     bh,bh
        imul    bx,size TrapTblS
        add     bx,dataOFFSET TrapTbl
EndProc

;***    CheckCtrlC - checks for ctrl-c pending at the console
;
;       Check for ctrlc because there might be a default command
;       string that never stops or lets the normal ctrlc in.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX (if packet-break), Flags
;
        assumeDATA <ds, es, ss>

DefProc CheckCtrlC, NEAR, PUBLIC
        push    ax
        Pcall   inchr                   ; check for ctrlc
        jz      ccc2
        cmp     al,CTRLC                ; is it a ctrlc?
        jne     ccc1
        mov     fTraceCount,0
        mov     fTraceSpecial,0
        mov     fRegDisp,1              ;  ... and enable register display
        mov     fDoGoSpecial,0
        pop     ax
        Jump    RCmdBreak               ; break and do "R" command

ccc1:
        IFDEF   KDP
        cmp     al,KDP_BREAK            ; is it a Packet Break?
        jne     ccc1a
        cmp     fKDPEnabled,0
        je      ccc1a
        pop     ax
        mov     al,KDP_ASYNC_TRAP
        Jump    KDPEvent                ; break and send packet
ccc1a:
        ENDIF

        Pcall   ungetc                  ; put character back if not ctrlc
ccc2:   pop     ax
EndProc

CodeSegmentEnd

        end
