;       SCCSID = @(#)xcptmisc.asm       6.6 92/03/07
SCCSID      equ     "@(#)xcptmisc.asm   6.6 92/03/07"
;***    XCPTMISC.ASM
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;       Title:  Miscellaneous exception management routines.
;
;
;       Description: This file contains exception management routines
;                    that cannot be written in C.
;
;       Modification History:
;
;       72837  Changeteam   Format segment table entries correctly

;**************************** Revision History ********************************
;date:          person:         defect:         description:
;10/14/93       Gary Dommer     74165   Nested xcpt not unwound to orig. pgm
;
INCL_DOSERRORS  equ     1               ; For BSEERR.INC

include fnotask.inc
include basemaca.inc
include osmaca.inc
include mi.inc
include dosseg.inc
include dossymc.inc
include basemid.inc
include bseerr.inc
include bsexcpt.inc
include seldesc.inc
include tkexport.inc
include exmg.inc
include bsedosp.inc
include pgexport.inc
include vmexport.inc
include ldrvars.inc

CpuMode 386
ModName XCPTMISC, FNO_XCPTMISC_ASM


        EXTRN16 DelayHardErr
        EXTRN32 FormatRegDump
        EXTRN32 FormatLimAccDump
        EXTRN32 _TKFuBuff
        EXTRN32 SwitchNPX
        EXTRN32 WaitNPX
        EXTRN32 _VMGetOd
        EXTRN32 _ldrValidateMteHandle
        EXTRN32 HexToAscii32

        ReferFlat _pTCBCur, DWORD
        ReferFlat _pPTDACur,DWORD
        ReferGlobal mathCop, BYTE

DATA segment

XCPTFullMsg             label   byte

;*   Exception Information Dump Message

XCPTParamsMsg           label   byte
                db      'P1='
P1val           db      'XXXXXXXX  '

                db      'P2='
P2val           db      'XXXXXXXX  '

                db      'P3='
P3val           db      'XXXXXXXX  '

                db      'P4='
P4val           db      'XXXXXXXX  '
                db      c_CR, c_LF
XCPTParamsMsgLen        equ     $ - XCPTParamsMsg

;*   Control Register Dump Message

XCPTControlRegMsg       label   byte
                db      'CS:EIP='
CSval           db      'XXXX:'

EIPval          db      'XXXXXXXX  '
                db      'CSACC='
CSacc           db      'XXXX  '

                db      'CSLIM='
CSlimit         db      'XXXXXXXX'
                db      c_CR, c_LF

                db      'SS:ESP='
SSval           db      'XXXX:'
ESPval          db      'XXXXXXXX  '

                db      'SSACC='
SSacc           db      'XXXX  '

                db      'SSLIM='
SSlimit         db      'XXXXXXXX'
                db      c_CR, c_LF

                db      'EBP='
EBPval          db      'XXXXXXXX  '

                db      'FLG='
EFLAGval        db      'XXXXXXXX'
                db      c_CR, c_LF

XCPTControlRegMsgLen    equ     $ - XCPTControlRegMsg

;*   Integer Register Dump Message

XCPTIntegerRegMsg       label   byte
                db      'EAX='
EAXval          db      'XXXXXXXX  '

                db      'EBX='
EBXval          db      'XXXXXXXX  '

                db      'ECX='
ECXval          db      'XXXXXXXX  '

                db      'EDX='
EDXval          db      'XXXXXXXX'
                db      c_CR, c_LF

                db      'ESI='
ESIval          db      'XXXXXXXX  '

                db      'EDI='
EDIval          db      'XXXXXXXX  '
                db      c_CR, c_LF

XCPTIntegerRegMsgLen    equ     $ - XCPTIntegerRegMsg

;*   Segment Register Dump Message

XCPTSegmentRegMsg       label   byte
                db      'DS='
DSval           db      'XXXX  '

                db      'DSACC='
DSacc           db      'XXXX  '

                db      'DSLIM='
DSlimit         db      'XXXXXXXX  '
                db      c_CR, c_LF

                db      'ES='
ESval           db      'XXXX  '

                db      'ESACC='
ESacc           db      'XXXX  '

                db      'ESLIM='
ESlimit         db      'XXXXXXXX  '
                db      c_CR, c_LF

                db      'FS='
FSval           db      'XXXX  '

                db      'FSACC='
FSacc           db      'XXXX  '

                db      'FSLIM='
FSlimit         db      'XXXXXXXX'
                db      c_CR, c_LF

                db      'GS='
GSval           db      'XXXX  '

                db      'GSACC='
GSacc           db      'XXXX  '

                db      'GSLIM='
GSlimit         db      'XXXXXXXX'
                db      c_CR, c_LF

XCPTSegmentRegMsgLen    equ     $ - XCPTSegmentRegMsg

;
; BUGBUG: Gotta add this one some time...
;
; ;*   Floating Point Register Dump Message
;
; XCPTFPRegMsg    label   byte
;                 db      c_CR, c_LF
; XCPTFPRegMsgLen equ     $ - XCPTFPRegMsg

                db      0                       ; End of 3rd message insert

;*   Module Containing Faulting CS:EIP Message

XCPTFileNameMsg label   byte
                db      40 dup (?)
XCPTFileNameMsgLen      equ     $ - XCPTFileNameMsg

XCPTObjOffMsg   label   byte
                db      ' XXXX:XXXXXXXX'
XCPTObjOffMsgLen        equ     $ - XCPTObjOffMsg

XCPTCRLFMsg     label   byte
                db      c_CR, c_LF
XCPTCRLFMsgLen  equ     $ - XCPTCRLFMsg

                db      0                       ; End of 4th message insert

XCPTFullMsgLen  equ     $ - XCPTFullMsg

XCPTExFmt       label   dword
                dd      ExceptionNum, offset FLAT:EXCval, 4
                dd      ExceptionAddress, offset FLAT:ADDRval, 4
XCPTExFmtLen    equ     ($-XCPTExFmt)/12

XCPTExEiFmt     label   dword
                dd      ExceptionInfo + 0, offset FLAT:P1val, 4
                dd      ExceptionInfo + 4, offset FLAT:P2val, 4
                dd      ExceptionInfo + 8, offset FLAT:P3val, 4
                dd      ExceptionInfo + 12, offset FLAT:P4val, 4

XCPTIntFmt      label   dword
                dd      ctx_RegEax, offset FLAT:EAXval, 4
                dd      ctx_RegEbx, offset FLAT:EBXval, 4
                dd      ctx_RegEcx, offset FLAT:ECXval, 4
                dd      ctx_RegEdx, offset FLAT:EDXval, 4
                dd      ctx_RegEsi, offset FLAT:ESIval, 4
                dd      ctx_RegEdi, offset FLAT:EDIval, 4
XCPTIntFmtLen   equ     ($-XCPTIntFmt)/12


XCPTSegmentFmt  label   dword
                dd      ctx_SegDs, offset FLAT:DSval, 2
                dd      ctx_SegEs, offset FLAT:ESval, 2
                dd      ctx_SegFs, offset FLAT:FSval, 2
                dd      ctx_SegGs, offset FLAT:GSval, 2
XCPTSegmentFmtLen       equ ($ - XCPTSegmentFmt)/12

XCPTControlFmt  label   dword
                dd      ctx_SegCs, offset FLAT:CSval, 2
                dd      ctx_RegEip, offset FLAT:EIPval, 4
                dd      ctx_SegSs, offset FLAT:SSval, 2
                dd      ctx_RegEsp, offset FLAT:ESPval, 4
                dd      ctx_RegEbp, offset FLAT:EBPval, 4
                dd      ctx_EFlags, offset FLAT:EFLAGval, 4
XCPTControlFmtLen       equ ($ - XCPTControlFmt)/12

XCPTSegLimAccFmt label  dword
                dd      ctx_SegDs, offset FLAT:DSacc, offset FLAT:DSlimit
                dd      ctx_SegEs, offset FLAT:ESacc, offset FLAT:ESlimit
                dd      ctx_SegFs, offset FLAT:FSacc, offset FLAT:FSlimit
                dd      ctx_SegGs, offset FLAT:GSacc, offset FLAT:GSlimit
XCPTSegLimAccFmtLen     equ     ($-XCPTSegLimAccFmt)/12

XCPTControlLimAccFmt label      dword
                dd      ctx_SegCs, offset FLAT:CSacc, offset FLAT:CSlimit
                dd      ctx_SegSs, offset FLAT:SSacc, offset FLAT:SSlimit
XCPTControlLimAccFmtLen equ     ($-XCPTControlLimAccFmt)/12

XCPTNumToMsg label dword
dd 0,                             MSG_XCPT_USER         ; Default
dd XCPT_BREAKPOINT,               MSG_XCPT_BREAKPOINT
dd XCPT_SINGLE_STEP,              MSG_XCPT_SINGLE_STEP
dd XCPT_ACCESS_VIOLATION,         MSG_XCPT_ACCESS_VIOLATION
dd XCPT_ILLEGAL_INSTRUCTION,      MSG_XCPT_ILLEGAL_INSTRUCTION
dd XCPT_FLOAT_DENORMAL_OPERAND,   MSG_XCPT_FLOAT_DENORMAL_OPERAND
dd XCPT_FLOAT_DIVIDE_BY_ZERO,     MSG_XCPT_FLOAT_DIVIDE_BY_ZERO
dd XCPT_FLOAT_INEXACT_RESULT,     MSG_XCPT_FLOAT_INEXACT_RESULT
dd XCPT_FLOAT_INVALID_OPERATION,  MSG_XCPT_FLOAT_INVALID_OPERATION
dd XCPT_FLOAT_OVERFLOW,           MSG_XCPT_FLOAT_OVERFLOW
dd XCPT_FLOAT_STACK_CHECK,        MSG_XCPT_FLOAT_STACK_CHECK
dd XCPT_FLOAT_UNDERFLOW,          MSG_XCPT_FLOAT_UNDERFLOW
dd XCPT_INTEGER_DIVIDE_BY_ZERO,   MSG_XCPT_INTEGER_DIVIDE_BY_ZERO
dd XCPT_INTEGER_OVERFLOW,         MSG_XCPT_INTEGER_OVERFLOW
dd XCPT_PRIVILEGED_INSTRUCTION,   MSG_XCPT_PRIVILEGED_INSTRUCTION
dd XCPT_IN_PAGE_ERROR,            MSG_XCPT_IN_PAGE_ERROR
dd XCPT_NONCONTINUABLE_EXCEPTION, MSG_XCPT_NONCONTINUABLE_EXCEPTION
dd XCPT_INVALID_DISPOSITION,      MSG_XCPT_INVALID_DISPOSITION
dd XCPT_INVALID_LOCK_SEQUENCE,    MSG_XCPT_INVALID_LOCK_SEQUENCE
dd XCPT_ARRAY_BOUNDS_EXCEEDED,    MSG_XCPT_ARRAY_BOUNDS_EXCEEDED
dd XCPT_B1NPX_ERRATA_02,          MSG_XCPT_B1NPX_ERRATA_02
XCPTNumToMsgCount equ ($ - 8 - XCPTNumToMsg) / 8

;*   Exception Report Record Message

XCPTReportRecordMsg     label   byte
EXCval          db      'XXXXXXXX'
                db      0                       ; End of 1st message insert

ADDRval         db      'XXXXXXXX'
                db      0                       ; End of 2nd message insert
XCPTReportRecordMsgLen  equ     $ - XCPTReportRecordMsg

public  XCPTXferBuffer
XCPTXferBuffer  label   byte
        db      XCPTFullMsgLen dup (?)

DATA ends

          FARCODE HIGH32
EXMGSWAP_TEXT SEGMENT

;***LP  _xcptFormatAndSendHardErr - Exception HardErr dispatcher
;*
;*      _xcptFormatAndSendHardErr formats a DelayHardErr message
;*      and calls DelayHardErr.
;*
;*      ENTRY   fas_ulTrapNumber        Trap Number
;*              fas_pERepRec            Exception Report Record
;*              fas_pContext            Context Record - May be NULL
;*

Procedure _xcptFormatAndSendHardErr

ArgVar  fas_ulTrapNumber, DWORD
ArgVar  fas_pERepRec, DWORD
ArgVar  fas_pContext, DWORD

LocalVar fas_edi, DWORD                 ; Buffer Offset
LocalVar fas_msg, DWORD                 ; Message number
LocalVar fas_smte, DWORD                ; Pointer to swappable MTE
LocalVar fas_R0ERepRec, <size EXCEPTIONREPORTRECORD>  ; For nested records
LocalVar fas_od, <size vmod_s>          ; Object description buffer
LocalVar fas_leip, DWORD                ; EIP linear address
LocalVar fas_mte_flags2, WORD           ; MTE's mte_flags2 field        ;72837

        xor     eax, eax                ; --> Calculate MSG Number
        jmp     short xfs10

Entry   _xcptStackOverRun
        mov     eax, MSG_XCPT_STACK_OVERRUN
        jmp     short xfs10

Entry   _xcptFatalDispatchError
        mov     eax, MSG_XCPT_CANNOT_DISPATCH

xfs10:  EnterProc
        SaveReg <esi,edi,ebx>           ; C calling convention

        mov     [fas_msg], eax
        or      eax, eax                ; If MSG already known, then the
        jz      short xfs11             ;  EH_STACK_INVALID flag should be set

        mov     ebx, [fas_pERepRec]
        or      [ebx].fHandlerFlags, EH_STACK_INVALID

xfs11:  mov     esi, _pTCBCur
        .errnz  (TMF_XCPT_HE - (1 SHL 6))
        bts     [esi].TCBMiscFlags, 6
        jc      xfs95

;
; Format the Exception message
;

        mov     ebx, [fas_pERepRec]

;
; Change made for defect # 74165 (by GWD) to check for Nested Pointer instead of
; Nexted flag. Cause poiner is set up before push to stack that generates
; fatal stack fault. The nested flag is updated after fault occures.
;

xfs12:  cmp     [ebx].NestedExceptionReportRecord, 0 ;Nested Pointer present?
        je      short xfs15                     ; No. Use current record

;
; If there is a nested exception report record, we want to use
; that one for the hard error popup.
;

        mov     eax, [ebx].NestedExceptionReportRecord
        SSToDS  esi, [fas_R0ERepRec]
        CCALL32 _TKFuBuff, <esi, eax, size EXCEPTIONREPORTRECORD, 0>
        or      eax, eax                        ; Error fetching record?
        jnz     short xfs15                     ; Yes. Use what we have
        mov     ebx, esi                        ; Use new exception report rec
        jmp     short xfs12                     ; Look for another.

xfs15:  mov     eax, [fas_msg]                  ; Have we already go a number?
        or      eax, eax
        jnz     short xfs30                     ; Yes. Don't look for one.

        mov     eax, [ebx].ExceptionNum
        mov     ecx, XCPTNumToMsgCount
        mov     esi, offset FLAT:XCPTNumToMsg
xfs20:  cmp     [esi + ecx * 8], eax            ; Exception number match?
        je      short xfs25
        loop    xfs20
xfs25:  mov     eax, [esi + ecx * 8] + 4
        mov     [fas_msg], eax

xfs30:  mov     [fas_pERepRec], ebx
        mov     ecx, XCPTExFmtLen
        mov     esi, offset FLAT:XCPTExFmt
        mov     [fas_edi], offset DOSGROUP:XCPTXferBuffer
        CCALL32 FormatRegDump

        mov     esi, offset FLAT:XCPTExEiFmt
        mov     ecx, EXCEPTION_MAXIMUM_PARAMETERS
        CCALL32 ClearRegDump            ; Clear old values

        mov     esi, offset FLAT:XCPTExEiFmt
        mov     ecx, [ebx].cParameters
        cmp     ecx, EXCEPTION_MAXIMUM_PARAMETERS
        jle     xfs35
        mov     ecx, EXCEPTION_MAXIMUM_PARAMETERS



xfs35:  cmp     ecx,0                   ; Are there *any* parameters?
        jle     short xfs40             ; No. Don't format.
        CCALL32 FormatRegDump
        DosContext <es>,di
        mov     ecx, XCPTParamsMsgLen
        mov     esi, offset FLAT:XCPTParamsMsg
        mov     edi, [fas_edi]
B1EMac  rep     movsb
        mov     [fas_edi],edi
        FlatContext <es>,di

xfs40:  mov     ebx, fas_pContext
        or      ebx, ebx                        ; Is there a context record?
        jz      xfs86                           ; No. Don't format it.

        mov     ecx, XCPTIntFmtLen
        mov     esi, offset FLAT:XCPTIntFmt

        test    [ebx].ContextFlags, CONTEXT_INTEGER
        jz      short xfs45
        CCALL32 FormatRegDump
        DosContext <es>,di
        mov     ecx, XCPTIntegerRegMsgLen
        mov     esi, offset FLAT:XCPTIntegerRegMsg
        mov     edi, [fas_edi]
B1EMac  rep     movsb
        mov     [fas_edi],edi
        FlatContext <es>,di
        jmp     short xfs50

xfs45:  CCALL32 ClearRegDump

xfs50:  mov     ecx, XCPTSegmentFmtLen
        mov     esi, offset FLAT:XCPTSegmentFmt
        test    [ebx].ContextFlags, CONTEXT_SEGMENTS
        jz      short xfs55
        CCALL32 FormatRegDump
        jmp     short xfs60

xfs55:  CCALL32 ClearRegDump

xfs60:  mov     ecx, XCPTSegLimAccFmtLen
        mov     esi, offset FLAT:XCPTSegLimAccFmt
        test    [ebx].ContextFlags, CONTEXT_SEGMENTS
        jz      short xfs65
        CCALL32 FormatLimAccDump
        DosContext <es>,di
        mov     ecx, XCPTSegmentRegMsgLen
        mov     esi, offset FLAT:XCPTSegmentRegMsg
        mov     edi, [fas_edi]
B1EMac  rep     movsb
        mov     [fas_edi],edi
        FlatContext <es>,di
        jmp     short xfs70

xfs65:  CCALL32 ClearLimAccDump

xfs70:  mov     ecx, XCPTControlFmtLen
        mov     esi, offset FLAT:XCPTControlFmt
        test    [ebx].ContextFlags, CONTEXT_CONTROL
        jz      short xfs75
        CCALL32 FormatRegDump
        jmp     short xfs80

xfs75:  CCALL32 ClearRegDump

xfs80:  mov     ecx, XCPTControlLimAccFmtLen
        mov     esi, offset FLAT:XCPTControlLimAccFmt
        test    [ebx].ContextFlags, CONTEXT_CONTROL
        jz      short xfs85
        CCALL32 FormatLimAccDump
        DosContext <es>,di
        mov     ecx, XCPTControlRegMsgLen
        mov     esi, offset FLAT:XCPTControlRegMsg
        mov     edi, [fas_edi]
B1EMac  rep     movsb
        mov     [fas_edi],edi
        FlatContext <es>,di
        jmp     short xfs86

xfs85:  CCALL32 ClearLimAccDump

; Get the fully qualified path name of the module (EXE or DLL) that owns
; the faulting CS:EIP and copy only the file name into the buffer, along
; with the number of the object containing the faulting CS:EIP and the
; offset within the object of the EIP

;       Terminate the message's third insert

xfs86:  DosContext <es>,di
        mov     edi, [fas_edi]                  ; (EDI) = current end of buffer
        xor     al, al
        stosb                                   ; End of 3rd insert
        mov     [fas_edi], edi                  ; Save new end of buffer
        FlatContext <es>,di

;       Get the description of the object containing the faulting EIP

        mov     esi, [fas_pERepRec]             ; (ESI) = -> xcpt report rec
        mov     eax, [esi].ExceptionAddress     ; (EAX) = EIP laddr
        mov     fas_od.od_laddr, eax            ; Stuff EIP laddr into od
        mov     eax, [_pPTDACur]                ; (EAX) = -> current PTDA
        mov     fas_od.od_pPTDA, eax            ; Stuff current PTDA into od
        SSToDS  eax, fas_od                     ; (EAX) = -> od
        CCALL32 _VMGetOd <0, eax>
        or      eax, eax                        ; Did call succeed?
        jnz     xfs91                           ; No, skip 4th insert

;       Get the MTE of the module containing the faulting EIP

        mov     esi, fas_od.od_pob              ; (ESI) = -> ob
        movzx   eax, [esi].ob_hobmte            ; (EAX) = hobmte
        or      eax, eax                        ; Is there a hobmte?
        jz      xfs91                           ; No, skip 4th insert
        CCALL32 _ldrValidateMteHandle <eax>
        or      eax,eax
        jz      xfs91                           ; bad hMTE - skip

;       Get the path name of the module containing the faulting EIP
;       from the swappable MTE

        mov     esi, eax                        ; (ESI) = -> mte
        mov     ax, [esi].mte_flags2            ; (EAX) = mte flags2    ;72837
        mov     [fas_mte_flags2], ax            ; Save mte flags2       ;72837
        mov     esi, [esi].mte_swapmte          ; (ESI) = -> swappable mte
        mov     [fas_smte], esi                 ; Save -> swappable mte
        movzx   eax, [esi].smte_pathlen         ; (EAX) = path name length
        or      eax, eax                        ; Does path name exist?
        jz      xfs91                           ; No, skip 4th insert
        mov     esi, [esi].smte_path            ; (ESI) = -> path name

;       Find the file name within the path name by starting at the end
;       of the path name and searching backwards for a separator or the
;       beginning of the path name

        xor     ecx, ecx                        ; (ECX) = counter
        add     esi, eax                        ; (ESI) = -> end of path name
xfs87:  dec     esi
        cmp     byte ptr [esi], '\'             ; Is character '\'?
        je      short xfs88                     ; Yes, quit searching
        cmp     byte ptr [esi], '/'             ; Is character '/'?
        je      short xfs88                     ; Yes, quit searching
        inc     ecx                             ; No, increment counter
        cmp     ecx, eax                        ; At beginning of path name?
        jl      short xfs87                     ; No, look at next character
        jmp     short xfs89                     ; Yes, quit searching
xfs88:  inc     esi                             ; Move forward over '\' or '/'

;       If the file name is too long to fit on a single line, just print
;       the maximum allowable characters

xfs89:  cmp     ecx, XCPTFileNameMsgLen         ; Is file name too long?
        jle     short xfs90                     ; No, print entire file name
        mov     ecx, XCPTFileNameMsgLen         ; Yes, print first part
xfs90:

;       Copy the file name into the buffer

        DosContext <es>,di
        mov     edi, [fas_edi]                  ; (EDI) = current end of buffer
B1EMac  rep     movsb
        mov     [fas_edi], edi                  ; Save new end of buffer
        FlatContext <es>,di

;       Find the number of the object/segment containing the faulting EIP by
;       searching through the object/segment table within the swappable MTE
;       for an object whose lower and upper base virtual addresses bound the
;       linearized EIP or a segment whose selector matches the faulting CS

        mov     esi, [fas_pERepRec]             ; (ESI) = -> xcpt report rec
        mov     ecx, [esi].ExceptionAddress     ; (ECX) = EIP laddr
        mov     [fas_leip], ecx                 ; Save EIP laddr for later
        mov     esi, [fas_smte]                 ; (ESI) = -> swappable mte
        mov     edx, [esi].smte_objcnt          ; (EDX) = number of objects

;begin 72837 block changes
        mov     esi, [esi].smte_objtab          ; (ESI) = -> first ote/ste
        mov     eax, 1                          ; (EAX) = current obj/seg number

;       Determine whether smte_objtab points to an object table (MTE format is
;       LX) or a segment table (MTE format is NE)

        SaveReg <bx>
        mov     bx, [fas_mte_flags2]            ; (BX) = mte flags2
        and     bx, MTEFORMATMASK               ; (BX) = mte format flags
        cmp     bx, MTEFORMATLX                 ; Is MTE format LX?
        RestoreReg <bx>
        je      short xfs90a                    ; Yes

;       Search through segment table only if the CS and EIP are available,
;       which means that the context record must be present and valid

        or      ebx, ebx                        ; Is there a context record?
        jz      xfs90d                          ; No, skip rest of insert
        test    [ebx].ContextFlags, CONTEXT_CONTROL ; Is the context valid?
        jz      short xfs90d                    ; No, skip rest of insert
        mov     ecx, [ebx].ctx_SegCs            ; (CX) = faulting CS
        and     cx, RPL_CLR                     ; (CX) = faulting CS - RPL
xfs200: mov     di, [esi].ste_selector          ; (DI) = segment selector
        and     di, RPL_CLR                     ; (DI) = segment selector - RPL
        cmp     cx, di                          ; Does CS match selector?
        je      short xfs205                    ; Yes, quit searching
        add     esi, size ldrste_s              ; (ESI) = -> next ste
        inc     eax                             ; (EAX) = next segment number
        cmp     eax, edx                        ; Are there segments left?
        jle     short xfs200                    ; Yes, try next segment
        jmp     short xfs90d                    ; No, skip rest of insert

xfs205: mov     edx, [ebx].ctx_RegEip           ; (EDX) = faulting EIP
        jmp     short xfs210

;       Search through object table
; end 72837 block changes

xfs90a: mov     edi, [esi].ote_base             ; (EDI) = object lower base
        cmp     ecx, edi                        ; Is EIP less than lower base?
        jl      short xfs90b                    ; Yes, try next object
        add     edi, [esi].ote_size             ; (EDI) = object upper base
        cmp     ecx, edi                        ; Is EIP greater than upper base?
        jl      short xfs90c                    ; No, quit searching
xfs90b: add     esi, size ldrote_s              ; (ESI) = -> next ote
        inc     eax                             ; (EAX) = next object number
        cmp     eax, edx                        ; Are there objects left?
        jle     short xfs90a                    ; Yes, try next object
        jmp     short xfs90d                    ; No, skip rest of insert

;begin 72837 block changes
xfs90c: mov     edx, [fas_leip]                 ; (EDX) = EIP laddr
        sub     edx, [esi].ote_base             ; (EDX) = Offset within object

;       EAX now contains the number of the object/segment containing the
;       faulting EIP and EDX contains the offset of the faulting EIP within
;       this object/segment

xfs210: mov     ecx, XCPTObjOffMsgLen           ; (ECX) = length of obj:off
; end 72837 block changes

        mov     edi, offset FLAT:XCPTObjOffMsg  ; (EDI) = -> obj:off buffer
        inc     edi                             ; Skip over space in buffer
        CALL32  HexToAscii32                    ; Format object/segment number
        inc     edi                             ; Skip colon in address string
        mov     eax,edx
        shr     eax,16
        CALL32  HexToAscii32                    ; Format high word of offset
        mov     ax,dx
        CALL32  HexToAscii32                    ; Format low word of offset
        mov     esi, offset FLAT:XCPTObjOffMsg  ; (ESI) = -> obj:off buffer

;       Copy the object/segment number and offset into the buffer

        DosContext <es>,di
        mov     edi, [fas_edi]                  ; (EDI) = current end of buffer
B1EMac  rep     movsb
        jmp     short xfs90e                    ; (ES:EDI) already set

xfs90d: DosContext <es>,di
        mov     edi, [fas_edi]                  ; (EDI) = current end of buffer
xfs90e: mov     ecx, XCPTCRLFMsgLen             ; (ECX) = length of '\r\n'
        mov     esi, offset FLAT:XCPTCRLFMsg    ; (ESI) = pointer to '\r\n'
B1EMac  rep     movsb

        mov     [fas_edi], edi                  ; Save new end of buffer
        FlatContext <es>,di

;       Terminate the message's fourth insert (if there is no insert, then
;       there must be an additional 0 following the 0 which terminates the
;       message's third insert)

xfs91:  mov     edx, [fas_msg]                  ; (EDX) = message number
        DosContext <es>,di
        mov     edi, [fas_edi]                  ; (EDI) = current end of buffer
        xor     al, al
        stosb                                   ; End of message
        FlatContext <es>,di

; Determine which CodeTerminate value and CodeResult value to use.  If
; there is a context record (EBX) and the CONTEXT_CONTROL bit is set and
; the CS is 16-bit, then CodeTerminate = 2 and CodeResult = trap number.
; Otherwise, CodeTerminate = 4 and CodeResult = exception number.

        or      ebx, ebx                        ; Is there a context record?
        jz      short xfs92                     ; No. Don't check CS.
        test    [ebx].ContextFlags, CONTEXT_CONTROL ; Is the context valid?
        jz      short xfs92                     ; No. Don't check CS.

        mov     ebx, [ebx].ctx_SegCs
        and     ebx, TABLE_MASK
        cmp     ebx, 4
        jne     short xfs92

        mov     ebx, [fas_ulTrapNumber]         ; CodeResult = trap number
        mov     eax, TC_GP_TRAP                 ; CodeTerminate = 2
        jmp     short xfs93

xfs92:  mov     ebx, [fas_pERepRec]
        mov     ebx, [ebx].ExceptionNum         ; CodeResult = exception number
        mov     eax, TC_XCPT                    ; CodeTerminate = 4

;       (EAX) = exit type
;       (EBX) = trap number/exception number
;       (ECX) = number of replacement strings
;       (EDX) = message number
;       (EDI) = Optional pointer to nested exception record.
;       (DS:SI) = pointer to replacement strings

xfs93:  DosContext <ds>,di
        mov     ecx, 4
        mov     edi, [fas_pERepRec]
        mov     si,offset DOSGROUP:XCPTReportRecordMsg
        CALL16  DelayHardErr            ; generate harderr when process is dead
        FlatContext <es,ds>,bx
xfs95:  RestoreReg <ebx,edi,esi>

        LeaveProc
        RETC

EndProc _xcptFormatAndSendHardErr

;***LP  ClearRegDump - Clear the specified register dump
;
;       Formats the register dump string.
;
;       ENTRY   ECX = length of table
;               ESI = register dump table, in this format:
;
;               dd      offset relative to EBX of data to be printed
;                         if EBX == 0, reg number for KMQueryClientRegister
;               dd      flat relative offset of the place to put hex string
;               dd      size of register (2 or 4)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDI, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure ClearRegDump,near,local

crd10:  lodsd                           ; (EAX) = offset of value
        lodsd                           ; (EAX) = offset to clear value
        mov     edi,eax                 ; (EDI) = offset to put value

        lodsd                           ; (EAX) = size
        cmp     eax,2                   ; are we clearing a dword register?
        mov     eax, 'XXXX'
        jbe     short crd40             ;  no, jump around print high part

        stosd
crd40:  stosd

        loop    crd10
        RETC

EndProc   ClearRegDump


;***LP  ClearLimAccDump - Clear the specified Limit/Access dump
;
;       Formats the register dump string.
;
;       ENTRY   ECX = length of table
;               ESI = register dump table, in this format:
;
;               dd      offset relative to EBX of data to be printed
;                         if EBX == 0, reg number for KMQueryClientRegister
;               dd      flat offset of the place to put access byte hex string
;               dd      flat offset of the place to put limit hex string
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDI, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure ClearLimAccDump,near,local

cla10:  lodsd                           ; (EAX) = offset of value
        lodsd                           ; (EAX) = offset of Access
        mov     edi,eax                 ; (EDI) = offset to put value

        mov     eax, 'XXXX'
        stosd

        lodsd                           ; (EAX) = offset of Limit
        mov     edi,eax
        mov     eax, 'XXXX'
        stosd
        stosd

        loop    cla10
        RETC

EndProc   ClearLimAccDump

;***LP  _xcptQueryFPState - Fetch the NPX context from the chip.
;*
;*      _xcptQueryFPState switches the NPX to the current context and
;*      retrieves the full state.
;*
;*      ENTRY   gfp_pFPEnv - Pointer to space to store FP environment
;*
;*      EXIT    None
;*
;*      USES    FLAGS

Procedure _xcptQueryFPState

ArgVar  gfp_pFPEnv,DWORD

LocalVar gfp_FPState, <SIZE FPSTATE>

        EnterProc
        SaveReg <esi, edi, ebx>

        CCALL32 SwitchNPX               ; Swich NPX to current context
        CCALL32 WaitNPX

        mov     esi, [gfp_pFPEnv]
        fnsave  [esi]                   ; Get the full FP state

        RestoreReg <ebx, edi, esi>
        LeaveProc

        RETC

EndProc _xcptQueryFPState

EXMGSWAP_TEXT ends

END
