windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/lddebug.asm
2020-09-26 16:20:57 +08:00

2275 lines
47 KiB
NASM

TITLE LDDEBUG - Debugger interface procedures
include kernel.inc
include newexe.inc
include tdb.inc
include protect.inc
include wow.inc
include dbgsvc.inc
include bop.inc
ifdef WOW
include vint.inc
endif
;.386p
HEAPDUMP = 0
DEBUGOFFSET equ 000FBH
INTOFFSET equ 4*3+2
DEBUGCALL MACRO
call MyDebugCall
ENDM
DataBegin
externW winVer
externW wDefRip
externB Kernel_Flags
externB Kernel_InDOS
externB fDW_Int21h
externW pGlobalHeap
externW hGlobalHeap
externD ptrace_dll_entry
externD lpfnToolHelpProc
externD pKeyboardSysReq
externW curTDB
externW wExitingTDB
externW <Win_PDB, topPDB>
ifdef WOW
externD FastBop
externW DebugWOW
externW hExeHead
if PMODE32
externW gdtdsc
endif; PMODE32
endif; WOW
debugseg dw 0
IF KDEBUG
externB fKTraceOut
ENDIF
DataEnd
ifdef WOW
externFP GetModuleFileName
externFP GetModuleHandle
externFP WOWOutputDebugString
externFP WOWNotifyTHHOOK
endif
ifdef FE_SB
; _TEXT code segment is over flow with debug 386 version
; GetOwnerName moves to _MISCTEXT from _TEXT segment with DBCS flag
externFP FarGetOwner
endif ; FE_SB
sBegin CODE
assumes CS,CODE
if pmode32
externNP get_arena_pointer32
else
externNP get_arena_pointer
endif
externNP GetOwner
externNP genter
externNP get_physical_address
externNP ValidatePointer
sEnd CODE
sBegin INITCODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING
;-----------------------------------------------------------------------;
; debuginit ;
; ;
; Returns a non zero value in AX if debugger is resident. ;
; If the debugger is present a distinquished string of "SEGDEBUG",0 ;
; will be found at 100H off of the interrupt vector segment (int 3). ;
; ;
; Arguments: ;
; None. ;
; ;
; Returns: ;
; AX =! 0 if debugger resident. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:03:51p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugInit,<PUBLIC,NEAR>,<es,si,di>
cBegin
CheckKernelDS
ReSetKernelDS
DebInt 4fh
cmp ax, 0F386h
jne short no_debugger
inc debugseg
or Kernel_flags[2],KF2_SYMDEB
no_debugger:
cEnd
;-----------------------------------------------------------------------;
; DebugDebug
;
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Tue 21-Jun-1988 13:10:41 -by- David N. Weise [davidw]
;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugDebug,<PUBLIC,NEAR>
cBegin nogen
push ds
SetKernelDS
ifdef WOW
call WOWNotifyTHHOOK
; Tell the debugger where it can poke around for kernel data structure info
mov cx, hGlobalHeap
mov dx, hExeHead
push DBG_WOWINIT
FBOP BOP_DEBUGGER,,FastBop
add sp,+2
else
test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
jz short dd_done
; Tell the debugger where it can poke around for kernel data structure info
push ax
push bx
push cx
push dx
mov bx,winVer
mov cx,dataOffset hGlobalHeap
mov dx,ds
DebInt 5ah
pop dx
pop cx
pop bx
pop ax
UnSetKernelDS
dd_done:
endif
pop ds
ret
cEnd nogen
;-----------------------------------------------------------------------;
; DebugSysReq
;
; tell the keyboard driver to pass sys req through
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Tue 19-Sep-1989 21:42:02 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugSysReq,<PUBLIC,NEAR>
cBegin nogen
CheckKernelDS
ReSetKernelDS
mov ax,debugseg
or ax,ax
jz short dwr_ret
cmp pKeyboardSysReq.sel,0 ; is there a keyboard driver?
jz short dwr_ret
mov ax,1 ; use int 2
cCall pKeyboardSysReq,<ax>
dwr_ret:
ret
cEnd nogen
sEnd INITCODE
ifdef FE_SB
sBegin MISCCODE
assumes CS,MISCCODE
else ; !FE_SB
sBegin CODE
assumes CS,CODE
endif ; !FE_SB
assumes DS,NOTHING
assumes ES,NOTHING
; Copyright (c) Microsoft Coropration 1989-1990. All Rights Reserved.
;
; Stolen from DOSX\DXBUG.ASM
;
; -------------------------------------------------------
; GENERAL SYMBOL DEFINITIONS
; -------------------------------------------------------
Debug_Serv_Int equ 41h ;WDEB386 service codes
DS_Out_Char equ 0
DS_Out_Symbol equ 0fh
; Find owner of 'sel', copy name to buffer, zero terminate name
; return count of chars copied, or 0.
cProc GetOwnerName,<PUBLIC,FAR>,<ds, si, di>
parmW obj
parmD buf
parmW buflen
cBegin
push [obj]
ifdef FE_SB
call FarGetOwner
else ; !FE_SB
call GetOwner
endif ; !FE_SB
or ax, ax
jz gon_exit
mov ds, ax ; DS:SI points to name
xor ax, ax
cmp word ptr ds:[0], NEMAGIC
jnz gon_exit
mov si, ds:[ne_restab]
lodsb ; get length
cmp ax, [buflen] ; name must be smaller than buf
jb @F
mov ax, [buflen]
dec ax
@@: mov cx, ax
cld
les di, [buf]
rep movsb
mov byte ptr es:[di], 0
gon_exit:
cEnd
ifdef FE_SB
sEnd MISCCODE
sBegin CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING
endif ; FE_SB
;******************************************************************************
;
; KOutputDebugStr
;
; Basically stolen from Windows/386 code by Ralph Lipe -- hacked up for
; 286 instead of 386. Here in RalphL's own words is the description:
;
; DESCRIPTION:
; The following code is not pretty but it does what it needs to. It will
; only be included in DEBUG versions of Kernel. It accepts an ASCIIZ
; string which it will output to the COM1 serial port. If the string
; contains #(Register) (for example #AX) then the value of that register
; will be output. It will not work for segment registers.
;
; If the string contains ?(Register)[:(Register)] (for example ?AX or
; ?AX:BX) then the value of the register(s) is passed to the debugger
; to display the label nearest to the given address. (It, also, will
; not work with segment registers. If ?AX is given, then the segment is
; assumed to be the DS data segment.
;
; Lower case register forces skip leading zeros.
;
; ENTRY:
; DS:SI -> ASCIIZ string
;
; EXIT:
; All registers and flags trashed
;
; ASSUMES:
; This procedure was called by the Trace_Out macro. It assumes that
; the stack is a pusha followed by a FAR call to this procedure.
;
;------------------------------------------------------------------------------
Reg_Offset_Table LABEL WORD ; Order of PUSHA
dw "DI"
dw "SI"
dw "BP"
dw "SP"
dw "BX"
dw "DX"
dw "CX"
dw "AX"
dw "SS"
dw "ES"
dw "DS"
dw "CS"
OSC1_ModName:
pop ax
OSC1_ModName1:
push es
mov es, ax
cmp word ptr es:[0], NEMAGIC
jz @F
pop es
jmps is_pdb
@@: mov cx, es:[ne_restab]
inc cx ; skip length byte
pop es
jmp Show_String ; AX:CX -> string to print
OSC1_FileName:
pop ax
push es
mov es, ax
mov cx, word ptr es:[ne_crc+2]
add cx, 8
pop es
jmp Show_String
szUnk db 'Unknown',0
OSC1_OwnerName:
pop ax
push ds
push ax
cCall GetOwner ; seg value already on stack
pop ds
or ax, ax
jnz OSC1_ModName1
is_pdb: mov ax, cs
mov cx, CodeOffset szUnk
jmp Show_String
OSC1_Custom:
call Get_Register
jnc short OSC1_not_special
or ax, ax
jz short OSC1_not_special
push ax
lodsb
cmp al, '0'
jz short OSC1_ModName
cmp al, '1'
jz short OSC1_FileName
cmp al, '2'
jz short OSC1_OwnerName
pop ax
jmps OSC1_not_special
public KOutDebugStr
KOutDebugStr proc far
push bp
mov bp, sp ; Assumes BP+6 = Pusha
sub sp, 84 ; local 80 char line + count
odslen equ word ptr [bp-2]
odsbuf equ byte ptr [bp-82]
odszero equ word ptr [bp-84] ; flag - true if skip leading zero
odsflag equ word ptr [bp-86] ; last local var - from pushf
mov odslen, 0
pushf
push es
push cs ; Address our own data seg
pop es
assumes ds,NOTHING
assumes es,code
cld
FCLI
OSC1_Loop:
lodsb ; Get the next character
test al, al ; Q: End of string?
jz short OSC1_Done ; Y: Return
push codeoffset OSC1_Loop
cmp al, "#" ; N: Q: Special register out?
je SHORT OSC1_Hex ; Y: Find out which one
cmp al, "?" ; Q: special label out?
je short OSC1_Label ; Y: find out which one
cmp al, "@" ; Q: special string out?
je short OSC1_Str
cmp al, "%" ; Custom value?
je short OSC1_Custom
OSC1_out:
xor ah, ah ; N: Send char to COM
jmp Out_Debug_Chr
OSC1_Hex:
call Get_Register
jnc short OSC1_not_special
or bh, bh ; Q: Word output?
jz SHORT OSC1_Out_Byte ; N: display byte
OSC1_Out_Word:
jmp Out_Hex_4_test ; Display AX in hex
OSC1_Out_Byte:
xchg al, ah ; swap bytes to print just
jmp Out_Hex_2_test ; the low one!
OSC1_Label:
call Get_Register
jc short show_label
OSC1_not_special:
lodsb ; Get special char again
jmp OSC1_out ; display it, and continue
show_label:
mov cx, ax ; save first value
cmp byte ptr [si], ':' ;Q: selector separator?
jne short flat_offset ; N:
lodsb ; Y: eat the ':'
call Get_Register ; and attempt to get the selector
jc short sel_offset
flat_offset:
mov ax, cs ; default selector value
sel_offset:
jmp Show_Near_Label
OSC1_Str:
call Get_Register
jnc short OSC1_not_special
mov cx,ax
cmp byte ptr [si],':'
jne short no_selector
lodsb
push cx
call Get_Register
pop cx
xchg ax,cx
jc short got_sel_off
mov cx,ax
no_selector:
mov ax,ds ; default selector for strings
got_sel_off:
jmp Show_String
OSC1_Done: ; The end
xor ax, ax ; flush buffer
call Out_Debug_Chr
pop es
if pmode32
test odsflag, 200h
jz short @F
FSTI
@@:
endif
popf
leave
ret
KOutDebugStr endp
;******************************************************************************
;
; Get_Register
;
; DESCRIPTION:
;
; ENTRY:
;
; EXIT: Carry set if register value found
; AX = register value
; BL = value size (1, 2, 4) (no longer true - donc)
;
; USES:
;
;==============================================================================
Get_Register proc near
lodsw ; get next pair of letters
mov bx, ax
and bx, 2020h
mov [odszero], bx
and ax, 0dfdfh ; to upper case
xchg ah, al ; normal order (or change table?)
or bx, -1 ; BH = -1
cmp al, 'L' ; Q: "L" (ie AL, BL, etc)?
jne short @F ; N: word reg
mov al, 'X' ; Y: change to X for pos match
inc bh ; BH now 0 - will clear AH below
@@:
xor di, di ; DI = 0
mov cx, 12 ; Size of a pusha + 4 seg regs
OSC1_Special_Loop:
cmp ax, Reg_Offset_Table[di] ; Q: Is this the register?
je SHORT OSC1_Out_Reg ; Y: Output it
add di, 2 ; N: Try the next one
loop OSC1_Special_Loop ; until CX = 0
sub si, 3 ; restore pointer, clear carry
ret
OSC1_Out_Reg:
mov ax, SS:[bp.6][di] ; AX = Value to output
and ah, bh ; if xL, zero out high byte
stc
ret
Get_Register endp
;******************************************************************************
;
; Out_Hex_Word
;
; Outputs the value in AX to the COM port in hexadecimal.
;
;------------------------------------------------------------------------------
Out_Hex_2_test: ; Write two chars
xor ah, ah
cmp [odszero], 0 ; skip leading 0's?
je Out_Hex_2 ; no, show 2 chars
; yes, fall through
Out_Hex_4_test:
cmp [odszero], 0
je Out_Hex_4
test ax, 0fff0h
jz Out_Hex_1
test ah, 0f0h
jnz Out_Hex_4
test ah, 0fh
jz Out_Hex_2
Out_Hex_3:
xchg al, ah
call Out_Hex_1
xchg al, ah
jmps Out_Hex_2
Out_Hex_4:
xchg al, ah
call Out_Hex_2
xchg al, ah
Out_Hex_2:
push ax
shr ax, 4
call Out_Hex_1
pop ax
Out_Hex_1:
push ax
and al, 0fh
cmp al, 10
jb @F
add al, '@'-'9'
@@: add al, '0'
call Out_Debug_Chr
pop ax
ret
;******************************************************************************
;
; Out_Debug_Chr
;
; DESCRIPTION:
;
; ENTRY:
; AL contains character to output
;
; EXIT:
;
; USES:
; Nothing
;
;==============================================================================
Out_Debug_Chr proc near
push di
mov di, odslen
mov odsbuf[di], al ; store in buffer (in stack)
or al, al
jz short odc_flushit ; if null, flush buffer
inc odslen
cmp di, 79 ; if full, flush buffer
jnz short odc_ret
odc_flushit:
mov odsbuf[di], 0 ; null terminate string
lea di, odsbuf
ifdef WOW
cCall <far ptr DebugWrite>,<ssdi,odslen>
else
cCall DebugWrite,<ssdi,odslen>
endif
mov odslen, 0
odc_ret:
pop di
ret
Out_Debug_Chr endp
;******************************************************************************
;
; Show_Near_Label
;
; DESCRIPTION: call the debugger to display a label less than or equal
; to the given address
;
; ENTRY: AX is selector, CX is offset of address to try to find
; a symbol for
; ES selector to DOSX data segment
; EXIT:
;
; USES:
;
;==============================================================================
Show_Near_Label proc near
push ax ;on a 286, use 16 bit regs
push bx
push cx
mov bx,cx
mov cx,ax
mov ax,DS_Out_Symbol
int Debug_Serv_Int
pop cx
pop bx
pop ax
ret
Show_Near_Label endp
;******************************************************************************
;
; Show_String
;
; DESCRIPTION: Display an asciiz string
;
; ENTRY: AX is selector, CX is offset of address to find string
;
; EXIT:
;
; USES:
;
;==============================================================================
Show_String proc near
push ax
push ds
push si
mov ds,ax
mov si,cx
xor ax,ax
cmp byte ptr ds:[si], ' '
jbe pascal_show_string
@@:
lodsb
or al,al
jz short @f
call Out_Debug_Chr
jmp short @b
@@:
pop si
pop ds
pop ax
ret
pascal_show_string:
push cx
lodsb
mov cl, al
xor ch, ch
pss_1: lodsb
call Out_Debug_Chr
loop pss_1
pop cx
jmps @B
Show_String endp
; END OF DXBUG STUFF
;-----------------------------------------------------------------------;
; CVWBreak
;
; This is part of the tortuous path from a Ctrl-Alt-SysReq to
; CVW. In RegisterPtrace we tell the keyboard driver to jump
; here if Ctrl-Alt_SysReq is done.
;
; Entry:
; none
;
; Returns:
;
; Registers Destroyed:
; none
;
; History:
; Mon 17-Jul-1989 14:34:21 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc CVWBreak,<PUBLIC,FAR>
cBegin nogen
push ax
push di
push ds
SetKernelDS
test Kernel_flags[2],KF2_PTRACE
jz short call_WDEB
cmp Kernel_InDOS,0 ; not in DOS we don't
jnz short TVC15_exit
if pmode32
.386p
push fs ; save current FS for debuggers
.286p
endif
call genter ; sets FS to kernel data seg
UnSetKernelDS
if pmode32
.386p
pop fs
.286p
endif
dec [di].gi_lrulock
jz short call_PTrace
or [di].gi_flags,GIF_INT2
jmps TVC15_exit
call_PTrace:
SetKernelDS
cmp ptrace_DLL_entry.sel,0
jnz short yes_CVW
;** This is the only case where WINDEBUG gets first dibs something.
;* Since we have no way of knowing if TOOLHELP wants the
;** CtlAltSysRq, we always give it to CVW if it's there.
test Kernel_Flags[2],KF2_TOOLHELP
jz SHORT call_WDEB
mov ax,SDM_INT2 ;Notification number
call lpfnToolHelpProc ;Give it to TOOLHELP
jmp SHORT TVC15_exit
;** Give it to the kernel debugger
call_WDEB:
pop ds
UnSetKernelDS
pop di
pop ax
int 1
iret
;** Give it to CVW
yes_CVW:
ReSetKernelDS
mov ax,SDM_INT2
call ptrace_DLL_entry
TVC15_exit:
pop ds
UnSetKernelDS
pop di
pop ax
iret
cEnd nogen
;-----------------------------------------------------------------------;
; DebugDefineSegment ;
; ;
; Informs debugger of physical address and type of a segment for the ;
; named module, that is informed of segment index and corresponding ;
; name and physical segment. ;
; ;
; Arguments: ;
; ModName - Long pointer to module name. ;
; SegNumber - zero based segment index ;
; LoadedSeg - Physical seg address assigned by user to index. ;
; InstanceNumber - Windows instance number bound to physical seg.;
; DataOrCodeFlag - Whether segment is code or data. ;
; ;
; Returns: ;
; None. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:20:52p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
default_buf_size equ 130
cProc DebugDefineSegment,<PUBLIC,NEAR>,<es>
Parmd ModName
Parmw SegNumber
Parmw LoadedSeg
Parmw InstanceNumber
Parmw DataOrCodeFlag
localV modBuf,default_buf_size
localV nameBuf,default_buf_size
cBegin
SetKernelDS es
test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
jz short setdone
push bx
push cx
push dx
push si
push di
les di, ModName
UnSetKernelDS es
mov bx, SegNumber
mov cx, LoadedSeg
mov dx, InstanceNumber
mov si, DataOrCodeFlag
mov ax,SDM_LOADSEG
DEBUGCALL
pop di
pop si
pop dx
pop cx
pop bx
setdone:
ifdef WOW
SetKernelDS es
test es:DebugWOW,DW_DEBUG
jnz @f
jmp dd_no_wdebug
UnSetKernelDS es
@@:
push ds
push bx
push cx
push dx
push si
push di
lds si, ModName
mov cx,ds:[ne_magic]
cmp cx,NEMAGIC
jz @f
jmp not_yet
@@: mov cx,ss
mov es,cx
lea di,modBuf
xor cx,cx
mov cl,byte ptr [si-1] ; Get length byte
cmp cx,default_buf_size
jl @f
mov cx,default_buf_size-1
@@:
rep movsb ; Copy the string
xor ax,ax
stosb
mov si,ds:[ne_pfileinfo]
mov cl,ds:[si].opLen
sub cx,opFile
lea si,[si].opFile
lea di,nameBuf
cmp cx,default_buf_size
jl @f
mov cx,default_buf_size-1
@@:
rep movsb ; Copy the string
stosb
SetKernelDS es
push DataOrCodeFlag
lea si,nameBuf
push ss
push si
lea si,modBuf
push ss
push si
push SegNumber
push LoadedSeg
push DBG_SEGLOAD
IFE PMODE
BOP BOP_DEBUGGER
ELSE
FBOP BOP_DEBUGGER,,FastBop
ENDIF
add sp,+16
not_yet:
pop di
pop si
pop dx
pop cx
pop bx
pop ds
UnSetKernelDS
dd_no_wdebug:
endif
cEnd
;-----------------------------------------------------------------------;
; DebugMovedSegment ;
; ;
; Informs debugger of the old and new values for a physical segment. ;
; ;
; Arguments: ;
; SourceSeg - Original segment value. ;
; DestSeg - New segment value. ;
; ;
; Returns: ;
; None. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:29:15p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
cProc DebugMovedSegment,<PUBLIC,NEAR>
ParmW SourceSeg
ParmW DestSeg
cBegin
cEnd
;-----------------------------------------------------------------------;
; DebugFreeSegment ;
; ;
; Informs debugger that a segment is being returned to the global ;
; memory pool and is no longer code or data. ;
; ;
; Arguments: ;
; SegAddr - segment being freed ;
; fRelBP - flag indicating if breakpoints should be released, ;
; -1 means yes ;
; ;
; Returns: ;
; None. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:34:13p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc DebugFreeSegment,<PUBLIC,NEAR>,<es>
Parmw SegAddr
parmW fRelBP
cBegin
push ds
SetKernelDS
ifdef WOW
test DebugWOW,DW_DEBUG
jz df_no_wdebug
push SegAddr ; Notify the Win32 debugger that
push fRelBP
mov ax,DBG_SEGFREE ; the selector number needs to be freed
push ax
IFE PMODE
BOP BOP_DEBUGGER
ELSE
FBOP BOP_DEBUGGER,,FastBop
ENDIF
add sp,+6
df_no_wdebug:
endif
test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
pop ds
UnSetKernelDS
jz short killdone
mov bx, SegAddr
mov ax, SDM_FREESEG
inc fRelBP
jnz short @f
mov ax, SDM_RELEASESEG ;free but pulls out breakpoints 1st
@@:
DEBUGCALL
killdone:
cEnd
;-----------------------------------------------------------------------;
; DebugWrite ;
; ;
; Prints the given string of the given length. If a debugger is ;
; present tells the debugger to print the message. Otherwise uses ;
; DOS Function 40h to the con device. ;
; ;
; Arguments: ;
; lpBuf long pointer to string to write ;
; nBytes # of bytes in string ;
; ;
; Returns: ;
; None. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:53:08p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
ifdef WOW
cProc DebugWrite,<PUBLIC,FAR>,<ds,si>
else
cProc DebugWrite,<PUBLIC,NEAR>,<ds,si>
endif
parmD lpBuf
parmW nBytes
localW wHandled
localW SavePDB
cBegin
;** Validate the pointer and number of bytes
mov ax,WORD PTR lpBuf[0]
add ax,nBytes
jnc SHORT @F
jmp DW_End ;Overflow: error
@@:
if pmode32
.386
push eax ; 32 bit ValidatePointer destroys top half
push ecx ; of eax, ecx which isn't nice in debug outs
.286
endif
push WORD PTR lpBuf[2]
push ax
call ValidatePointer ;Make sure pointer is OK
or ax,ax
if pmode32
.386
pop ecx
pop eax
.286
endif
jnz SHORT @F
jmp DW_End ;Bogus pointer: just return.
@@: mov cx,nBytes
lds dx,lpBuf ;DS:DX points to string
or cx,cx ;Zero length requires computing
jnz SHORT DW_GoodLen
;** Compute string length if a valid length not passed in
mov si,dx
cld
DW_LenLoop:
lodsb
or al,al
jnz short DW_LenLoop
mov cx,si
sub cx,dx
dec cx
DW_GoodLen:
;** Set up for the Int 41h, PTrace, and TOOLHELP interfaces
mov wHandled,0 ;Flag that we haven't handled yet
mov si,dx ;Point to string with DS:SI
push ds ; and ES:SI
pop es
;** Decide which debugger (if any) to send string to
push ds
SetKernelDS
test Kernel_Flags[2],KF2_SYMDEB ;WDEB386 loaded?
pop ds
UnSetKernelDS
jz SHORT DW_TryToolHelp ;No, now try TOOLHELP
;** Send to WDEB386
push si
DebInt SDM_CONWRITE
pop si
mov wHandled,1 ;Assume that WDEB386 handled it
;** Send it to TOOLHELP if it is there
DW_TryToolHelp:
push ds
SetKernelDS
test Kernel_Flags[2],KF2_TOOLHELP ;ToolHelp around?
pop ds
UnSetKernelDS
jz SHORT DW_TryPTrace ;Nope, now try PTrace
push ds
SetKernelDS
push Win_PDB ;Save current PDB
cmp curTDB,0
jz @F
push es ; and set to current task's PDB
mov es,curTDB ; for toolhelp call.
push es:[TDB_PDB]
pop ds:Win_PDB
pop es
@@:
mov ax,SDM_CONWRITE ;Notification ID
call lpfnToolHelpProc ;String in ES:SI for TOOLHELP
pop Win_PDB ;Restore current PDB
or ax,ax ;TOOLHELP client say to pass it on?
pop ds
UnSetKernelDS
jnz SHORT DW_End ;No, we're done
;** Handle PTrace
DW_TryPTrace:
SetKernelDS es
cmp WORD PTR es:ptrace_dll_entry[2],0 ;WINDEBUG.DLL lurking around?
jz SHORT DW_WriteToCOM ;No, try COM port
;** If we're exiting a task, don't send the debug write to PTrace.
;** This is a gross hack for QCWin who chokes on these. These
;** were being sent because of parameter validation errors.
push ax ;Temp reg
mov ax,es:curTDB
cmp ax,es:wExitingTDB
pop ax
je DW_WriteToCOM ;Write out directly
IF KDEBUG
;** If we're sending a KERNEL trace out, we don't want to send this
;** to PTrace, either
cmp fKTraceOut, 0 ;Are we doing a KERNEL trace out?
jne DW_WriteToCOM ;Yes, don't call PTrace
ENDIF
;** Now send to PTrace
mov wHandled,1 ;Assume WINDEBUG handles if present
push ax ;Save regs PTrace might trash
push si
push dx
push ds
push es
mov ax,SDM_CONWRITE ;Notification ID
call es:ptrace_DLL_entry ;Do the PTrace thing
pop es
pop ds
pop dx
pop si
pop ax
;** Write string to debug terminal
DW_WriteToCOM:
cmp wHandled,0 ;Handled?
jnz SHORT DW_End ;Yes
inc es:fDW_Int21h ; Skip it if user has canceled
jnz SHORT DW_Skip_Write ; a crit error on this before
mov ax, es:topPDB
xchg es:Win_PDB, ax ; Switch to Kernel's PDB,
mov SavePDB, ax ; saving current PDB
ifdef WOW
cCall WOWOutputDebugString,<lpBuf>
else
mov bx,3 ;Send to DOS AUX port
mov ah,40h
int 21h
endif; WOW
mov ax, SavePDB
mov es:Win_PDB, ax ; restore app pdb
DW_Skip_Write:
dec es:fDW_Int21h
DW_End:
UnSetKernelDS
UnSetKernelDS es
cEnd
;-----------------------------------------------------------------------;
; OutputDebugString ;
; ;
; A routine callable from anywhere since it is exported. It calls ;
; DebugWrite to do its dirty work. ;
; ;
; Arguments: ;
; lpStr long pointer to null terminated string ;
; ;
; Returns: ;
; none ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; all ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Tue June 28, 1988 -by- Ken Shirriff [t-kens] ;
; Made it save all the registers. ;
; ;
; Thu Nov 13, 1986 02:54:36p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc OutputDebugString,<PUBLIC,FAR,NODATA>,<es>
parmD lpStr
cBegin
pusha
ifdef WOW
cCall <far ptr DebugWrite>,<lpStr, 0>
else
cCall DebugWrite,<lpStr, 0>
endif
popa
cEnd
;-----------------------------------------------------------------------;
; DebugRead ;
; ;
; Gets a character from either the debugger (if one is present) or ;
; from the AUX. ;
; ;
; Arguments: ;
; none ;
; ;
; Returns: ;
; AL = character ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Nov 13, 1986 02:55:09p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc DebugRead,<PUBLIC,NEAR>
cBegin nogen
push ds
SetKernelDS
;** Send it to the debugger(s) FIRST
mov ax,SDM_CONREAD ;Get the notification ID
; This sure is weird! Goal is to ask if WDEB386 has a char
; available. If so, return.
; We do the check here because MyDebugCall assumes INT41
; doesn't modify registers, but the CONREAD call does.
; This was hosing TOOLHELP, since we were passing a different
; function to TOOLHELP based on what char a user was pressing.
test Kernel_Flags[2],KF2_SYMDEB ; WDEB386 loaded?
jz short dr_symdeb ; no - MyDebugCall
DebInt ; Yes - read CON
cmp ax, SDM_CONREAD
jnz @F ; got a response - continue.
dr_symdeb:
DEBUGCALL
@@:
;** See if we should still hand it to the AUX port
cmp al,SDM_CONREAD ;If not changed, we didn't get a character
jne SHORT DR_End
mov ax, wDefRIP ;Do we have a default value to use?
or ax, ax
jnz DR_End
xor cx,cx ;Allocate WORD to read into
push cx
mov dx,sp ;Point with DS:DX
push ss
pop ds
inc cx ;Get one byte
DR_ConLoop:
ifdef WOW
int 3 ; BUGBUG mattfe 29-mar-92, should be thunked to 32 bit side.
endif
mov bx,3 ;Use AUX
mov ah,3fh ;Read device
int 21h ;Call DOS
cmp ax,cx ;Did we get a byte?
jne SHORT DR_ConLoop ;No, try again
pop ax ;Get the byte read
DR_End:
pop ds
ret
cEnd nogen
;-----------------------------------------------------------------------;
; DebugDefineLine ;
; ;
; Notifies debugger of the location of The Line. ;
; ;
; Arguments: ;
; None ;
; ;
; Returns: ;
; None ;
; ;
; Registers Destroyed: ;
; ;
; History: ;
; Mon 20-Jun-1988 13:17:41 -by- David N. Weise [davidw] ;
; Moved it here. ;
;-----------------------------------------------------------------------;
;
; assumes ds,nothing
; assumes es,nothing
;
;cProc DebugDefineLine,<PUBLIC,NEAR>
;
;cBegin nogen
; ret
;cEnd nogen
;
;cProc FarDebugNewTask,<PUBLIC,FAR>
;
;cBegin nogen
; call DebugNewTask
; ret
;cEnd nogen
;
;
;-----------------------------------------------------------------------;
; DebugNewTask ;
; ;
; ;
; Arguments: ;
; AX = EMS PID ;
; ;
; Returns: ;
; None ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
;-----------------------------------------------------------------------;
;
;cProc DebugNewTask,<PUBLIC,NEAR>
;
;cBegin nogen
; ret
;cEnd nogen
;
;cProc FarDebugFlushTask,<PUBLIC,FAR>
;
;cBegin nogen
; call DebugFlushTask
; ret
;cEnd nogen
;
;-----------------------------------------------------------------------;
; DebugFlushTask ;
; ;
; ;
; Arguments: ;
; AX = EMS PID ;
; ;
; Returns: ;
; None ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
;-----------------------------------------------------------------------;
;
;cProc DebugFlushTask,<PUBLIC,NEAR>
;
;cBegin nogen
; ret
;cEnd nogen
;-----------------------------------------------------------------------;
; DebugSwitchOut ;
; ;
; ;
; Arguments: ;
; DS = TDB ;
; ;
; Returns: ;
; None ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; All ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
;-----------------------------------------------------------------------;
cProc DebugSwitchOut,<PUBLIC,NEAR>
cBegin nogen
push ds
SetKernelDS
test Kernel_Flags[2],KF2_PTRACE
pop ds
UnSetKernelDS
jz short dso_done
push ax
mov ax,SDM_SWITCHOUT
DEBUGCALL
pop ax
dso_done:
ret
cEnd nogen
;-----------------------------------------------------------------------;
; DebugSwitchIn ;
; ;
; ;
; Arguments: ;
; DS = TDB ;
; ;
; Returns: ;
; None ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; All ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
;-----------------------------------------------------------------------;
cProc DebugSwitchIn,<PUBLIC,NEAR>
cBegin nogen
push ds
SetKernelDS
test Kernel_Flags[2],KF2_PTRACE
pop ds
UnSetKernelDS
jz short dsi_done
push ax
mov ax,SDM_SWITCHIN
DEBUGCALL
pop ax
dsi_done:
ret
cEnd nogen
;-----------------------------------------------------------------------;
; DebugExitCall
;
; Notifies the debugger than an app is quitting. This gets
; called at the top of ExitCall.
;
; Entry:
;
; Returns:
;
; Registers Preserved:
; all
;
; History:
; Thu 11-May-1989 08:58:40 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugExitCall,<PUBLIC,NEAR>
cBegin nogen
;
; Windebug knows where this is. See MyDebugCall() comment.
;
ifdef WOW
push ds
SetKernelDS
test DebugWOW,DW_DEBUG
jz de_no_wdebug
push ax
push es
mov es,bx ; Get the current TDB
push es ; hTask
mov ax,es:[TDB_pModule] ; Get the module handle
mov es,ax
push es ; hModule
push es ; Pointer to module name
push es:ne_restab
push es ; Pointer to module path
push word ptr es:ne_crc+2
mov ax,DBG_TASKSTOP ; the selector number needs to be freed
push ax
FBOP BOP_DEBUGGER,,FastBop
add sp,+14
pop es ; Restore original ES
pop ax
de_no_wdebug:
pop ds
UnSetKernelDS
endif
push ax
mov bl,al ;Exit code in BL
mov ax,SDM_EXITCALL
DEBUGCALL
pop ax
ret
cEnd nogen
;-----------------------------------------------------------------------;
; FarDebugDelModule
;
; Notifies the debugger than a module is being deleted. This gets
; called at the top of ExitCall.
;
; Entry:
; ES = module handle
;
; Returns:
;
; Registers Reserved:
; all
;
; History:
; Mon 11-Sep-1989 18:34:06 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc FarDebugDelModule,<PUBLIC,FAR>
ifdef WOW
localV nameBuf,130
localV ModName,64
endif
cBegin nogen
push es
ifdef WOW
push ds
push es
SetKernelDS
test DebugWOW,DW_DEBUG
jnz @f
jmp fdd_no_wdebug
@@: push di
push si
push cx
xor cx,cx
mov ax,es
mov ds,ax
mov si,es:[ne_restab]
mov cl,[si]
inc si
cmp cl,64
jb @f
mov cl,63
@@:
mov ax,ss
mov es,ax
lea di,ModName
rep movsb ; Copy module name from resource
mov byte ptr es:[di],0 ; table and null terminate it
mov ax,ds
mov es,ax
lea di,nameBuf
push ax
push ss
push di
mov ax, 130
push ax
call GetModuleFileName
SetKernelDS
lea di,nameBuf
push ss
push di
lea di,ModName
push ss
push di
push DBG_MODFREE
IFE PMODE
BOP BOP_DEBUGGER
ELSE
FBOP BOP_DEBUGGER,,FastBop
ENDIF
add sp,+10
pop cx
pop si
pop di
fdd_no_wdebug:
pop es
pop ds
UnSetKernelDS
endif; WOW
mov ax,SDM_DELMODULE
DEBUGCALL
add sp,2
ret
cEnd nogen
;-----------------------------------------------------------------------;
; void DebugLogError(WORD err, VOID FAR* lpInfo);
;
; Notifies debugger of a LogError() call.
;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugLogError,<PUBLIC,NEAR>
;ParmW err
cBegin nogen
pop ax
pop bx ; dx:bx = lpInfo
pop dx
pop cx ; cx = error code
push ax
mov ax,SDM_LOGERROR
jmp short MyDebugCall
cEnd nogen
;-----------------------------------------------------------------------;
; void DebugLogParamError(VOID FAR* param, FARPROC lpfn, WORD err);
;
; Notifies debugger of a LogParamError() call.
;
; NOTE: the parameters are passed in the REVERSE order than expected,
; so that the stack layout is natural when we do the DebugCall.
;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc DebugLogParamError,<PUBLIC,NEAR>
;ParmD param
;ParmD lpfn
;ParmW err
cBegin nogen
;
; es:bx = pointer to struct containing args
;
mov bx,sp
add bx,2 ; point past return addr.
push ss
pop es
mov ax,SDM_LOGPARAMERROR
call MyDebugCall
ret 2+4+4
cEnd nogen
;------------------------------------------------------------------------
;
; MyDebugCall
;
; Call the debugger interface. Created to reduce references to kernel
; data segment.
;
;------------------------------------------------------------------------
assumes ds,nothing
assumes es,nothing
cProc MyFarDebugCall, <FAR,PUBLIC>
cBegin nogen
cCall MyDebugCall
retf
cEnd nogen
cProc MyDebugCall,<NEAR,PUBLIC>
cBegin nogen
push ds
SetKernelDS
test Kernel_Flags[2],KF2_SYMDEB
jz short no_symdeb
cmp ax,SDM_SWITCHOUT ; Don't give these to WDEB.
je no_symdeb
cmp ax,SDM_SWITCHIN
je no_symdeb
pop ds ; Too bad some Int 41h services
UnSetKernelDS ; require segment reg params
DebInt
push ds
SetKernelDS
no_symdeb:
;** Check for TOOLHELP's hook. We always send it here first
;** This callback does NOT depend on what's on the stack.
test Kernel_Flags[2],KF2_TOOLHELP ;TOOLHELP hook?
jz SHORT MDC_NoToolHelp ;No
push ax
push Win_PDB ; Preserve Win_TDB across ToolHelp call
cmp curTDB,0
jz @F
push es
mov es,curTDB
push es:[TDB_PDB]
pop ds:Win_PDB
pop es
@@:
;** Just call the TOOLHELP callback. It preserves all registers
;** except AX where it returns nonzero if the notification
;** was handled.
call lpfnToolHelpProc ;Do it
pop Win_PDB ; Restore Win_TDB
or ax,ax ;Did the TOOLHELP client say to
; pass it on?
jz SHORT @F ;Yes
add sp,2 ;No, so return TOOLHELP's return value
jmp SHORT no_ptrace
@@: pop ax ;Restore notification ID
MDC_NoToolHelp:
;** Make sure we don't have a new notification. If it's newer than
;* CVW, CVW chokes on it so we can't send new notifications
;** through PTrace.
cmp ax,SDM_DELMODULE ;Last old notification
ja short no_ptrace ;Don't send new notification
MDC_PTraceOk:
cmp WORD PTR ptrace_dll_entry[2],0 ;WINDEBUG.DLL lurking around?
jz SHORT no_ptrace
; !!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!
;
; Windebug.DLL for Windows 3.0 knows exactly what is on the stack
; when Kernel makes a PTrace callout. For this reason, we cannot
; change what is on the stack when we make one of these calls.
; This stuff below fakes a FAR return to our NEAR caller, and jumps
; to the PTrace DLL entry with all registers intact.
;
; SP -> DS RET
sub sp,8
push bp
mov bp,sp
; BP -> BP xx xx xx xx DS KERNEL_RET
mov [bp+2],ax ; save AX
mov ax,[bp+10] ; move saved DS
mov [bp+4],ax
mov ax,[bp+12] ; convert near RET to far
mov [bp+10],ax
mov [bp+12],cs
mov ax,word ptr ptrace_dll_entry[2] ; CS of Routine to invoke
mov [bp+8],ax
mov ax,word ptr ptrace_dll_entry ; IP of Routine to invoke
mov [bp+6],ax
; SP -> BP AX DS PTRACE_IP PTRACE_CS KERNEL_RET KERNEL_CS
pop bp
pop ax
pop ds
UnSetKernelDS
retf
no_ptrace:
pop ds
UnSetKernelDS
ret
cEnd nogen
if KDEBUG
dout macro var
mov byte ptr ss:[si],var
inc si
endm
;-----------------------------------------------------------------------;
; hex ;
; ;
; Outputs byte in AL as two hex digits. ;
; ;
; Arguments: ;
; AL = 8-bit value to be output ;
; SS:SI = where it's to be put ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Fri Nov 14, 1986 02:32:15p -by- David N. Weise [davidw] ;
; Modified it from symdeb\debug.asm. ;
;-----------------------------------------------------------------------;
ifndef WOW
cProc hex,<NEAR>
cBegin nogen
mov ah,al ; save for second digit
; shift high digit into low 4 bits
mov cl,4
shr al,cl
and al,0Fh ; mask to 4 bits
add al,90h
daa
adc al,40h
daa
dout al
mov al,ah ; now do digit saved in ah
and al,0Fh ; mask to 4 bits
add al,90h
daa
adc al,40h
daa
dout al
ret
cEnd nogen
;-----------------------------------------------------------------------;
; pdref_norip ;
; ;
; Dereferences the given global handle, i.e. gives back abs. address. ;
; ;
; Arguments: ;
; DX = selector ;
; DS:DI = BURGERMASTER ;
; ;
; Returns: ;
; FS:ESI = address of arena header ;
; AX = address of client data ;
; CH = lock count or 0 for fixed objects ;
; CL = flags ;
; DX = handle, 0 for fixed objects ;
; ;
; Error Returns: ;
; ZF = 1 if invalid or discarded ;
; AX = 0 ;
; BX = owner of discarded object ;
; SI = handle of discarded object ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ghdref ;
; ;
; History: ;
; ;
;-----------------------------------------------------------------------;
if pmode32
.386p
assumes ds,nothing
assumes es,nothing
cProc pdref_norip,<PUBLIC,NEAR>
cBegin nogen
; DPMI - no LDT access
mov si, dx
sel_check si
or si, si ; Null handle?
jnz short OK1
mov ax, si ; yes, return 0
jmps pd_exit
OK1:
lar eax, edx
jnz short pd_totally_bogus
shr eax, 8
; We should beef up the check for a valid discarded sel.
xor cx,cx
test ah, DSC_DISCARDABLE
jz short pd_not_discardable
or cl, GA_DISCARDABLE
; Discardable, is it code?
test al, DSC_CODE_BIT
jz short pd_not_code
or cl,GA_DISCCODE
pd_not_code:
pd_not_discardable:
test al, DSC_PRESENT
jnz short pd_not_discarded
; object discarded
or cl,HE_DISCARDED
if PMODE32
; On WOW we don't copy the owner to the real LDT since it is slow to call
; the NT Kernel, so we read our copy of it directly.
; see set_discarded_sel_owner mattfe mar 23 93
mov ax,es ; save es
mov bx,dx
mov es,cs:gdtdsc
and bl, not 7
mov bx,es:[bx].dsc_owner
mov es,ax ; restore
else
lsl bx, dx ; get the owner
endif
or si, SEG_RING-1 ; Handles are RING 2
xor ax,ax
jmps pd_exit
pd_not_discarded:
cCall get_arena_pointer32,<dx>
mov esi, eax
mov ax, dx
or esi, esi ; Unknown selector
jz short pd_maybe_alias
mov dx, ds:[esi].pga_handle
cmp dx, ax ; Quick check - handle in header
je short pd_match ; matches what we were given?
test al, 1 ; NOW, we MUST have been given
jz short pd_totally_bogus ; a selector address.
push ax
StoH ax ; Turn into handle
cmp dx, ax
pop ax
jne short pd_nomatch
pd_match:
or cl, ds:[esi].pga_flags
and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!!
mov ax, dx ; Get address in AX
test dl, GA_FIXED ; DX contains handle
jnz short pd_fixed ; Does handle need derefencing?
mov ch, ds:[esi].pga_count
HtoS ax ; Dereference moveable handle
jmps pd_exit
pd_totally_bogus:
xor ax,ax
pd_maybe_alias:
pd_nomatch: ; Handle did not match...
xor dx, dx
pd_fixed:
pd_exit:
or ax,ax
ret
cEnd nogen
.286p
endif
;-----------------------------------------------------------------------;
; xhandle_norip ;
; ;
; Returns the handle for a global segment. ;
; ;
; Arguments: ;
; Stack = sp -> near return return address ;
; sp+2 -> far return return address of caller ;
; sp+6 -> segment address parameter ;
; ;
; Returns: ;
; Old DS,DI have been pushed on the stack ;
; ;
; ZF= 1 if fixed segment. ;
; AX = handle ;
; ;
; ZF = 0 ;
; AX = handle ;
; BX = pointer to handle table entry ;
; CX = flags and count word from handle table ;
; DX = segment address ;
; ES:DI = arena header of object ;
; DS:DI = master object segment address ;
; ;
; Error Returns: ;
; AX = 0 if invalid segment address ;
; ZF = 1 ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Oct 16, 1986 02:40:08p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
if pmode32
.386p
cProc xhandle_norip,<PUBLIC,NEAR>
cBegin nogen
pop dx ; Get near return address
mov bx,sp ; Get seg parameter from stack
mov ax,ss:[bx+4]
cmp ax,-1 ; Is it -1?
jnz short xh1
mov ax,ds ; Yes, use callers DS
xh1: inc bp
push bp
mov bp,sp
push ds ; Save DS:DI
push edi
push esi
SetKernelDS
mov ds, pGlobalHeap ; Point to master object
UnSetKernelDS
xor edi,edi
inc [di].gi_lrulock
push dx
mov dx,ax
call pdref_norip
xchg dx,ax ; get seg address in DX
jz short xhandle_ret ; invalid or discarded handle
test al, GA_FIXED
jnz short xhandle_fixed
or ax, ax
jmps xhandle_ret
xhandle_fixed:
xor bx, bx ; Set ZF
xhandle_ret:
ret
cEnd nogen
.286p
else ; !pmode32
cProc xhandle_norip,<PUBLIC,NEAR>
cBegin nogen
pop dx ; Get near return address
mov bx,sp ; Get seg parameter from stack
mov ax,ss:[bx+4]
cmp ax,-1 ; Is it -1?
jnz xh1
mov ax,ds ; Yes, use callers DS
xh1: inc bp
push bp
mov bp,sp
push ds ; Save DS:DI
push di
call genter
push dx
mov dx,ax
push si
externNP pdref
call pdref
xchg dx,ax ; get seg address in DX
jz xhandle_ret ; invalid or discarded handle
mov bx,si
or si,si
jz xhandle_ret
mov ax,si
xhandle_ret:
pop si
ret
cEnd nogen
endif ; !pmode32
endif ;ifndef WOW
endif ;KDEBUG
cProc ReplaceInst,<PUBLIC,FAR>
;; parmD bpaddress
;; parmW instruct
cBegin nogen
ret 6
cEnd nogen
sEnd CODE
end