;       SCCSID = @(#)dosinit.asm        6.4 92/02/05
PAGE    ,132
NAME    DOSINIT
TITLE   DOSINIT.ASM - Debugger initialization for DOS 5 1.1

SCCSID  equ     "@(#)dosinit.asm        6.4 92/02/05"

;***    DOSINIT.ASM
;
;       This module provides the debugger initialization
;       routines and data to start the debugger in DOS 1.1.
;

INCL_MI =       1

.xlist
        include dosseg.inc
        include basemaca.inc
        include fnodeb.inc
        include osmaca.inc
        include mi.inc
        include devsym.inc
        include filemode.inc
        include opncreat.inc
        include dirent.inc
        include vmowner.inc
        include seldesc.inc
        include protmode.inc
        include virtsym.inc
        include osconst.inc
        include pgexport.inc
        include vmexport.inc
        include tkexport.inc
        include selxport.inc
        include debequ.inc
        include debsym.inc
        include debinit.inc
        include ldrvars.inc
        include newexe.inc
        include kmode.inc
        include proc.inc
        include dossymc.inc
        include infoseg.inc
        include sem.inc
        include except.inc
        include screen.inc
        include sigdef.inc
        include tkptda.inc
.list
        ModName  , FNO_DOSINIT_ASM
        CpuMode 386

        EXTRN           _Debug_Entry:far
        EXTRN           _Debug_Sym:far
        EXTRN           _Debug_Command:far
        EXTRN           _Debug_Task:far
        EXTRN           _Debug_Break32:far
        EXTRN           _DebCallOutRoutine:near
        EXTRN           _KDPLink:far
        EXTRN           _KDPUnlink:far
        EXTRN           _KDPEnable:far
        EXTRN           _KDPTaskNew:far ;JWE
        EXTRN           _KDPTaskEnd:far ;JWE
        EXTRN           _KDPPageIn:far  ;JWE
        EXTRN           InitComPort:far
        EXTRN           ArenaSelToSeg:near
        EXTRN           _VMCreateKH:near
        EXTRN           _VMAllocKHB:near
        EXTRN           _VMFreeKHB:near
        EXTRN           _VMGetInfoKHB:near
        EXTRN           _VMAllocMem:near
        EXTRN           _VMFreeMem:near
        EXTRN           _VMLinToPhys:near
        EXTRN           _SELLdrDesc:near
        EXTRN           _SELAllocGDT:near
        EXTRN           _SELFreeGDT:near
        EXTRN           _SELSetDescInfo:near
        EXTRN           IDTLEN:abs
        EXTRN16         _Debug_Sym32
        EXTRNFAR        DoOpenCreate
        EXTRNFAR        w_Close
        EXTRNFAR        w_Read
        EXTRNFAR        w_LSeek
        EXTRNFAR        SYIOpenFile
        EXTRNFAR        SYIReadFile
        EXTRNFAR        SYICloseFile
        ReferGDT        GDT_IDT,QWORD
        ReferGDT        _EndGDTPUBSEG,QWORD
        ReferFlat       _TKSSBase,DWORD
        ReferFlat       dcm_ote_start,byte
        ReferFlat       CallGate_Debug_SymWinOS2,WORD
        ReferGlobal     TaskNumber,WORD
        ReferGlobal IDT,QWORD
        EXTRN           _pDebugLoadSymDosFS:near
        EXTRN           _pDebugLoadSymModule:near
        EXTRN           SIOpen:near
        EXTRN           SIClose:near
        EXTRN32         _TKCatchFault
        EXTRN32         _TKClrFault

;       Debugger initialization flags

DI_COMMON               equ     (INIT_REALFLAG or INIT_CPU386 or \
                                 INIT_ENV386 or INIT_DISLWR)
DI_RM                   equ     (DI_COMMON or INIT_PROTFLAG)
DI_DM                   equ     (DI_COMMON or INIT_PROTFLAG)
DI_REINIT               equ     (DI_COMMON or INIT_PROTFLAG)

;       Vectors the debugger should intercept

REALVECS_RM             equ     (V0+V1+V2+V3+V4+V5+V6)
REALVECS_DM             equ     (V0+V1+V2+V3+V4+V5+V6)
REALVECS_REINIT         equ     (V0+V1+V2+V3+V4+  +V6)

PROTVECS_RM             equ     0
PROTVECSHARD_RM         equ     0
PROTVECS_DM             equ     (V0+V1+V2+V3+V4+V5+V6+V7+V8+V9+VA+VB+VC+VD)
PROTVECSHARD_DM         equ     (V0+V1+V2+V3+V4+V5+V6+V7+V8+V9+VA+VB+VC+VD)
PROTVECS_REINIT         equ           (V2)
PROTVECSHARD_REINIT     equ           (V2)

MTESymStruc     struc
                MTESymLink      dd      0
                MTESymHandle    dd      0
MTESymStruc     ends

NE_pModName     equ     (size NESymStruc)

SYM_HEAP_SIZE   equ     (_1MEG * 2)                                  ;B732292
; BUGBUG - the following is only good up to 32k filesystems
; There is potentially a problem here on smaller systems with lessor
; conventional memory.
SYM_READ_SIZE   equ     (PAGESIZE * 8)

INITDATA segment

        public _DebBreakChar
_DebBreakChar   db      ?

DebInit DebugInit <,,DBGCODE,DBGDATA,DOSGDTDATA,,,,,,,,,,,,_DebCallOutRoutine>

DosSymFile      db      "OS2KRNL.SYM",0
DebugConfigFile db      "KDB.INI",0

DevMapTable     label   word
                SegTable <,2>                           ; Map address
DevMapDSData    SegDef   <SYM_TYPE_BIMODAL, 0, 0, 1>
DevMapCSData    SegDef   <SYM_TYPE_BIMODAL, 0, 0, 2>

                .errnz  AddrOff-0
                .errnz  AddrSeg-4
                .errnz  AddrType-6
                .errnz  AddrTask-8
                .errnz  GroupCount-10
                .errnz  SegDefs-12

                .errnz  SegDefType-0
                .errnz  SegDefSel-2
                .errnz  SegDefSeg-4
                .errnz  SegDefSegNum-6

INITDATA ends

INITBSS segment
DosSymMap       SegTable <, ?>                          ; Map address
                db      SN_MAX * size SegDef dup(?)     ; space for kernel map
INITBSS ends


_DATA           SEGMENT

hkrhSym         dd      0

MTESymHead      MTESymStruc     <0, 0>

                public  NESymHead
NESymHead       dd      0

MTESymMapAddr   label   word
                db      size AddrS DUP (?)

segtableV86Krnl label   word
                SegTable <, 1>
                SegDef   <SYM_TYPE_SEG, 0, 0, 0>

cV86KrnlSym     dd      -1              ; count of VDM's created

SymString       db      ".sym", 0
SymStringLen    equ     $-SymString

; Start of change DGE
        public  pTSBuff
pTSBuff         dd      0
; End of change DGE

_DATA           ENDS

DATA segment

SymMapNameLen   equ     128             ; must be in a 16 bit data segment
SymMapName      db      SymMapNameLen dup(0)

                public  segDebugCS
segDebugCS      dw      0               ; debugger's code segment para

DATA ends

        FARCODE LOW
CODE    segment
        extrn   far_dprintfRM:dword
        extrn   far_doutcharRM:dword

Debug_BreakRM   dd      _Debug_Break32  ; real mode break address

Procedure Debug_BreakDM,near
Entry   Debug_BreakDM,far16,,nocheck
        pushf
        whatmode
        jc      dbd10
        popf
        jmp     [Debug_BreakRM]

dbd10:  popf
        jmp     _Debug_Break32
EndProc   Debug_BreakDM

CODE    ends

         FARCODE INIT
INITCODE segment

Debug_EntryRM   dd      _Debug_Entry    ; real mode entry point pointer

;***    DebugInitializeRM - Initialize Kernel Debugger for 386 real mode
;
;       This initializes the debugger for real mode operations, but
;       doesn't break into the debugger.  An int 3 in the pre-protected
;       mode init code will break into the debugger.  Lower case "r" at
;       the console will make the debugger stop here.
;
;       ENTRY:  (AL)      = break char read by os2ldr
;               ((SS:DI)) = ArenaInfo array
;       EXIT:   NONE
;       USES:   Flags

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugInitializeRM
        push    ds
        push    es
        pushad
        push    ss                      ; ((es:di)) = ArenaInfo array
        pop     es
        DosContext ds

        push    ax
        mov     ax,DOSINITDATA
        call    ArenaSelToSeg           ; (ax)=seg = ArenaSelToSeg(ax,es:di)
        mov     ds,ax                   ; (ds) = DOSINITDATA paragraph address
    assume  ds:DOSINITDATA
        pop     ax
        mov     [_DebBreakChar],al

        mov     ax,DOSGROUP
        call    ArenaSelToSeg           ; (ax)=seg = ArenaSelToSeg(ax,es:di)
        push    ax

        mov     ax,DOSGDTDATA
        call    ArenaSelToSeg           ; (ax)=seg = ArenaSelToSeg(ax,es:di)
        push    ax

        mov     ax,DBGDATA
        call    ArenaSelToSeg           ; (ax)=seg = ArenaSelToSeg(ax,es:di)
        push    ax                      ; save DBGDATA paragraph address

        mov     ax,DBGCODE
        call    ArenaSelToSeg           ; (ax)=seg = ArenaSelToSeg(ax,es:di)
        push    DOSCODE
        pop     es                      ; (es) = DOSCODE
    assume  es:DOSCODE
        mov     [far_dprintfRM].Segmt16,ax
        mov     [far_doutcharRM].Segmt16,ax
        mov     [Debug_BreakRM].Segmt16,ax
    assume  es:nothing
CpuMode 8086
        mov     cs:[Debug_EntryRM].Segmt16,ax ; set DBGCODE paragraph address
CpuMode 386

        mov     di,offset DOSINITDATA:DebInit
        pop     [di].DSseg              ; restore DBGDATA paragraph address
        mov     [di].CSseg,ax           ; set DBGCODE paragraph address
        mov     [di].InitFlag,DI_RM
        mov     [di].RealVectorSet,REALVECS_RM
        mov     [di].ProtVectorSet,PROTVECS_RM
        mov     [di].ProtVectorHard,PROTVECSHARD_RM
        mov     [di].BreakChar,'r'

        xor     eax,eax
        pop     ax                      ; (AX) = DOSGDTDATA paragraph address
        shl     eax,4                   ; (EAX) = linear address
        mov     dword ptr [di].GDTaddr+2,eax
        mov     word ptr [di].GDTaddr,(GSEL _EndGDTPUBSEG) - 1

        xor     eax,eax
        pop     ax                      ; (AX) = DOSGROUP paragraph address
        mov     es,ax
    assume  es:DOSGROUP
        mov     cx,cs:[Debug_EntryRM].Segmt16
        mov     [segDebugCS],cx
    assume  es:nothing
        shl     eax,4                   ; (EAX) = linear address
        add     eax,offset DOSGROUP:IDT
        mov     dword ptr [di].ProtIDTaddr+2,eax
        mov     word ptr [di].ProtIDTaddr,IDTLEN - 1

        push    ds
        pop     es
     assume es:DOSINITDATA
        jmp     DebReinitEntryRM
EndProc DebugInitializeRM

;***    DebugInitializeDM - Initialize the kernel debugger for protected mode
;
;       This call initializes the kernel debugger for both protected mode
;       and real mode stopping so that breakpoints can be set, etc.  Lower
;       case "p" will make the debugger stop here.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USE:    Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugInitializeDM
        push    ds
        push    es
        pushad
        FlatContext <ds>,ax
        mov     [segtableV86Krnl].MapAddrS.AddrOff,0
        DosInitContext <ds,es>,ax
        mov     di,offset DOSINITDATA:DebInit
        mov     [di].InitFlag,DI_DM
        mov     [di].RealVectorSet,REALVECS_DM
        mov     [di].ProtVectorSet,PROTVECS_DM
        mov     [di].ProtVectorHard,PROTVECSHARD_DM
        mov     [di].BreakChar,'p'
        jmp     DebReinitEntry
EndProc DebugInitializeDM

;***    DebugMovedGDTIDT - Tell debugger GDT or IDT moved
;
;       This call re-initializes the kernel debugger to tell it
;       that the GDT and IDT have moved.  The debugger doesn't
;       stop on this call.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USE:    Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugMovedGDTIDT,<near,far16>
        push    ds
        push    es
        pushad
        DosInitContext <ds,es>,ax
        mov     di,offset DOSINITDATA:DebInit
        mov     [di].InitFlag,DI_DM + INIT_NOBRKFLAG
        mov     [di].RealVectorSet,REALVECS_DM
        mov     [di].ProtVectorSet,PROTVECS_DM
        mov     [di].ProtVectorHard,PROTVECSHARD_DM
        jmp     DebReinitEntry
EndProc DebugMovedGDTIDT

;***    DebugReInitialize - ReInitialize the kernal debugger
;
;       This call re-initializes the kernel debugger.  Symbols for DOS
;       are are also loaded.  The debugger will stop on this call if
;       the space bar is pressed.  The KDB.INI debugger command file
;       is loaded and executed.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USE:    Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugReInitialize
        push    ds
        push    es
        pushad
        DosInitContext <ds>,ax
        mov     [DosSymMap].GroupCount,SN_MAX
        FlatContext <es>,ax
        mov     si,offset DOSINITDATA:DosSymMap + size SegTable
        mov     edi,offset FLAT:dcm_ote_start
        mov     cx,1

dri10:  mov     edx,es:[edi].ote_flags
        test    edx,OBJBIGDEF
        jnz     short dri30                     ; jmp if 32 bit segment
        mov     [si].SegDefType,SYM_TYPE_SEL    ; symtype is selector
        mov     ax,es:[edi].ote_selector
        mov     [si].SegDefSel,ax               ; set selector
        xor     ax,ax                           ; set seg to 0 if not tiled
dri20:  mov     [si].SegDefSeg,ax               ; set RM segment
        jmp     short dri40

dri30:  mov     [si].SegDefType,SYM_TYPE_LIN    ; symtype is linear
        mov     eax,es:[edi].ote_base
        mov     [si].SegDefLinPhy,eax           ; set base laddr

dri40:  mov     [si].SegDefSegNum,cx            ; set segment number
        add     edi,size ldrote_s
        add     si,size SegDef
        inc     cx
        cmp     cx,SN_MAX
        jbe     short dri10

;       Create symbol file heap

        FlatContext <ds>,ax
        CCALL32 _VMCreateKH, <SYM_HEAP_SIZE, (PG_RESIDENT + PG_R + PG_W),\
                              KDBSYMOWNER, offset FLAT:hkrhSym, NULL>
        or      eax,eax                 ; did the heap creation succeed?
        jz      short dri50             ;  yes, continue
        mov     [hkrhSym],0             ;  no, mark that we can't load symbols

;       Load and link in symbol file on the re-init call

dri50:
        SSToDS  eax,[esp-4]             ; allocate selector
        sub     esp,4
        CCALL32 _SELAllocGDT,eax
        or      eax,eax
        pop     eax
        jnz     short dri55             ; Jump if error

        push    eax
        mov     bx,seg FLAT:DOSHIGH32CODE
        CCALL32 _SELSetDescInfo, < SELSD_GATE, D_GATE332, eax, \
                                   offset FLAT:_Debug_SymWinOS2, ebx, \
                                   0, 0, 0 >
        pop     eax
        or      ax,RPL_RING3
        mov     CallGate_Debug_SymWinOS2, ax

dri55:
        DosInitContext <ds,es>,ax
        mov     si,offset DOSINITDATA:DosSymMap.MapAddrS
        mov     di,offset DOSINITDATA:DosSymFile
        xor     dx,dx
        SaveReg <ecx>
        xor     ecx,ecx
        call    DebugLoadSymSysInitFS
        RestoreReg <ecx>
        jc      dri60
        mov     al,SYM_LINKMAP          ; (AL) = Link Map Flag
        call    _Debug_Sym              ; go Link in new Map
        jnc     short dri60             ; if no error, don't release map space

        pusha
        SaveReg <es,ds>
        mov     esi,ds:[si].AddrOff     ; (ESI) = linear address to free
        FlatContext <ds,es>,ax,noassume
        CALLF32 DebFreeMem
        RestoreReg <ds,es>
        popa

;       Reinitialize the debugger

dri60:  call    DebugInitialize

;       Load and execute debugger command script

        mov     di,offset DOSINITDATA:DebugConfigFile
        mov     dx,1
        SaveReg <ecx>
        xor     ecx,ecx
        call    DebugLoadSymSysInitFS
        RestoreReg <ecx>

        popad
        pop     es
        pop     ds
        ret
EndProc DebugReInitialize

;***    DebugInitialize - Initialize the kernal debugger
;
;       This call re-initializes the kernel debugger.  Symbols for DOS
;       are are also loaded.  The debugger will stop on this call if
;       the space bar is pressed.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USE:    Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugInitialize,near,local
        push    ds
        push    es
        pushad
        DosInitContext <ds,es>,ax
        mov     di,offset DOSINITDATA:DebInit
        mov     [di].InitFlag,DI_REINIT
        mov     [di].RealVectorSet,REALVECS_REINIT
        mov     [di].ProtVectorSet,PROTVECS_REINIT
        mov     [di].ProtVectorHard,PROTVECSHARD_REINIT
        mov     [di].BreakChar,' '

;       Copy the Interrupt Descriptor Table descriptor to the
;       parameter list

DebReinitEntry:
    assume ds:DOSINITDATA, es:DOSINITDATA

        GDTContext ds
        push    di
        mov     si,GSEL GDT_IDT
        add     di,ProtIDTaddr
        movsw                           ; move IDT limit
        movsw                           ; move IDT base low
        movsb                           ; move IDT base high
        lodsw                           ; skip access/attr word
        movsb                           ; move IDT base ext
        pop     di

;       Copy the GDT descriptor to the parameter list

        push    di
        mov     si,DOSGDTDATA
        add     di,GDTaddr
        movsw                           ; move GDT limit
        movsw                           ; move GDT base low
        movsb                           ; move GDT base high
        lodsw                           ; skip access/attr word
        movsb                           ; move GDT base ext
        pop     di

;       Set the real mode interrupt vector table address

        push    di
        add     di,RealIDTaddr
        mov     ax,0ffffh
        stosw                           ; set IDT limit
        xor     ax,ax
        stosw                           ; set IDT base low
        stosw                           ; set IDT base high/ext
        pop     di

;       Invoke the Kernel Debugger
;       Call _Debug_Entry(parameter list,kernel segment selectors)
;
;       (ES:DI) = DOSINITDATA:DebInit (mode dependent pointer)

DebReinitEntryRM:
    assume es:DOSINITDATA
        mov     al,[_DebBreakChar]
        cmp     es:[di].BreakChar,al    ; did boot loader detect proper char?
        jnz     short dit10             ; jmp if not
        mov     es:[di].BreakChar,0     ; force break if so
        mov     [_DebBreakChar],0       ; and don't do it again

dit10:  mov     ax,seg FLAT:DGROUP      ; (ax) = FLAT data selector
        mov     bx,seg FLAT:DOSHIGH32CODE ; (bx) = FLAT code selector
        mov     cx,DOSHIGH2CODE         ; (cx) = high code 2 segment selector
        mov     dx,DOSHIGH3CODE         ; (dx) = high 3 code segment selector
        DosContext ,si          ; (si) = DOSGROUP selector
        DosContext ds                   ; (ds) = DOSGROUP
        whatmode
        jc      short dit20
        push    cs
        push    offset cs:dit30
        jmp     [Debug_EntryRM]         ; (es:di) = address of parameter list

dit20:  call    _Debug_Entry            ; (es:di) = address of parameter list

;       Return to caller

dit30:  popad
        pop     es
        pop     ds
        ret
EndProc DebugInitialize

;***    DebugLoadSymSysInitFS - Loads a symbol file for debugging
;
;       Uses the sysinit file system.
;
;       ENTRY:  (DS:SI) = pointer to map AddrS to fill in (symbols only)
;               (ES:DI) = pointer to file name to load (asciiz)
;               (ECX) = size of header to put on front of symbol segment
;               (DX)    = 0 load and link symbol file
;                       = 1 load and execute debugger command script
;
;
;       EXIT:   'C' - File loaded successfully
;               'C' Set - Unable to load file.
;               Unable to allocate memory | file not found
;
;       USES:   Flags
;
        ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugLoadSymSysInitFS, <hybrid,far16>

LocalVar  lsi_fp16addrsMap,DWORD
LocalVar  lsi_cbHeader,DWORD
LocalVar  lsi_fCommandFile,WORD
LocalVar  lsi_addrsCommandFile,<size AddrS>
LocalVar  lsi_cbMem,DWORD
LocalVar  lsi_pMem,DWORD
LocalVar  lsi_selTmp,DWORD
LocalVar  lsi_pTmp,DWORD
LocalVar  lsi_pCurrent,DWORD
LocalVar  lsi_cbLeft,DWORD
LocalVar  lsi_cbRead,DWORD

        EnterProc <ds,si,ecx,dx>            ; initialize lsi_fp16addrsMap
        SaveReg <ds,es>
        pushad

;       (ES:DI) = file name (in root only)

        CALLFAR SYIOpenFile     ; (AX:BX) = file size
        jc      lsix                    ; exit if error in opening

        mov     [lsi_cbMem].HighWord,ax
        mov     [lsi_cbMem].LowWord,bx  ; save map file size
        or      ax,bx
        stc                             ; is file size 0?
        jz      lsix                    ;  yes, jump to exit

        mov     eax,[lsi_cbMem]
        mov     [lsi_cbLeft],eax        ; size left is always file size

        xor     eax,eax
        cmp     [lsi_fCommandFile],0    ; loading symbol file?
        jnz     short lsi10             ;  no, set header size to zero
        mov     eax,(size SymMapHeader) ;  yes, add in symbol head size
        add     eax,lsi_cbHeader
        add     [lsi_cbMem],eax
lsi10:  mov     [lsi_pCurrent],eax      ; save header size

        mov     ecx,[lsi_cbMem]
        cmp     ecx,SYM_READ_SIZE
        jbe     short lsi15
        mov     ecx,SYM_READ_SIZE
lsi15:  mov     edx,PG_1M               ; below 1M physical
        FlatContext <ds,es>,ax
        CALLF32 DebAllocMem             ; (ESI) = linear
        jc      lsix
        mov     [lsi_pTmp],esi          ; save linear address

        SSToDS  eax,[lsi_selTmp]        ; allocate selector
        CCALL32 _SELAllocGDT,eax
        or      eax,eax
        jnz     lsi60                   ; if error, free memory and exit

        xor     eax,eax
        CCALL32 _SELSetDescInfo, <SELSD_ALL, D_DATA0, [lsi_selTmp], \
                        SYM_READ_SIZE, [lsi_pTmp], eax, eax, eax>

;       Now allocate high physical memory for the map file
;       and copy it up there.  We do this because low physical
;       memory is (unfortunately) a precious resource while we
;       continue to use the SysInit file system.

        mov     ecx,[lsi_cbMem]
        xor     edx,edx
        CALLF32 DebAllocMem             ; (ESI) = linear
        jc      lsi50
        mov     [lsi_pMem],esi          ; save linear address
        add     [lsi_pCurrent],esi      ; add linear address to header size

        mov     [lsi_cbRead],SYM_READ_SIZE
lsi20:  mov     eax,[lsi_cbLeft]        ; (EAX) = size left
        cmp     eax,[lsi_cbRead]
        jae     short lsi30
        mov     [lsi_cbRead],eax

lsi30:  mov     ax,[lsi_selTmp].LowWord
        xor     bx,bx                   ; (AX:BX) = buffer address
        mov     cx,[lsi_cbRead].HighWord
        mov     dx,[lsi_cbRead].LowWord ; (CX:DX) = read size
        CALLFAR SYIReadFile

        FlatContext <ds,es>
        mov     esi,[lsi_pTmp]
        mov     edi,[lsi_pCurrent]      ; save new laddr, (DS:ESI) = old laddr
        mov     ecx,[lsi_cbRead]        ; (ECX) = number of bytes read
        CALLF32 docopy                  ; go do copy in 32-bit code
        add     [lsi_pCurrent],ecx
        sub     [lsi_cbLeft],ecx        ; subtract read size from size left
        ja      short lsi20

        CALLFAR SYICloseFile
    ASSUME   DS:NOTHING, ES:NOTHING

        cmp     [lsi_fCommandFile],0    ; are we loading symbols?
        jz      short lsi40             ;  yes, jump to symbol linking

;       Initialize the command buffer AddrS and call debugger to execute.

        mov     ax,ss
        mov     ds,ax
    ASSUME   DS:NOTHING
        lea     si,[lsi_addrsCommandFile] ; (DS:SI) = pointer to AddrS
        mov     eax,[lsi_pMem]          ; (EAX) = linear address of commands
        mov     ds:[si].AddrOff,eax
        mov     ds:[si].AddrType,SYM_TYPE_LIN
        mov     ds:[si].AddrTask,0
        mov     ecx,[lsi_cbMem]
        call    _Debug_Command
        clc
        jmp     short lsi50             ; exit

;       Initialize symbol map header and call the debugger to link it up.

lsi40:  lds     si,[lsi_fp16addrsMap]   ; (DS:SI) = Map Table Address
    ASSUME   DS:NOTHING
        mov     eax,[lsi_pMem]          ; (EAX) = linear address of symbols
        add     eax,lsi_cbHeader
        mov     ds:[si].AddrOff,eax
        mov     ds:[si].AddrType,SYM_TYPE_LIN
        mov     ds:[si].AddrTask,0
;       mov     al,SYM_LINKMAP          ; (AL) = Link Map Flag
;       call    _Debug_Sym              ; go Link in new Map
;       jnc     short lsi50             ; if no error, release lomem

;       mov     esi,[lsi_pMem]          ; (ESI) = linear address to free
;       FlatContext <ds,es>,ax
;       CALLF32 DebFreeMem

lsi50:  pushf
        FlatContext <ds,es>,ax
        CCALL32 _SELFreeGDT, <[lsi_selTmp]>
        popf
lsi60:  pushf
        mov     esi,[lsi_pTmp]          ; (ESI) = linear address to free
        CALLF32 DebFreeMem
        popf

; Start of change DGE

        mov     ecx,TSBUFF_BUFF_SIZE
        xor     edx,edx
        FlatContext <ds,es>,ax
        CALLF32 DebAllocMem             ; (ESI) = linear
        jc      lsix
        mov     [pTSBuff],esi

; End of change DGE

lsix:   popad
        RestoreReg <es,ds>
    ASSUME   DS:NOTHING, ES:NOTHING
        LeaveProc
        ret
EndProc   DebugLoadSymSysInitFS

;***    DebugRemoveSymMTE
;
;       Removes MTE/symbols linkage for an FSD or install device
;       driver.  The FSD or dd was loaded via its MTE, which will
;       be going away.  We want to keep the symbols, but get rid
;       of the mte reference.
;
;       Pseudo code:
;           Search from MTESymHead looking for an mte handle which matches
;           If found
;               unlink the current entry
;
;       ENTRY:  (SI) = MTE handle
;
;       EXIT:   NONE
;
;       USES:   NONE
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugRemoveSymMTE,<far16,near>
        SaveReg <ds,es>
        pushad
        FlatContext <ds,es>,ax
        movzx   edx,si                  ; (EDX) = MTE handle
        mov     esi,offset FLAT:MTESymHead

duf1:   cmp     [esi].MTESymHandle,edx  ; do the MTE handles match?
        je      short duf2              ; jump if found one to unlink

        cmp     [esi].MTESymLink,0      ; end of linked list?
        je      short duf3              ; jump if so

        mov     edi,esi                 ; (EDI) = previous link
        mov     esi,[esi].MTESymLink    ; next link
        jmp     short duf1

duf2:   mov     eax,[esi].MTESymLink    ; unlink it from the chain
        mov     [edi].MTESymLink,eax

duf3:   popad
        RestoreReg <es,ds>
        ret
EndProc DebugRemoveSymMTE

INITCODE ends


        FARCODE HIGH32
CINIT_TEXT segment

;***    _DebugPagingEnabled - Tell debugger paging has been enabled
;
;       This routine informs the debugger that paging is going to
;       be enabled and passes the spare PTE entry to it.
;
;       ENTRY:  (dpe_ppte)   = linear address of spare PTE
;               (dpe_ptelin) = linear address affected by spare PTE
;
;       EXIT:   NONE
;
;       USE:    AX, Flags
;
;       NOTE:   This function is called from "C" and has the
;               "C" calling convention.
;
        ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

Procedure _DebugPagingEnabled

ArgVar  dpe_ppte,DWORD                  ; linear pointer to spare PTE
ArgVar  dpe_ptelin,DWORD                ; linear address affected by PTE

        EnterProc
        push    ds
        push    edi
        DosInitContext <ds>,ax
        mov     edi,offset DOSINITDATA:DebInit
        mov     eax,[dpe_ppte]
        mov     [edi].DebppteSpare,eax
        mov     eax,[dpe_ptelin]
        mov     [edi].DebptelinSpare,eax
        pop     edi
        pop     ds
        LeaveProc
        CALL16  DebugMovedGDTIDT
        RETC
EndProc   _DebugPagingEnabled

;***LP  docopy - do rep movsb in 32-bit code segment
;
;       We wish to do a rep movsb using (ES:EDI) and (DS:ESI)
;       as the pointers and ECX as the count.  Getting the
;       processor to use (ECX) as the count in a 16-bit code
;       segment is tricky, so we don't bother trying; we just
;       come here.
;
;       ENTRY   (DS:ESI) = source pointer
;               (ES:EDI) = destination pointer
;               (ECX) = count of bytes
;               Direction flag set as desired
;       EXIT    NONE
;       USES    NONE

Procedure docopy,far32,local
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        push    ecx
        push    edi
        push    esi
        rep movsb
        pop     esi
        pop     edi
        pop     ecx
        RETC

EndProc docopy

;***    SIDebugLoadSymDosFS
;
;       This routine is used by the debugger at init time to
;       use the sysinit file system to read symbol files
;
;       ENTRY:  (ESI) = flat pointer to put map address.
;               (ECX) = size of header to put on front of symbol segment
;               (ES:DI) = pointer to file name to load (asciiz).
;
;       EXIT:   'C' - File loaded successfully
;               'C' Set - Unable to load file.
;               Unable to allocate memory | file not found
;
;        USES:   Flags

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure SIDebugLoadSymDosFS,near

    LocalVar        SelTemp,DWORD

    EnterProc
    SaveReg <es,ds,ecx,edx>
    SaveReg <ecx>
    mov     SelTemp,0                       ; Allocate a new selector
    SSToDS  eax,SelTemp
    CCALL32 _SELLdrDesc,<esi,SIZE AddrS,eax>
    RestoreReg <ecx>
    or     eax,eax
    .errnz NO_ERROR
    jnz     sdls_10                         ; jump if error
    SaveReg <ds>
    mov     ds,SelTemp                      ; 16 bit address in ds:si
    xor     si,si
    xor     dx,dx                           ; set symbol load flag
    CALL16    DebugLoadSymSysInitFS
    RestoreReg <ds>
    pushf
    CCALL32 _SELFreeGDT,SelTemp             ; free the alias
    popf
    jmp sdls_20
sdls_10:
    stc
sdls_20:
    RestoreReg <edx,ecx,ds,es>
    LeaveProc
    RETC
EndProc  SIDebugLoadSymDosFS

;***    SIDebugLoadSymModule
;
;       This routine is used by the debugger at init time to
;       use the sysinit file system to load symbol files
;
;       ENTRY:  (dlm_pmte) = module table entry address
;               (dlm_paddrsMap) = place to put map address
;               (dlm_cbHeader) = size of header to put on front of symbol blk
;
;       EXIT:   If carry clear, symbols loaded
;               If carry set, error during symbol load
;
;        USES:   Flags
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING


Procedure SIDebugLoadSymModule,<near,pascal>
ArgVar    dlm_cbHeader,DWORD
ArgVar    dlm_paddrsMap,DWORD
ArgVar    dlm_pmte,DWORD

    EnterProc
    SaveReg <es,ds,ecx,edx,esi,edi>
    xor ecx,ecx
    CCALL32 SIClose,<ecx>               ; close device file, only one
                                        ; file can be open at a time
    PCall   DebugLoadSymModule, <dlm_pmte,dlm_paddrsMap,dlm_cbHeader>
    pushf
    mov     edi,dlm_pmte                    ; laddr, for _SELLdrDesc
    mov     edi,[edi].mte_swapmte           ; (EDI) = pointer to swappable mte
    CCALL32 SIOpen,<[edi].smte_path,ecx,ecx,ecx>
    popf
    RestoreReg <edi,esi,edx,ecx,ds,es>
    LeaveProc
    RETC
EndProc  SIDebugLoadSymModule

CINIT_TEXT ends

        FARCODE HIGH32
HIGH32CODE segment

Procedure       DebugLoadSymDosFS_Stub,near
        CALL16  DebugLoadSymDosFS
        ret
EndProc DebugLoadSymDosFS_Stub

Procedure _KDPEnableCVK,near
        EnterProc
        CALL16  KDPEnable
        LeaveProc
        RETC
EndProc   _KDPEnableCVK

; JWE start
;***    _DebugPageLoaded
;
;       Notifies debugger that a page has been reloaded from disk (so debugger
;       can reestablish any breakpoints in the page).
;
;       ENTRY   (hmte) = MTE handle of module containing page
;               (page) = address of page
;
;       EXIT    NONE
;
;       USES    EAX, EDX, ECX, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure _DebugPageLoaded,near

ArgVar  dpl_hmte,WORD
ArgVar  dpl_page,DWORD

        EnterProc
        SaveReg <ebx, esi, edi>
        movzx   ecx,[dpl_hmte]
        mov     edx,[dpl_page]
        CALL16  KDPPageIn
        RestoreReg <edi, esi, ebx>
        LeaveProc
        RETC
EndProc   _DebugPageLoaded
; JWE end

;***    _DebugLoadSymMTE
;
;       Loads symbols for an MTE.
;
;       ENTRY   (pmte) = MTE address
;               (hmte) = MTE handle
;
;       EXIT    NONE
;
;       USES    EAX, EDX, ECX, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure _DebugLoadSymMTE,near

ArgVar  lmt_pmte,DWORD
ArgVar  lmt_hmte,WORD

        EnterProc
        SaveReg <ebx, esi, edi>
        mov     eax,[lmt_pmte]
        test    [eax].mte_flags1,MTESYMLOADED   ; if symbols already loaded
        jnz     short lmtx
        test    [eax].mte_flags1,FSHMOD+MVDMMOD+DOSMOD
        jnz     short lmtx

        mov     esi,offset FLAT:MTESymMapAddr
        mov     eax,dword ptr _pDebugLoadSymModule  ; Routine to call initially
        PCall   eax,                <[lmt_pmte], esi, (size MTESymStruc)>
        jc      short lmt10

        mov     esi,[esi].AddrOff
        sub     esi,(size MTESymStruc)          ; (ESI) = MTESymStruc pointer
        mov     eax,esi
        xchg    eax,[MTESymHead].MTESymLink     ; link in this symbol map
        mov     [esi].MTESymLink,eax            ; save next symbol pointer

        movzx   edx,[lmt_hmte]                  ; (EDX) = MTE handle
        mov     [esi].MTESymHandle,edx          ; save MTE handle in header

        mov     eax,[lmt_pmte]
        or      [eax].mte_flags1,MTESYMLOADED   ; mark symbols already loaded

lmt10:  mov     eax,[lmt_pmte]                  ; (EAX) = MTE pointer
        movzx   ecx,[lmt_hmte]                  ; (ECX) = MTE handle
        CALL16  KDPLink
lmtx:   RestoreReg <edi, esi, ebx>
        LeaveProc
Entry   EndDebugLoadSymMTE,near
        RETC
EndProc   _DebugLoadSymMTE

;***    _DebugUnLinkSymMTE
;
;       Loads symbols for an MTE.
;
;       ENTRY   (pmte) = MTE address
;               (hmte) = MTE handle
;
;       EXIT    NONE
;
;       USES    EAX, EDX, ECX, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure _DebugUnLinkSymMTE,near

ArgVar  dum_pmte,DWORD
ArgVar  dum_hmte,WORD

        EnterProc
        SaveReg <ebx, esi, edi>
        movzx   edx,[dum_hmte]          ; (dx) = MTE handle
        mov     esi,offset FLAT:MTESymHead

dum1:   cmp     [esi].MTESymHandle,edx  ; do the MTE handles match?
        je      short dum2              ; jump if found one to unlink

        cmp     [esi].MTESymLink,0      ; end of linked list?
        je      short dum3              ; jump if so

        mov     edi,esi                 ; (EDI) = previous link
        mov     esi,[esi].MTESymLink    ; next link
        jmp     short dum1

dum2:   mov     eax,[esi].MTESymLink    ; unlink it from the chain
        mov     [edi].MTESymLink,eax
        lea     eax,[esi + size MTESymStruc]

        push    esi
        mov     esi,offset FLAT:MTESymMapAddr
        mov     [esi].AddrOff,eax       ; save map address
        mov     [esi].AddrType,SYM_TYPE_LIN
        mov     [esi].AddrTask,0
        mov     al,SYM_UNLINKMAP
        CALL16  _Debug_Sym32
        pop     esi                     ; (ESI) = start of memory block
        CALLF32 DebFreeMem

dum3:   mov     eax,[dum_pmte]          ; (eax) = MTE pointer
        movzx   ecx,[dum_hmte]          ; (ecx) = MTE handle
        CALL16  KDPUnlink
        RestoreReg <edi, esi, ebx>
        LeaveProc
        RETC
EndProc   _DebugUnLinkSymMTE

;***    DebugLoadSymModule
;
;       Loads symbols for an module loaded.
;
;       ENTRY:  (dlm_pmte) = module table entry address
;               (dlm_paddrsMap) = place to put map address
;               (dlm_cbHeader) = size of header to put on front of symbol blk
;
;       EXIT:   If carry clear, symbols loaded
;               If carry set, error during symbol load
;
;       USES:   Flags
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING

Procedure DebugLoadSymModule,<near,pascal>

ArgVar    dlm_cbHeader,DWORD
ArgVar    dlm_paddrsMap,DWORD
ArgVar    dlm_pmte,DWORD
LocalVar  dlm_pSelTable,DWORD
LocalVar  dlm_cSegments,DWORD

        EnterProc
        SaveReg <ds,es>
        pushad
        mov     esi,[dlm_pmte]          ; (ESI) = pointer to resident mte
        mov     esi,[esi].mte_swapmte   ; (ESI) = pointer to swappable mte
        mov     esi,[esi].smte_path     ; (ESI) = module path name linear addr
        CALL16  GetSymName              ; (ES:DI) = sym file name
    ASSUME  DS:NOTHING, ES:NOTHING
        jc      dlmx
        mov     esi,[dlm_paddrsMap]     ; (ESI) = pointer to put map address
        mov     ecx,[dlm_cbHeader]
        call    dword ptr _pDebugLoadSymDosFS  ; Routine to call initially

    ASSUME  DS:NOTHING, ES:NOTHING
        jc      dlmx

;       Get the size of the map selector table

        FlatContext <ds,es>,ax
        mov     ebx,[dlm_pmte]          ; (EBX) = pointer to resident mte
        mov     ebx,[ebx].mte_swapmte   ; (EBX) = pointer to swappable mte
        mov     ecx,[ebx].smte_objcnt
        mov     [dlm_cSegments],ecx
        imul    ecx,(size SegDef)
        add     ecx,(size SegTable)     ; (ECX) = segment table size

;       Allocate memory for map selector table

        xor     edx,edx
        CALLF32 DebAllocMem
        jc      dlm40                   ; exit if error
        mov     [dlm_pSelTable],esi

        mov     eax,[dlm_cSegments]     ; (EAX) = number of objects
        mov     [esi].GroupCount,ax     ; set group count
        lea     edi,[esi].SegDefs       ; (EDI) = segdef pointer
        mov     ebx,[dlm_pmte]          ; (EBX) = pointer to resident mte
        mov     esi,[ebx].mte_swapmte   ; (ESI) = pointer to swappable mte
        mov     esi,[esi].smte_objtab   ; (ESI) = object/segment table
        xor     edx,edx                 ; (EDX) = segment number

dlm10:  inc     edx
        cmp     edx,[dlm_cSegments]
        ja      short dlm30

        mov     ax,word ptr [ebx].mte_flags2
        and     ax,MTEFORMATMASK
        cmp     ax,MTEFORMATLX
        je      short dlm20             ; jump if linear MTE, do object table
        cmp     ax,MTEFORMATR2          ; _PE_LDR
        je      short dlm20             ; jump if linear MTE, do object table

        mov     ax,SYM_TYPE_SEL
        stosw
        .errnz  SegDefType-0
        mov     ax,[esi].ste_selector
        stosw
        .errnz  SegDefSel-2
        xor     ax,ax
        stosw
        .errnz  SegDefSeg-4
        mov     ax,dx                   ; (AX) = segment number
        stosw
        .errnz  SegDefSegNum-6
        add     esi,size ldrste_s       ; next segment table entry
        jmp     short dlm10

dlm20:  test    [esi].ote_flags,OBJBIGDEF
        jnz     short dlm25

        mov     ax,SYM_TYPE_SEL
        stosw
        .errnz  SegDefType-0
        movzx   eax,word ptr [esi].ote_selector ; (EAX) = object base
        stosd
        .errnz  SegDefSel-2
        .errnz  SegDefSeg-4
        mov     ax,dx                   ; (AX) = object number
        stosw
        .errnz  SegDefSegNum-6
        add     esi,size ldrote_s       ; next object table entry
        jmp     short dlm10

dlm25:  mov     ax,SYM_TYPE_LIN
        stosw
        .errnz  SegDefType-0
        mov     eax,[esi].ote_base      ; (EAX) = object base
        stosd
        .errnz  SegDefLinPhy-2
        mov     ax,dx                   ; (AX) = object number
        stosw
        .errnz  SegDefSegNum-6
        add     esi,size ldrote_s       ; next object table entry
        jmp     short dlm10

dlm30:  mov     esi,[dlm_paddrsMap]     ; (ESI) = src
        mov     edi,[dlm_pSelTable]     ; (EDI) = dest
        .errnz  MapAddrS
        mov     ecx,(size AddrS)        ; store map segment address in table
        rep     movsb

        mov     esi,[dlm_pSelTable]     ; (ESI) = selector table address
        mov     al,SYM_LINKMAP
        CALL16  _Debug_Sym32
        pushf                           ; save carry
        CALLF32 DebFreeMem              ; free SelTable, (ESI) = pSelTable
        popf
        jnc     short dlmx

dlm40:  mov     esi,[dlm_paddrsMap]
        mov     esi,[esi].AddrOff
        sub     esi,[dlm_cbHeader]      ; (ESI) = real begining of memory block
        CALLF32 DebFreeMem
        stc

dlmx:   popad
        RestoreReg <es,ds>
        LeaveProc
        RETC
EndProc   DebugLoadSymModule

;***    _DebugLoadSymV86Krnl
;
;       ENTRY   (dvk_psz)    = v86krnl pathname
;               (dvk_ulAddr) = base paragraph address of V86 kernel
;
;       EXIT    NONE
;
;       USES    EAX, EDX, ECX, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure _DebugLoadSymV86Krnl,near

ArgVar    dvk_psz, DWORD
ArgVar    dvk_ulAddr,DWORD

        EnterProc
        pushad
        SaveReg <ds, es>
        inc     [cV86KrnlSym]
        jnz     short dvkx
        mov     eax,[dvk_ulAddr]
        mov     [segtableV86Krnl].SegDefs.SegDefSeg,ax
        mov     esi,[dvk_psz]           ; (DS:ESI) = name
        CALL16  GetSymName              ; (ES:DI) = sym file name
        jc      short dvkx
    ASSUME  DS:NOTHING, ES:NOTHING
        FlatContext <ds>,ax
        mov     esi,offset FLAT:segtableV86Krnl.MapAddrS
        xor     ecx,ecx                 ; (ECX) = no header size
        CALL16  DebugLoadSymDosFS
        jc      short dvk10
        mov     esi,offset FLAT:segtableV86Krnl
        mov     al,SYM_LINKMAP
        CALL16  _Debug_Sym32
        jc      short dvk10
        mov     al,SYM_RELINKMAP
        CALL16  _Debug_Sym32
        jnc     short dvkx
        mov     al,SYM_UNLINKMAP
        CALL16  _Debug_Sym32
dvk10:  FlatContext <ds,es>,ax
        xor     esi,esi
        xchg    esi,[segtableV86Krnl].MapAddrS.AddrOff
        or      esi,esi
        jz      short dvkx
        CALLF32 DebFreeMem
dvkx:   RestoreReg <es, ds>
        popad
        LeaveProc
        RETC
EndProc   _DebugLoadSymV86Krnl

;***    _DebugFreeSymV86Krnl
;
;       ENTRY   NONE
;
;       EXIT    NONE
;
;       USES    EAX, EDX, ECX, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure _DebugFreeSymV86Krnl,near
        pushad
        SaveReg <ds, es>
        dec     [cV86KrnlSym]           ; if -1, free symbol map
        jns     short dfvx
        cmp     [segtableV86Krnl].MapAddrS.AddrOff,0
        jz      short dfvx
        mov     esi,offset FLAT:segtableV86Krnl
        mov     al,SYM_UNLINKMAP
        CALL16  _Debug_Sym32
        xor     esi,esi
        xchg    esi,[segtableV86Krnl].MapAddrS.AddrOff
        CALLF32 DebFreeMem
dfvx:   call    _Debug_ForceSymWinOS2
        RestoreReg <es, ds>
        popad
        RETC
EndProc   _DebugFreeSymV86Krnl

;***    _Debug_SymWinOS2 - Process symbol files for WINOS2
;
;       ENTRY:  (dsw_flags)  = DSW_LINK_MAP   - Link map
;                              DSW_UNLINK_MAP - Unlink map
;
;               (dsw_pne)    = Pointer to NE structure of file
;
;       EXIT:   NONE
;
;       USES:   NONE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

DSW_LINK_MAP        EQU  00000001h
DSW_UNLINK_MAP      EQU  00000002h
DSW_VALID_FLAGMASK  EQU  (DSW_LINK_MAP or DSW_UNLINK_MAP)

dsw_sf struc
        dsw_sf_edi      dd  ?
        dsw_sf_esi      dd  ?
        dsw_sf_ebp      dd  ?
        dsw_sf_padesp   dd  ?
        dsw_sf_ebx      dd  ?
        dsw_sf_edx      dd  ?
        dsw_sf_ecx      dd  ?
        dsw_sf_eax      dd  ?
        dsw_sf_trapnum  dd  ?
        dsw_sf_errcode  dd  ?
        dsw_sf_eflag    dd  ?
        dsw_sf_eip      dd  ?
        dsw_sf_cs       dd  ?
        dsw_sf_pad      dd  ?   ; Pad used because the following fields are
        dsw_sf_esp      dd  ?   ;  referenced after the EnterProc
        dsw_sf_ss       dw  ?   ;
dsw_sf ends

Procedure _Debug_SymWinOS2,near

LocalVar  dsw_flags,DWORD
LocalVar  dsw_pne,DWORD
LocalVar  dsw_paddrsMap,<size AddrS>
LocalVar  dsw_pSegTable,DWORD
LocalVar  dsw_cSegments,DWORD
LocalVar  dsw_pModName,DWORD
LocalVar  dsw_cbModName,DWORD
LocalVar  dsw_currTask,WORD
LocalVar  dsw_j1,DWORD
LocalVar  dsw_j2,DWORD
LocalVar  dsw_j3,DWORD
LocalVar  dsw_j4,DWORD
LocalVar  dsw_lj,<SIZE ljmp_s>

        pushfd                               ; Used in building VSF
        movzxESP                             ; Clear high word of ESP
        cmp     ss:[TKOPTDA].ptda_ProcType,PT_VDM ; Entry from VDM protected
        jz      short dsw05                  ;  Jmp if yes
        popfd
        jmp     dswx2
dsw05:  push    0                            ; Zero out trapnum,
        push    0                            ;  and errcode for VSF
        KMEnterKmodeVDM vpm,nothing
        mov     eax,[esp].dsw_sf_eflag       ; Change stack frame to a VSF
        xchg    eax,[esp].dsw_sf_cs          ;
        xchg    eax,[esp].dsw_sf_eip         ;
        mov     [esp].dsw_sf_eflag,eax       ;

        EnterProc
        SSToDS  eax,dsw_lj                   ; Install Fault handler
        CCALL32 _TKCatchFault,<eax>          ;
        or      eax,eax                      ;
        jnz     dswx1                        ; If we faulted, just return

        push    es                           ;
        DosContext es,ax                     ;
        mov     ax,es:TaskNumber             ;
        mov     dsw_currTask,ax              ; Save current task number
        mov     bx,[ebp].dsw_sf_ss           ; Grab parms from user's R3 stack
        mov     es,bx                        ;  into local vars
    ASSUME ES:NOTHING                        ;
        mov     eax,[ebp].dsw_sf_esp         ;
        mov     ebx,dword ptr es:[eax]       ;
        mov     dsw_flags,ebx                ;
        mov     ebx,dword ptr es:[eax+4]     ;
        mov     dsw_pne,ebx                  ;
        pop     es                           ;
    ASSUME ES:FLAT                           ;

        mov     eax,dsw_flags                ; Validate flags parameter
        and     eax,not DSW_VALID_FLAGMASK   ;
        jnz     dswx                         ;  Jmp if invalid

        mov     ebx,dsw_pne                  ; Validate NE pointer parameter
        cmp     word ptr [ebx].ne_magic,"EN" ;
        jnz     dswx                         ;  Jmp if invalid

        movzx   esi,word ptr [ebx].ne_pWinFileStruc
        add     esi,ebx                      ; (ESI)=Pointer to winFileStruc
        movzx   ebx,byte ptr [esi].ne_cbModName
        sub     ebx,ne_pWinModName           ;
        mov     dsw_cbModName,ebx            ; Save size of mod name in bytes
        add     esi,ne_pWinModName           ; (ESI) = Pointer to mod name
        mov     dsw_pModName,esi             ;

        mov     eax,dsw_flags
        and     eax,DSW_VALID_FLAGMASK

        mov     dsw_j1,offset FLAT:dsw_loadSym ; JmpAddr, NESymStruc not found
        mov     dsw_j2,offset FLAT:dsw_linkSegTable1; JmpAddr, NESymStruc found
        cmp     eax,DSW_LINK_MAP             ; Check if linking map ?
        jz      dsw_findNE                   ;  Jmp if yes

        mov     dsw_j1,offset FLAT:dswx      ; JmpAddr, NESymStruc not found
        mov     dsw_j2,offset FLAT:dsw_findSegTable ; JmpAddr, NESymStruc found
        mov     dsw_j3,offset FLAT:dswie     ; JmpAddr, SegTable not found
        mov     dsw_j4,offset FLAT:dsw_unlink; JmpAddr, SegTable found
        cmp     eax,DSW_UNLINK_MAP           ; Check if unLinking map ?
        jz      dsw_findNE                   ;  Jmp if yes
        jmp     dswx

dsw_loadSym:
        mov     esi,dsw_pModName
        CALL16  GetSymName                   ; (ES:DI)  = sym file name
    ASSUME DS:NOTHING, ES:NOTHING
        jc      dswx

        SSToDS  esi,dsw_paddrsMap            ;
        mov     ecx,dsw_cbModName            ;
        add     ecx,(size NESymStruc)        ; (ECX) = header size
        push    ecx
        CALL16  DebugLoadSymDosFS            ; Load symbol file
        pop     ecx
    ASSUME DS:NOTHING, ES:NOTHING            ;  Jmp if error
        jc      dswx

        FlatContext <ds,es>,ax
        mov     ebx,[dsw_paddrsMap].AddrOff
        sub     ebx,ecx
        mov     [ebx].NE_pSegTable,0
        jmp     dsw_linkSegTable2

    ; EAX  = Pointer of NESymStruc to search

dsw_linkSegTable1:
        mov  dsw_j3,offset FLAT:dsw_linkSegTable2 ; JmpAddr, SegTable not found
        mov  dsw_j4,offset FLAT:dswie        ; JmpAddr, SegTable found
        jmp  dsw_findSegTable

dsw_linkSegTable2:
        mov     ebx,[dsw_pne]                ; (EBX) = pointer to NE struct
        movzx   ecx,[ebx].ne_cseg            ;
        mov     [dsw_cSegments],ecx          ;
        imul    ecx,(size SegDef)            ;
        add     ecx,(size SegTable)          ; (ECX) = segment table size

    ; Allocate memory for segTable

        xor     edx,edx
        CALLF32 DebAllocMem
        jc      dsw_freeMap                  ; exit if error
        mov     [dsw_pSegTable],esi

    ; Fill in SegTable

        mov     eax,[dsw_cSegments]          ; (EAX) = number of objects
        mov     [esi].GroupCount,ax          ; set group count
        lea     edi,[esi].SegDefs            ; (EDI) = segdef pointer
        mov     ebx,[dsw_pne]                ; (EBX) = pointer to ne struct
        movzx   esi,[ebx].ne_segtab          ; (ESI) = object/segment table
        add     esi,ebx                      ;
        xor     edx,edx                      ; (EDX) = segment number

dsw10:  inc     edx
        cmp     edx,[dsw_cSegments]
        ja      short dsw30

        mov     ax,SYM_TYPE_SEL
        stosw
        .errnz  SegDefType-0
        mov     ax,[esi].ns1_handle
        stosw
        .errnz  SegDefSel-2
        xor     ax,ax
        stosw
        .errnz  SegDefSeg-4
        mov     ax,dx                        ; (AX) = segment number
        stosw
        .errnz  SegDefSegNum-6
        add     esi,size new_seg1            ; next segment table entry
        jmp     short dsw10

dsw30:  cmp     [dsw_paddrsMap].AddrType,0   ; Sym file needs linking ?
        jnz     short dsw35                  ;  Jmp if yes
        mov     edi,[dsw_paddrsMap].AddrOff  ; (EDI) = Pointer to NESymStruc
        jmp     short dsw40                  ;

dsw35:  SSToDS  esi,dsw_paddrsMap            ; (ESI) = src
        mov     edi,[dsw_pSegTable]          ; (EDI) = dest
        mov     ecx,(size AddrS)             ; store map address in SegTable
        rep     movsb                        ;

        mov     dsw_j1,offset FLAT:dsw_freeMap ; JmpAddr for dsw_freeSegTable
        mov     esi,[dsw_pSegTable]          ; (ESI) = pSegTable
        mov     al,SYM_LINKMAP               ;
        CALL16  _Debug_Sym32                 ;
        pushf                                ; Save flags
        mov     ecx,dsw_cbModName            ;
        mov     eax,[dsw_paddrsMap].AddrOff  ; (EAX) = pMapDef
        mov     edi,eax                      ;
        sub     edi,ecx                      ;
        sub     edi,(size NESymStruc)        ; (EDI) = pNESymStruc
        mov     [dsw_paddrsMap].AddrOff,edi  ; Used in dsw_freeMap
        popf                                 ; Restore flags
        jc      short dsw_freeSegTable       ; Jmp if error while linking map

    ; Init, and Link NESymStruc's, SegTables

        or      [eax].MapFlags,MAP_FLAG_WINOS2; Indicate map is for WINOS2
        mov     [edi].NE_cbModName,cl        ; Set up mod name size in bytes
        mov     eax,edi                      ;
        mov     esi,dsw_pModName             ;
        add     edi,NE_pModName              ;
        rep     movsb                        ; copy file name to NESymStruc
        mov     edi,eax                      ;
        xchg    eax,NESymHead                ; link in this symbol map
        mov     [edi].NE_pNext,eax           ; save next symbol pointer
dsw40:  mov     esi,[dsw_pSegTable]          ; (ESI) = pSegTable
        mov     ebx,esi                      ; (EBX) = pSegTable
        mov     ax,dsw_currTask              ; Set curr task num
        mov     [esi].MapAddrS.AddrTask,ax   ;
        xchg    esi,[edi].NE_pSegTable       ; link in this seg table
        mov     [ebx].MapAddrS.AddrOff,esi   ; save next seg table pointer
        jmp     dswx                         ;

    ; ESI    = pSegTable to free
    ; dsw_j1 = Address of location to jump to

dsw_freeSegTable:
        CALLF32 DebFreeMem
        jmp     [dsw_j1]

    ; dsw_paddrsMap.AddrOff = pointer to NESymStruc to free

dsw_freeMap:
        mov     esi,[dsw_paddrsMap].AddrOff
        CALLF32 DebFreeMem
        jmp     dswx

    ; ESI,dsw_pModName = Pointer to mod name of target module
    ; dsw_cbModName    = Count in bytes of module name in ESI
    ; dsw_j1           = Address of location to jump to, if target not found
    ; dsw_j2           = Address of location to jump to, if target found

dsw_findNE:
        mov     eax,NESymHead                ; (ESI) = target mod name
        mov     ebx,offset FLAT:NESymHead    ;
dsw50:  or      eax,eax                      ; More NESymStruc's to check
        jnz     short dsw55                  ;  Jmp if yes
        jmp     [dsw_j1]                     ;
dsw55:  mov     edi,eax                      ;
        add     edi,NE_pModName              ; (EDI) = NESymStruc mod name
        mov     ecx,dsw_cbModName            ; (ECX) = cb of mod name in ESI
        repz    cmpsb                        ;
        or      ecx,ecx                      ; Are strings equal ?
        jz      short dsw60                  ;  Jmp if yes
        mov     ebx,eax                      ;
        mov     eax,[eax].NE_pNext           ; No - Check next NESymStruc
        mov     esi,dsw_pModName             ;
        jmp     short dsw50                  ;

    ; Zero dsw_paddrsMap.AddrType so sym file is not relinked, linking of sym
    ; files with multiple segTables is done by UpdateWinOS2Maps

dsw60:  mov     [dsw_paddrsMap].AddrType,0
        mov     [dsw_paddrsMap].AddrOff,eax
        jmp     [dsw_j2]

    ; EAX          = Pointer to current NESymStruc
    ; EBX          = Pointer to previous NESymStruc
    ; dsw_currTask = Task number of target seg table
    ; dsw_j3       = Address of location to jump to, if target not found
    ; dsw_j4       = Address of location to jump to, if target found

dsw_findSegTable:
        mov     esi,[eax].NE_pSegTable       ;
        mov     cx,dsw_currTask              ;
        mov     edi,eax                      ;
        add     edi,NE_pSegTable             ;
dsw65:  or      esi,esi                      ; More seg tables to check
        jnz     short dsw70                  ;  Jmp if yes
        jmp     [dsw_j3]                     ;
dsw70:  cmp     [esi].SegTable.MapAddrS.AddrTask,cx ; Seg table found
        jnz     short dsw75                  ;  Jmp if no
        jmp     [dsw_j4]                     ;
dsw75:  mov     edi,esi                      ;
        mov     esi,[esi].MapAddrS.AddrOff   ; Check next seg table
        jmp     short dsw65                  ;

    ; EAX = Pointer to current NESymStruc
    ; EBX = Pointer to previous NESymStruc
    ; ESI = Pointer to current segTable
    ; EDI = Pointer to previous segTable

dsw_unlink:
        mov     dsw_j1,offset FLAT:dswx      ; JmpAddr for dsw_freeSegTable
        mov     ecx,[esi].MapAddrS.AddrOff   ; Link segTables together
        mov     [edi].MapAddrS.AddrOff,ecx   ;
        mov     ecx,[eax].NE_pSegTable       ;
        or      ecx,ecx                      ; More seg tables exist
        jnz     dsw_freeSegTable             ;  Jmp if yes

        mov     dsw_j1,offset FLAT:dsw_freeMap ; JmpAddr for dsw_freeSegTable
        mov     ecx,[eax].NE_pNext           ; Link NESymStruc's together
        mov     [ebx].NE_pNext,ecx           ;
        movzx   edi,byte ptr [eax].NE_cbModName
        add     edi,(size NESymStruc)        ;
        add     edi,eax                      ; (EDI) = pMapAddrS
        mov     [esi].MapAddrS.AddrOff,edi   ;
        mov     [esi].MapAddrS.AddrType,SYM_TYPE_LIN
        mov     ebx,eax                      ;
        mov     al,SYM_UNLINKMAP             ; (ESI) = pSegTable
        CALL16  _Debug_Sym32                 ;
        mov     [dsw_paddrsMap].AddrOff,ebx  ; (EBX) = Pointer to NESymStruc
        jmp     dsw_freeSegTable             ;

dswx:   CCALL32 _TKClrFault                  ; Clear fault handler

dswx1:  LeaveProc
        mov     eax,[esp].dsw_sf_eflag       ; Restore original stack frame
        xchg    eax,[esp].dsw_sf_eip         ;
        xchg    eax,[esp].dsw_sf_cs          ;
        mov     [esp].dsw_sf_eflag,eax       ;
        KMExitKmodeVDM vpm,restore           ;
        add     esp,8                        ; Remove trapnum, and errcode
        popfd                                ;

dswx2:  RETFD
dswie:  Panic <"Debug_SymWinOS2: LINK: SegTable exists, UNLINK: SegTable not found">
EndProc   _Debug_SymWinOS2

;***    _Debug_ForceSymWinOS2 - Force unlinking of symbol files for WINOS2
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   EAX, EBX, ECX, EDX, ESI, EDI
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure _Debug_ForceSymWinOS2,near

LocalVar  fsw_pne,DWORD
LocalVar  fsw_currTask,WORD

        EnterProc
        push    es                           ;
        DosContext es,ax                     ;
        mov     dx,es:TaskNumber             ; DX = Current task number
        mov     fsw_currTask,dx              ;
        pop     es                           ;
    ASSUME ES:FLAT                           ;

        mov     eax,NESymHead                ;
        mov     ebx,offset FLAT:NESymHead    ;
fsw10:  mov     fsw_pne,eax                  ;
        or      eax,eax                      ; More NESymStruc's to check
        jz      short fswx                   ;  Jmp if no
        jmp     short fsw30                  ;

fsw15:  mov     dx,fsw_currTask              ; DX = Current task number

fsw20:  mov     eax,fsw_pne                  ;
        mov     ebx,eax                      ; (EBX) = point to prev NESymStruc
        mov     eax,[eax].NE_pNext           ; (EAX) = point to next NESymStruc
        jmp     short fsw10                  ; Loop

    ; EAX = Pointer to current NESymStruc
    ; EBX = Pointer to previous NESymStruc
    ; dx  = Task number of target seg table

fsw30:  mov     esi,[eax].NE_pSegTable       ;
        mov     edi,eax                      ;
        add     edi,NE_pSegTable             ;
fsw50:  or      esi,esi                      ; More seg tables to check
        jz      short fsw20                  ;  Jmp if no
        cmp     [esi].SegTable.MapAddrS.AddrTask,dx ; Seg table found
        jz      short fsw60                  ;  Jmp if yes
        mov     edi,esi                      ;
        mov     esi,[esi].MapAddrS.AddrOff   ; Check next seg table
        jmp     short fsw50                  ;

    ; EAX = Pointer to current NESymStruc
    ; EBX = Pointer to previous NESymStruc
    ; ESI = Pointer to current segTable
    ; EDI = Pointer to previous segTable

fsw60:  mov     ecx,[esi].MapAddrS.AddrOff   ; Link segTables together
        mov     [edi].MapAddrS.AddrOff,ecx   ;
        mov     ecx,[eax].NE_pSegTable       ;
        or      ecx,ecx                      ; More seg tables exist
        mov     ecx,0
        jnz     fsw_freeSegTable             ;  Jmp if yes

        mov     ecx,[eax].NE_pNext           ; Link NESymStruc's together
        mov     [ebx].NE_pNext,ecx           ;
        mov     fsw_pne,ebx                  ;
        movzx   edi,byte ptr [eax].NE_cbModName
        add     edi,(size NESymStruc)        ;
        add     edi,eax                      ; (EDI) = pMapAddrS
        mov     [esi].MapAddrS.AddrOff,edi   ;
        mov     [esi].MapAddrS.AddrType,SYM_TYPE_LIN
        mov     ecx,eax                      ; (ECX) = Pointer to NESymStruc
        mov     al,SYM_UNLINKMAP             ; (ESI) = pSegTable
        CALL16  _Debug_Sym32                 ;

    ; ESI = pSegTable to free
    ; ECX = pNESymStruc to free

fsw_freeSegTable:
        push    ecx
        CALLF32 DebFreeMem                   ; Freee SegTable
        pop     ecx                          ;
        or      ecx,ecx                      ; Free an NESymStruc ?
        jz      short fsw15                  ;  Jmp if no
        mov     esi,ecx                      ; (ESI) = Pointer to NESymStruc
        CALLF32 DebFreeMem                   ; Free NESymStruc
        jmp     short fsw15                  ;

fswx:   LeaveProc
        RETC
EndProc   _Debug_ForceSymWinOS2

;***LP  DebAllocMem - allocate memory for debugger
;
;       This function allocates memory for debugger.
;
;       ENTRY   (ECX) = size in bytes of allocation request
;               (EDX) = flag
;                       PAM_1M if physical memory below 1M needed
;                       0 otherwise
;
;       EXIT    Carry clear
;                   (ESI) = linear address of allocated memory
;               Carry set
;                   Error
;
;       USES    EAX, EBX, ECX, EDX, ESI, EDI, DS, ES, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

SYMALLOCF equ   (VMAC_ARENASYS + VMAC_LOCANY + VMAC_ALIGNPAGE + \
                PG_RESIDENT + PG_CONTIG + PG_R + PG_W)

Procedure DebAllocMem,far32,local

LocalVar  dsa_info,<SIZE vmac_s>        ; _VMAllocMem buffer

        EnterProc
        test    edx,PG_1M               ; low memory need?
        jnz     short dsa10             ;  yes, use VMAllocMem
        SSToDS  esi,[dsa_info]          ;  no, use the heap
        mov     eax,[hkrhSym]
        or      eax,eax
        stc
        jz      short dsax              ; fail call if no heap
        CCall   _VMAllocKHB, <eax, ecx, KDBSYMOWNER, PG_CONTIG + PG_16M, esi>
        mov     esi,[esi]               ; (ESI) = linear address
        cmp     eax,1                   ; set carry if no error
        .errnz  NO_ERROR
        cmc                             ; set carry if error
        jmp     short dsax

dsa10:  or      edx,SYMALLOCF           ; set flag bits
        SSToDS  esi,[dsa_info]
        xor     eax,eax
        .errnz  HOBNULL
        CCall   _VMAllocMem, <ecx, ecx, edx, eax, KDBSYMOWNER, eax, eax, eax, esi>
        cmp     eax,1                   ; set carry if no error
        .errnz  NO_ERROR
        cmc                             ; set carry if error
        jc      short dsax              ; exit if error
        mov     esi,[dsa_info].ac_va    ; (ESI) = linear address
        clc
dsax:   LeaveProc
        RETC
EndProc   DebAllocMem

;***LP  DebFreeMem - free memory for debugger
;
;       This function frees memory for debugger.
;
;       ENTRY   (ESI) = linear address
;
;       EXIT    NONE
;
;       USES    EAX, EBX, ECX, EDX, ESI, EDI, DS, ES, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

Procedure DebFreeMem,far32,local

LocalVar  khib,<size VMKHIB>                    ; Return structure for info

        EnterProc
        SSToDS  eax,[khib]
        CCall   _VMGetInfoKHB, <esi, eax>
        or      eax,eax                         ; is this a heap address?
        jnz     short dfm10                     ;  no, use VMFreeMem
        CCall   _VMFreeKHB, <[hkrhSym], esi>    ;  yes, use heap
        jmp     short dfmx

dfm10:  CCall   _VMFreeMem, <esi, HOBNULL, 0>
        or      eax,eax
        jnz     short dfmie
dfmx:   LeaveProc
        RETC
dfmie:  Panic   <"DebFreeMem: VMFree">
EndProc   DebFreeMem

HIGH32CODE ends

;        FARCODE HIGH2
;HIGH2CODE SEGMENT
        FARCODE HIGH3
HIGH3CODE SEGMENT

Procedure KDPLink,far16,local
        call    _KDPLink
        RETP
EndProc KDPLink

Procedure KDPUnlink,far16,local
        call    _KDPUnlink
        RETP
EndProc KDPUnlink

Procedure KDPEnable,far16,local
        call    _KDPEnable
        RETP
EndProc KDPEnable

;JWE start
Procedure KDPPageIn,far16,local
        call    _KDPPageIn
        RETP
EndProc KDPPageIn

;***    DebugThreadOneStarting
;
;       Handles notification when first thread of a task is starting
;
Procedure DebugThreadOneStarting,far16
        call    _KDPTaskNew
        RETP
EndProc DebugThreadOneStarting
;JWE end

;***    DebugThreadNDying
;
;       Cleans up when a thread is dying.  Special entry point for
;       thread 1.
;
;       Currently, the only cleanup work done is for breakpoints.
;       The old and new task numbers (or -1 to indicate that since thread
;       1 is dying, the BPs should be disabled) are passed in to the
;       debugger.
;
;       ENTRY:  NONE
;
;       EXIT:   NONE
;
;       USES:   AX, BX, EDX, DI, Flags
;
Procedure DebugThreadNDying,far16

        ASSUME DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:TASKAREA

        push    fs
        push    ebx
        mov     ebx,ss:[TKOPTDA].ptda_pTCBHead  ; (EBX)-> Thread 1's TCB
        FlatContext     fs,dx,NOASSUME
        movzx   edx,fs:[ebx].TCBNumber          ; (EDX) = new (th 1) slot
        pop     ebx
        pop     fs
        jmp     short dtod10

Entry DebugThreadOneDying,faronly
        call    _KDPTaskEnd    ; JWE
        mov     dx,TASK_DISABLE_BPS             ; (DX) = "DISABLE_BPs"

dtod10: push    ds
        DosContext ds
        mov     di,[TaskNumber]                 ; (DI) = old task number
        pop     ds
        mov     ax,TASK_CHANGE_TASKNUM          ; (AX) = fn 1, change BP task
        call    _Debug_Task                     ; call debugger tasking entry
        RETP

EndProc DebugThreadNDying

;***    DebugLoadSymDosFS - Loads a symbol file into memory
;
;       Uses the dos file system and doesn't call the debugger to
;       link it.
;
;       ENTRY:  (ESI) = flat pointer to put map address.
;               (ECX) = size of header to put on front of symbol segment
;               (ES:DI) = pointer to file name to load (asciiz).
;
;       EXIT:   'C' - File loaded successfully
;               'C' Set - Unable to load file.
;               Unable to allocate memory | file not found
;
;       USES:   Flags
;
        ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure DebugLoadSymDosFS,<near,far16>,local

LocalVar  lsy_paddrsMap,DWORD
LocalVar  lsy_cbHeader,DWORD
LocalVar  lsy_pMap,DWORD
LocalVar  lsy_cbFile,DWORD
LocalVar  lsy_sel,DWORD
LocalVar  lsy_hfile,WORD
LocalVar  lsy_pReadBuf,DWORD                                                ; p46737
LocalVar  lsy_readSize,DWORD                                                ; p46737

        EnterProc <esi,ecx>
        SaveReg <ds,es>
        pushad

;       Let's see if we can open the file for read only

        mov     ax,es
        mov     ds,ax
        mov     dx,di                   ; (DS:DX) = file name

        mov     di,sharing_deny_none+open_for_read  ; open file for read only
        mov     cx,exist_open+nexist_fail   ; OPEN, fail if does not exist
        mov     ah,attr_hidden+attr_system  ; AH = search attributes
        mov     al,OPCR_SATTR_DIRECT    ; set SAttrib directly
        xor     bx,bx                   ; set initial attributes to zero
        xor     si,si                   ; openmode2 = 0
        CALLFAR DoOpenCreate            ; call the worker function to open.
        jc      lsy40                   ; error (no file), so exit
        mov     [lsy_hfile],ax          ; (AX) = file handle, need for read.

;       Now let's determine the size of the file by seeking to the end.

        mov     bx,ax                   ; (BX) = file handle (for read)
        mov     ax,2                    ; seek relative to eof.
        mov     cx,0                    ; zero byte relative to the eof.
        mov     dx,0
        push    di
        push    si
        xor     di,di                   ; fake filehandle lockID lowword
        xor     si,si                   ; fake filehandle lockID highword
        CALLFAR w_LSeek                 ; DX:AX = size.
        pop     si
        pop     di
        jc      lsy20                   ; error in seeking, exit.
        shl     edx,16
        mov     dx,ax                   ; (EDX) = size
        mov     [lsy_cbFile],edx        ; save file size

        or      edx,edx                 ; zero length file?
        jz      lsy20                   ;  yes, exit

;       Now we must rewind the file, so seek to beginning.

        mov     bx,[lsy_hfile]          ; get the file handle.
        xor     ax,ax                   ; absolute position seek.
        xor     cx,cx                   ; zero offset from start of file.
        xor     dx,dx
        push    di
        push    si
        xor     di,di                   ; fake filehandle lockID lowword
        xor     si,si                   ; fake filehandle lockID highword
        CALLFAR w_LSeek                 ; rewind the file pointer.
        pop     si
        pop     di
        jc      lsy20                   ; error, so exit.

;       Now that we know the size, let's allocate memory for the file.

        FlatContext <ds,es>,ax
        mov     ecx,[lsy_cbFile]        ; (ECX) = file size
        add     ecx,[lsy_cbHeader]      ; (ECX) = file and header size
        add     ecx,(size SymMapHeader) ; (ECX) = file both header sizes
        xor     edx,edx                 ; (EDX) = no flags
        CALLF32 DebAllocMem
        jc      lsy20                   ; can't allocate memory error, exit.
        mov     [lsy_pMap],esi

        add     esi,[lsy_cbHeader]
        add     esi,(size SymMapHeader) ; (ESI) = map addr at end of headers
        mov     [lsy_pReadBuf],esi      ; save pointer to read buffer       ; p46737

;       Allocate temporary selector

lsy00:  mov     ecx,[lsy_cbFile]        ; count of bytes remaining to read  ; p46737
        cmp     ecx,0ffffh              ; jump, If count <= 64k-1           ; p46737
        jbe     short lsy02             ;                                   ; p46737
        mov     ecx,0ffffh              ; otherwise read size = 64K-1       ; p46737

lsy02:  mov     [lsy_readSize],ecx      ; save read size                    ; p46737
        mov     [lsy_sel],0             ; allocate a GDT selector
        SSToDS  eax,[lsy_sel]           ;
        CCALL32 _SELLdrDesc, <esi, ecx, eax>
        or      eax,eax                 ; jump, if error
        jnz     short lsy10             ;

;       Now let's read in the file.
;       Here we can only read in a max = 64k-1 at a time.

        mov     ds,[lsy_sel]            ;
        xor     edx,edx                 ; (DS:DX) = buffer address
        mov     ecx,[lsy_readSize]      ; (CX) = read size                  ; p46737
        mov     bx,[lsy_hfile]          ; (BX) = file handle
        push    di
        push    si
        push    bp                      ; since w_read trashes bp
        xor     si,si                   ; fake filehandlelockID lowword
        xor     di,di                   ; fake filehandlelockID highword
        CALLFAR w_Read                  ; have dos read in the file now
        pop     bp                      ; get our bp back first
        pop     si
        pop     di

;       Free temporary selector

        push    ax
        pushf
        FlatContext <ds,es>,ax
        CCALL32 _SELFreeGDT, <[lsy_sel]>
        popf
        pop     ax
        jc      short lsy10             ; jump if error from w_Read
        mov     ecx,[lsy_readSize]      ; (ECX) = Bytes requested           ; p46737
        cmp     ax,cx                   ; jump if bytes read != bytes requested ; p46737
        jne     short lsy10             ;                                   ; p46737
        mov     esi,[lsy_pReadBuf]      ; (ESI) = Pointer to read buffer    ; p46737
        add     esi,ecx                 ; update pointer                    ; p46737
        mov     [lsy_pReadBuf],esi      ; (ESI) = Pointer to read buffer    ; p46737
        sub     [lsy_cbFile],ecx        ; update bytes left to read         ; p46737
        jnz     lsy00                   ; jump, if more to read             ; p46737

        mov     eax,[lsy_pMap]
        add     eax,[lsy_cbHeader]      ; (EAX) = pointer to map
        mov     esi,[lsy_paddrsMap]     ; (ESI) = map address pointer
        mov     [esi].AddrOff,eax
        mov     [esi].AddrType,SYM_TYPE_LIN
        mov     [esi].AddrTask,0
        clc
        jmp     short lsy30

lsy10:  mov     esi,[lsy_pMap]          ; (ESI) = start of map
        CALLF32 DebFreeMem
lsy20:  stc

;       Now let's close the file since we're done with it.

lsy30:  pushf
        push    cx
        push    dx
        mov     bx,[lsy_hfile]          ; Move handle into bx for close.
        xor     cx,cx                   ; fake filehandlelockID lowword
        xor     dx,dx                   ; fake filehandlelockID highword
        CALLFAR w_Close                 ; Have dos close the file.
        pop     dx
        pop     cx
        popf

lsy40:  popad
        RestoreReg <es,ds>
        LeaveProc
        ret
EndProc    DebugLoadSymDosFS

;***    GetSymName - get symbol file name from name.
;
;       We copy the string to SymMapName, a temporary buffer in DOSGROUP.
;       As we do we lok for the last period after a '/' or '\'.
;       If we find one, we copy .sym over the last period, if not
;       we copy .sym to the end.
;
;       So c:\foo.aaa\bar.ext will become c:\foo.aaa\bar.sym
;       and c:\foo.aaa\bar will also become c:\foo.aaa\bar.sym
;
;       ENTRY:  (DS:ESI) = pointer to file name.
;
;       EXIT:   if carry clear,
;                       (ES:DI) = pointer to symbol file name.
;               if carry set,
;                       error - name too long.
;
;       USES:   AX, BX, CX, SI, DI, DS, ES, Flags
;
        ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure GetSymName,<near,faronly,far16>,local
        DosContext es           ; must be in 16 bit segment
        mov     edi,offset DOSGROUP:SymMapName
        mov     cx,SymMapNameLen
        push    di                      ; save start of sym file name

;       As we copy the name we use bx as a pointer to the last period copied.
;       If we find a slash, then we clear bx to indicate no valid period.
;       At the end of the search we check bx, if non zero, then it's
;       a valid period and we put the .sym there, else we copy .sym to the
;       end of the string.

        xor     bx,bx                   ; Initialise no '.' found
gsn1:   lods    byte ptr ds:[esi]
        db      67h, 90h                ; BUGBUG - nop with address override
        cmp     al,'.'                  ; Found a period?
        jne     short gsn2              ; No skip pointer save

; Here we found a period, save it's position in the string

        mov     bx,di                   ; (ES:BX) = ptr to last "." in string
        jmp     short gsn4              ; skip slash checks

;       Here it's not a period, see if we have a slash.

gsn2:   cmp     al,'\'                  ; Was it a backslash?
        je      short gsn3              ; Yes, jump
        cmp     al,'/'                  ; Forward slash?
        jne     short gsn4              ; No, skip

;       Here we have found a slash in the name, indicate no valid period
;       found yet

gsn3:   xor     bx,bx                   ; indicate no valid period

;       Store the character, and see if there are any more.

gsn4:   stosb                           ; copy string in buffer
        or      al,al                   ; at end of string?
        loopnz  short gsn1              ; no, continue

;       We either dropped through the loop because we found the terminating
;       null, or the name is too long. Check which.

        stc                             ; anitcipate error, name too long
        jcxz    short gsn7              ; jump if too long

;       See if we found a valid period (a period after the last slash) If
;       so, copy .sym over it, else copy .sym to the current position, the
;       end of the string.

        dec     di                      ; back di to terminating null
        or      bx,bx                   ; valid period found?
        jz      short gsn5              ; no, skip
        mov     di,bx                   ; (ES:DI) = ptr desination for .sym

gsn5:   FlatContext <ds>,ax
        mov     esi,offset FLAT:SymString
        mov     ecx,SymStringLen
        rep movs byte ptr es:[edi],byte ptr ds:[esi]
        db      67h, 90h                ; BUGBUG - nop with address override
        clc                             ; name ok
gsn7:   pop     di
        ret
EndProc   GetSymName

;HIGH2CODE ENDS
HIGH3CODE ENDS

        end
