;       SCCSID = @(#)debinit.asm	6.1 90/11/17
;      SCCSID = @(#)debinit.asm	13.16 90/07/09
PAGE	,132
NAME	DEBINIT
TITLE	DEBINIT.ASM - Debug Initialization
.286p

;***	DEBINIT.ASM
;
;	Contains the routines to initialization the debugger, setting
;	the traps for break points, etc. It saves the init data packet
;	passed to it. The debugger can be re-initialized at any time
;	with the sticky breakpoints still intact.
;
;

.xlist
	include debseg.inc
	include debmac.inc
	include debequ.inc
	include debinit.inc
	include debdesc.inc
.list

DataSegmentStart

Extern DebSASTable,	WORD
Extern DebData,		WORD		; DebugInit data structure
Extern RegSA,		WORD
Extern DefType,		WORD
Extern InDebugger,	BYTE
Extern TrapNumber,	BYTE		; Trap number
Extern DefaultCmd,	BYTE
Extern InitCmdBuffer,	BYTE
Extern CommandScriptAddrS,	BYTE
Extern CommandScriptSize,	WORD
Extern fTraceCount	BYTE
Extern fTraceSpecial	BYTE
Extern fRegDisp		BYTE
Extern fDoGoSpecial	BYTE

IFDEF	KDP
Extern fKDPEnabled,	BYTE
Extern fKDPPacketStop,	BYTE
ENDIF

Static header,		STRING, <CR, LF, "System Debugger 03/16/89 ">
Static headerflag,	BYTE, 0
Static cpu286msg,	STRING, <"[80286]", CR, LF>
Static cpu386msg,	STRING, <"[80386]", CR, LF>

Static TimerTicFlag	BYTE,	0	; timer tic interrupt set flag

TIMER_PROT_SET	equ	00000001b	; timer tic interrupt set in prot mode
TIMER_REAL_SET	equ	00000010b	; timer tic interrupt set in real mode

Static DebCSAddr,	STRUC,	AddrS,	<>
Static TmpAddr,		STRUC,	AddrS,	<>

DataSegmentEnd

CodeSegmentStart

;
;	These variables are put in the code segment so we can access
;	them with a CS override. This means in protected mode the
;	code segment must be readable. If the debugger is initialized
;	in protected mode these variables will be initialized using
;	a alias pointer (which will be writeable) to the code segment.
;

Static RealModeDS,	WORD,	0	; real mode data segment
Static ProtModeDS,	WORD,	0	; protected mode data selector

Static RealNextTimer,	DWORD,	0	; real mode address of timer interrupt
Static ProtNextTimer,	DWORD,	0	; protected mode address of timer int

;***	Debug_Entry
;
;	Debugger entry point called by program to start debugger.
;
;	ENTRY:	ES:DI = pointer to init packet (DebugInit struc
;		in DEBEQU.INC).
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	WARNING: Note that this is a far call.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Entry, FAR, PUBLIC
	pushf					; save flags and data segment
	push	ds				;
	cli					; disable interrupts
	Pcall	Is286				; don't initialize if 8086
	jnz	dbe1				;
	pop	ds
	POPFF
	ret					; return

dbe1:	Pcall	IsDebProtMode			; get debugger's data segment
	mov	ds,es:[di].DSsel
	jc	dbe2
	mov	ds,es:[di].DSseg
    assumeDATA	<ds>
dbe2:	pop	RegSA.DSsav			; get user's DS and flags
	pop	RegSA.Fsav
	SaveReg <si, di, ds, es>
	push	ds
	push	es
	pop	ds
	pop	es
	mov	si,di				; (DS:SI) = DebData passed
	mov	di,dataOFFSET DebData		; (ES:DI) = Local DebData
	mov	cx,size DebugInit
	rep movsb
	RestReg <es, ds, di, si>

;	Setup up debugger SAS hook vectors

	cmp	DebSASTable.DSAS_HookRM.Segmt16,0
	jne	dbe3
	test	DebData.InitFlag,INIT_REALFLAG
	jz	dbe3

	push	ax
	mov	ax,DebData.CSseg
	mov	DebSASTable.DSAS_HookRM.Segmt16,ax
	mov	ax,DebData.DebCallOutPtr
	mov	DebSASTable.DSAS_HookRM.Offst16,ax
	pop	ax

dbe3:	cmp	DebSASTable.DSAS_HookPM.Segmt16,0
	jne	dbe4
	test	DebData.InitFlag,INIT_PROTFLAG
	jz	dbe4

	push	ax
	mov	ax,DebData.CSsel
	mov	DebSASTable.DSAS_HookPM.Segmt16,ax
	mov	ax,DebData.DebCallOutPtr
	mov	DebSASTable.DSAS_HookPM.Offst16,ax
	pop	ax

;	Clear the high byte of the gdt and idt address if a 286

dbe4:	test	DebData.InitFlag,INIT_CPU386
	jnz	dbe5
	mov	DebData.GDTaddr.DTRBaseExt,0
	mov	DebData.ProtIDTaddr.DTRBaseExt,0
	mov	DebData.RealIDTaddr.DTRBaseExt,0

dbe5:	Pcall	EnterDebugINIT
    assumeDATA	<ds, es, ss>
	Pcall	InitComPort			; Initialize i/o ports
	Pcall	EnableNMI			; let NMI interrupts in
	Pcall	DebCallOut, <DEB_CALLOUT_DEBINIT>

;	Initialize debugger code segment AddrS

	Pcall	FillDefAddr, <dataOFFSET DebCSAddr, cs, 0, 0>

;	Restore the any vectors changed before, if re-initializing the IDT.

	test	DebData.InitFlag,INIT_NOVECSET
	jnz	dbe6
	Pcall	RestAllIdt

dbe6:	test	DebData.InitFlag,INIT_REALFLAG	; check if initialize real mode
	jnz	dbe7
	jmp	dbe11

;	Check if the idt vectors for real mode should be set

dbe7:	test	DebData.InitFlag,INIT_NOVECSET
	jnz	dbe10

;	Set real mode idt entries

	xor	si,si				; SI is not used by SetIdtEntry
	mov	di,DebData.RealVectorSet	; DI = bit field of vecs to set
dbe8:	shr	di,1				; If bit set, then set vector
	jnc	dbe9
	Pcall	SetIdtEntry, <TRAP_RM_USED, si> ; ES MUST be debugger data seg
dbe9:	inc	si
	cmp	si,NUMBER_TRAPS			; set real mode vectors
	jne	dbe8

dbe10:	mov	bx,dataOFFSET DebCSAddr
	mov	dx,DebData.DSseg		; put real mode data seg in
	Pcall	PutWordOff, <codeOFFSET RealModeDS, 0>
	jc	dbe12

;	Initialize timer tic interrupt trap in real mode idt entry

	test	DebData.InitFlag,INIT_CTRLCFLAG
	jz	dbe11				; jump if not to init ctrl C

	test	TimerTicFlag,TIMER_REAL_SET
	jnz	dbe11				; jump if already initialized

	mov	bx,dataOFFSET TmpAddr
	Pcall	GetRMIDTaddr

	mov	dx,DebData.RealTicInt		; DX = real mode int number
	shl	dx,2				; DX = index (intnum * 4)
	Pcall	AddAddr, <dx, 0>		; DX = offset into idt

	Pcall	GetWordOff, <Offst16, 0>
	jc	dbe12
	push	dx				; save offset

	Pcall	GetWordOff, <Segmt16, 0>
	jc	dbe12
	push	dx				; save segment

	mov	dx,codeOFFSET RMCheckCtrlC	; DX = offst of new tic handler
	Pcall	PutWordOff, <Offst16, 0>
	jc	dbe12

	mov	dx,DebData.CSseg		; DX = segmt of new tic handler
	Pcall	PutWordOff, <Segmt16, 0>
	jc	dbe12

	mov	bx,dataOFFSET DebCSAddr		; (BX) = debugger CS AddrS
	pop	dx				; (DX) = segment
	Pcall	PutWordOff, <codeOFFSET RealNextTimer.Segmt16, 0>
	jc	dbe12

	pop	dx				; (DX) = offset
	Pcall	PutWordOff, <codeOFFSET RealNextTimer.Offst16, 0>
	jc	dbe12

	or	TimerTicFlag,TIMER_REAL_SET

dbe11:	test	DebData.InitFlag,INIT_PROTFLAG	; check if initialize prot mode
	jnz	dbe13
	jmp	dbe19

dbe12:	jmp	dbe18

;	Check if the idt vectors for protected mode should be set

dbe13:	test	DebData.InitFlag,INIT_NOVECSET
	jnz	dbe17

;	Set protected mode idt entries

	xor	si,si
	mov	di,DebData.ProtVectorSet
	mov	bx,DebData.ProtVectorHard

;	(SI) = current vector number
;	(DI) = bit field of vectors to intercept
;	(BX) = intercept vector hard bit field

dbe14:	shr	di,1				; If bit set, then set vector
	jnc	dbe16

	push	bx				; Save hard vect set bit field
	shr	bx,1
	mov	ax,TRAP_PM_USED
	jnc	dbe15				; If hard vect set bit set,
	mov	ax,TRAP_PM_USED+TRAP_PM_HARD	;   use this parameter.
dbe15:	Pcall	SetIdtEntry, <ax, si>
	pop	bx

dbe16:	shr	bx,1				; (BX) = this vector's bit
	inc	si
	cmp	si,NUMBER_TRAPS			; set protected IDT entries
	jne	dbe14

dbe17:	mov	bx,dataOFFSET DebCSAddr
	mov	dx,DebData.DSsel		; put prot mode data selector
	Pcall	PutWordOff, <codeOFFSET ProtModeDS, 0>
	jc	dbe18

;	Initialize timer tic interrupt trap in protected mode idt entry

	test	DebData.InitFlag,INIT_CTRLCFLAG
	jz	dbe19				; jump if not to init ctrl C

	test	TimerTicFlag,TIMER_PROT_SET
	jnz	dbe19				; jump if already initialized

	mov	bx,dataOFFSET TmpAddr
	Pcall	GetPMIDTaddr

	mov	ax,DebData.ProtTicInt
	imul	ax,size Desc			; AX = prot mode tic offset
	Pcall	AddAddr, <ax,0>

	Pcall	GetWordOff, <GateOffset, 0>
	jc	dbe18
	push	dx				; save gate offset

	Pcall	GetWordOff, <GateSelector, 0>
	jc	dbe18
	push	dx				; save gate selector

	mov	dx,codeOFFSET PMCheckCtrlC	; DX = offset of new tic handler
	Pcall	PutWordOff, <GateOffset, 0>
	jc	dbe18

	mov	dx,DebData.CSsel		; DX = sel of new tic handler
	Pcall	PutWordOff, <GateSelector, 0>
	jc	dbe18

	mov	bx,dataOFFSET DebCSAddr		; (BX) = debugger's CS AddrS
	pop	dx				; (DX) = gate selector
	Pcall	PutWordOff, <codeOFFSET ProtNextTimer.Segmt16, 0>
	jc	dbe18

	pop	dx				; (DX) = gate offset
	Pcall	PutWordOff, <codeOFFSET ProtNextTimer.Offst16, 0>
	jc	dbe18

	or	TimerTicFlag,TIMER_PROT_SET
	jmp	short dbe19

dbe18:	putstr	<"Init Error">
	Pcall	PrintMemErr

;	Print Debugger header message exactly once.

dbe19:	cmp	[headerflag],0
	jnz	dbe21
	inc	[headerflag]
	mov	dx,dataOFFSET header
	Pcall	rprbuf
	test	DebData.InitFlag,INIT_CPU386
	mov	dx,dataOFFSET cpu286msg
	jz	dbe20
	mov	dx,dataOFFSET cpu386msg
dbe20:	Pcall	rprbuf

;	Check flag to break into debugger or just return to caller.

dbe21:	test	DebData.InitFlag,INIT_NOBRKFLAG
	jnz	dbe23				; jump if no break set

	cmp	DebData.BreakChar,0
	je	dbe24				; if 0, always break
	Pcall	inchr
	jz	dbe22				; if no key hit, do init cmd
	cmp	al,DebData.BreakChar
	je	dbe24				; if break char, do def cmd
	Pcall	ungetc				; put char back if not

dbe22:	mov	si,dataOFFSET InitCmdBuffer
	cmp	byte ptr [si],0			; check if init command exists
	je	dbe23				; jump if init command exists
	Pcall	DoCommand
	Jump	command				; accept commands

dbe23:	Pcall	CheckCtrlC
	Jump	ExitDebug			; return to caller

dbe24:	Jump	RCmdBreak
EndProc NoGen

DefProc KDPEnable, FAR, PUBLIC
	Pcall	EnterDebugRETF
	mov	fKDPEnabled,TRUE
	jmp	ExitDebug
EndProc NoGen

;***	Debug_Break
;
;	Debugger break entry point.
;
;	ENTRY:	NONE
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	WARNING: Note that this is a far call.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Break, FAR, PUBLIC
	Pcall	EnterDebugRETF
    assumeDATA	<ds, es, ss>
	mov	TrapNumber,BREAK_POINT_TRAP
	Pcall	CheckCtrlC
	Jump	BreakEntry
EndProc NoGen

;***	Debug_Break32
;
;	Debugger break 32 bit entry point.
;
;	ENTRY:	NONE
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	WARNING: Note that this is a 32 bit far call.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Break32, FAR, PUBLIC
	Pcall	EnterDebugRETFD
    assumeDATA	<ds, es, ss>
	mov	TrapNumber,BREAK_POINT_TRAP
	Pcall	CheckCtrlC
	Jump	BreakEntry
EndProc NoGen

;***	Debug_Command - do debugger command script
;
;	This function is passed an AddrS structure that points
;	to a block of debugger commands to be executed.  The command
;	lines can be terminated by either CR/LF or just a LF.  The
;	characters over 80 in a command line are ignored.  The command
;	buffer or script is terminated by the size parameter passed
;	or a null.
;
;	ENTRY:	(DS:SI) = pointer to AddrS for command buffer
;		(CX)	= command buffer size
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	WARNING: Note that this is far call.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Command, FAR, PUBLIC
	Pcall	EnterDebugRETF
    assumeDATA	<ds, es, ss>
	Pcall	CheckCtrlC
	mov	si,[RegSA].SIsav
	mov	ds,[RegSA].DSsav
	mov	di,dataOFFSET CommandScriptAddrS
	mov	cx,(size AddrS)
	rep movsb
	DataContext <ds>,ax
	mov	ax,[RegSA].CXsav
	mov	[CommandScriptSize],ax
	Jump	command
EndProc NoGen

;***	Debug_Exit - removes the debugger from the system.
;
;	This routines removes any changes to the read and protected
;	mode IDT entries that the debugger made and restores anything
;	else needed to discard the debugger.
;
;	ENTRY:	NONE
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	NOTE:	This routine is a far call.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc Debug_Exit, FAR, PUBLIC
	Pcall	EnterDebugRETF
	Pcall	DebExit
	Jump	ExitDebugNoBP
EndProc NoGen

;***	DebExit
;
;	This routines removes any changes to the read and protected
;	mode IDT entries that the debugger made and restores anything
;	else needed to discard the debugger.
;
;	ENTRY:	NONE
;
;	EXIT:	NONE
;
;	USES:	ALL
;
	assumeDATA <ds, es, ss>

DefProc DebExit, NEAR, PUBLIC

;	Undo the timer tic interrupt trap in real mode idt entry

	test	TimerTicFlag,TIMER_REAL_SET
	jz	dbx1				; jump if not initialized

	mov	bx,dataOFFSET TmpAddr
	Pcall	GetRMIDTaddr

	mov	ax,DebData.RealTicInt
	shl	ax,2
	Pcall	AddAddr, <ax, 0>

	mov	dx,cs:RealNextTimer.Offst16	  ; restore the offset
	Pcall	PutWordOff, <Offst16, 0>
	jc	dbx1

	mov	dx,cs:RealNextTimer.Segmt16	  ; restore the segment
	Pcall	PutWordOff, <Segmt16, 0>
	jc	dbx1

	and	TimerTicFlag,TIMER_REAL_SET

;	Undo timer tic interrupt trap in protected mode idt entry

dbx1:	test	TimerTicFlag,TIMER_PROT_SET
	jz	dbx2				; jump if not initialized

	mov	bx,dataOFFSET TmpAddr
	Pcall	GetPMIDTaddr

	mov	ax,DebData.ProtTicInt
	imul	ax,size Desc
	Pcall	AddAddr, <ax, 0>

	mov	dx,cs:ProtNextTimer.Offst16	  ; restore the offset
	Pcall	PutWordOff, <GateOffset, 0>
	jc	dbx2

	mov	dx,cs:ProtNextTimer.Segmt16	  ; restore the sel/seg
	Pcall	PutWordOff, <GateSelector, 0>
	jc	dbx2

	and	TimerTicFlag,TIMER_PROT_SET

dbx2:	Pcall	RestAllIdt
	Pcall	DebCallOut, <DEB_CALLOUT_DEBEND>
	Pcall	ExitMem
EndProc

;***	GetDebuggerDS - set a register to the data segment register value
;
;	The value that a segment register must hold to address the data
;	segment is different in real address and protected modes.  This
;	routine returns the correct value to address the dos/debugger
;	data segment.
;
;	ENTRY:	NONE
;
;	EXIT:	(DS) = Debugger's data segment
;
;	USES:	DS, Flags
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc GetDebuggerDS, NEAR, PUBLIC
	Pcall	IsDebProtMode
	mov	ds,cs:ProtModeDS
	jc	gds1
	mov	ds,cs:RealModeDS
gds1:
EndProc

;***	RMCheckCtrlC
;***	PMCheckCtrlC
;***	Debug_CtrlC - 16 bit frame ctrl-c entry
;
;	This is a timer tic trap that checks control C
;	and breaks into the debug if there is one at the
;	com port.
;
;	Debug_CtrlC is call by interrupt routines to let the
;	debugger poll the com port for ctrlc so the debugger
;	doesn't have to grab the timer interrupt. Either
;	method can be used.
;
;	ENTER:	NONE
;
;	EXIT:	NONE
;
;	USES:	NONE
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc RMCheckCtrlC, FAR, LOCAL
	pushf
	call	cs:RealNextTimer	; jump to timer tic handler
	jmp	short Debug_CtrlC

Entry	PMCheckCtrlC, FAR, LOCAL
	pushf
	call	cs:ProtNextTimer	; jump to timer tic handler

Entry	Debug_CtrlC, FAR, PUBLIC	; entry to be used at end of int routine
	cli
	push	ds
	Pcall	GetDebuggerDS		; (DS) = debugger data
    assumeDATA	ds
	Pcall	DebCallOut, <DEB_CALLOUT_BREAK>

	IFDEF	KDP
	jc	short ccc1
	jz	short ccca
	cmp	fKDPEnabled,0
	je	ccca
	mov	fKDPPacketStop,TRUE
	jmp	ccc1
ccca:
	pop	ds
    ASSUME  DS:NOTHING
	iret

ccc1:
    assumeDATA	ds
	pop	ds

    ASSUME  DS:NOTHING

	ELSE

	pop	ds
    ASSUME  DS:NOTHING
	jc	short ccc1		; jump if break character hit
	iret

ccc1:
	ENDIF

	push	ds
	pushf
	Pcall	GetDebuggerDS		; (DS) = debugger data
    assumeDATA	ds
	mov	fTraceCount,0		; Zero trace modes
	mov	fTraceSpecial,0
	mov	fRegDisp,1		;  ... and enable register display
	mov	fDoGoSpecial,0
	popf
	pop	ds
	push	NO_ERROR
	push	NO_TRAPNUM
	Pcall	EnterDebugIRET
	Jump	RCmdBreak

;***	Debug_CtrlC32 - 32 bit frame ctrl-c entry
;
;	Debug_CtrlC32 is call by interrupt routines to let the
;	debugger poll the com port for ctrlc so the debugger
;	doesn't have to grab the timer interrupt. Either
;	method can be used.
;
;	ENTER:	NONE
;
;	EXIT:	NONE
;
;	USES:	NONE
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry	Debug_CtrlC32, FAR, PUBLIC, FAR16
	cli

	push	ds
	Pcall	GetDebuggerDS		; (DS) = debugger data
    assumeDATA	ds
	Pcall	DebCallOut, <DEB_CALLOUT_BREAK>

	IFDEF	KDP
	jc	short ccc2
	jz	short ccc1a
	cmp	fKDPEnabled,0
	je	short ccc1a
	mov	fKDPPacketStop,TRUE
	jmp	short ccc2
ccc1a:
	pop	ds
    ASSUME  DS:NOTHING
.386p
Entry	EndCtrlC32, FAR, PUBLIC
	iretd
.286p

ccc2:
	pop	ds
    ASSUME  DS:NOTHING

	ELSE

	pop	ds
    ASSUME  DS:NOTHING
	jc	short ccc2		; jump if break character hit
.386p
Entry	EndCtrlC32, FAR, PUBLIC
	iretd
.286p

ccc2:
	ENDIF

	push	ds
	pushf
	Pcall	GetDebuggerDS		; (DS) = debugger data
    assumeDATA	ds
	mov	fTraceCount,0		; Zero trace modes
	mov	fTraceSpecial,0
	mov	fRegDisp,1		;  ... and enable register display
	mov	fDoGoSpecial,0
	popf
	pop	ds
	push	0			; error code pad
	push	NO_ERROR
	push	0			; trap number pad
	push	NO_TRAPNUM
	Pcall	EnterDebugIRETD
	Jump	RCmdBreak
EndProc NoGen

;***	DebCallOut - common debugger callout routine
;
;	Pcall	DebCallOut, <CallOutNumber>
;
;	ENTRY:	(CallOutNumber)
;
;	EXIT:	Depends on callout function
;
;	USES:	Depends on callout function
;
	assumeDATA <ds>
	ASSUME	ES:NOTHING, SS:NOTHING

DefProc DebCallOut, NEAR, PUBLIC

ArgVar	CallOutNumber, WORD

BeginProc
	push	CallOutNumber
	Pcall	IsDebProtMode
	jc	dco1
	call	[DebSASTable.DSAS_HookRM]
	jmp	short dcox

dco1:	call	[DebSASTable.DSAS_HookPM]
dcox:
EndProc

IFDEF	DEBUG

DataSegmentStart

SaveSS	dw	0
SaveSP	dw	0
	db	512 dup (0)
PrtStk	label	word
TmpBuf	db	256 dup (0)
Static	ReentryFlag,	WORD,	-1

DataSegmentEnd

;***	dprntf - debugging printf
;
;	debprt	<"fmt">, <args>
;
;	ENTER:	(fmtptr) = pointer to format string.
;		(args) = number of bytes of parameters on stack.
;		(parm) = first parameter.
;
;	EXIT:	NONE
;
;	USES:	NONE
;
;	Uses "C" calling conventions.
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING

DefProc dprntf, NEAR, PUBLIC, C

ArgVar	fmtptr, WORD
ArgVar	args,	WORD
ArgVar	     parm,   WORD

BeginProc
	pusha
	push	ds
	push	es
	Pcall	     GetDebuggerDS
     assumeDATA ds
	mov	ax,ds		; (AX) = debugger's data segment
	or	ax,ax
	jz	dpt3

	mov	[SaveSS],ss
	mov	[SaveSP],sp
	mov	ss,ax
	mov	sp,dataOFFSET PrtStk
     assumeDATA ss

	mov	es,[SaveSS]
	lea	di,parm		; (ES:DI) = pointer to first parameter

	mov	cx,es:[args]
	add	di,cx		; (ES:DI) = pointer to last parameter
	shr	cx,1		; (CX) = args/2, number of words
	jcxz	dpt2

dpt1:	sub	di,2
	push	es:[di]
	loop	dpt1

dpt2:	mov	di,sp		; (DI) = pointer to first parm on new stack
	mov	bx,es:[fmtptr]
	DataContext <es>
	mov	si,dataOFFSET TmpBuf
	Ccall	_sprntf, <si, bx, di>
	Pcall	prtstr, <si>

	mov	ss,[SaveSS]
	mov	sp,[SaveSP]
dpt3:	pop	es
	pop	ds
	popa
EndProc

;***	SegChk - debugging segment register check
;
;	An internal debugger segment register check
;	routine called by DefProc when SEGCHK is defined.
;
;	ENTRY:	DS, ES, SS
;
;	EXIT:	NONE
;
;	USES:	NONE
;
	ASSUME	DS:NOTHING, ES:NOTHING, SS:NOTHING
.386p
DefProc SegChk, NEAR, PUBLIC

ArgVar	RoutNam, WORD

BeginProc
	pushf
	pushad
	Pcall	IsDebProtMode
	mov	ax,[ProtModeDS]		; (AX) = protected mode data segment
	jc	short sck1		; jump if protected mode
	mov	ax,[RealModeDS]		; (AX) = real mode data segment
sck1:	or	ax,ax
	jz	short sck3
	mov	bx,ds			; (BX) = (DS)
	mov	cx,es			; (CX) = (ES)
	mov	dx,ss			; (DX) = (SS)
	cmp	bx,ax			; check DS
	jne	short sck2
	cmp	cx,ax			; check ES
	jne	short sck2
	cmp	dx,ax			; check SS
	je	short sck3
sck2:	call	Debug_Break
sck3:	popad
	POPFF
EndProc
.286p

;***	DumpDebugStack
;
;	DumpDebugStack()
;
;	ENTRY:	(SS:BP) = starting BP
;
;	EXIT:	NONE
;
;	USES:	NONE
;
	assumeDATA <ds, es, ss>

DefProc DumpDebugStack, NEAR, PUBLIC

LocVar	SSBPaddr, <size AddrS>
LocVar	CSIPaddr, <size AddrS>

BeginProc
	pushf
	inc	[ReentryFlag]
	jnz	short ddsx
	pusha
	Pcall	crlf
	lea	bx,SSBPaddr
	Pcall	FillDefAddr, <bx, ss, [bp], 0>
	lea	si,CSIPaddr
	Pcall	FillDefAddr, <si, cs, 0, 0>
	xor	di,di
	Pcall	PrintStack
	popa
ddsx:	dec	[ReentryFlag]
	popf
EndProc
ENDIF

CodeSegmentEnd

	end
