;
; GRDP
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; EXEC.ASM
;
; Function: Handle T,G,P commands
;
	;MASM MODE
	.model small
	.386


include  eprints.inc 
include  einput.inc 
include  emtrap.inc 
include  ebreaks.inc 
include  edos.inc
include  eints.inc
include eregs.inc
include eswift.inc

TRAPFLAG = 100h			; 80386 trap enable flag

	PUBLIC go,trap, proceed, ReTrap, TrapCount, callcheck, cmpstring, wadeprefix


	.data
trapcount	dd	0	;number of traps left to do or zero for none
pfx67flag	dw	0 	;flag if 67h prefix found during call check

;All possible prefixes

pretab	db	0f0h,0f2h,0f3h,026h,02eh,036h,03eh,064h,065h,066h,067h

;String functions

stringtab db	0a6h,0a7h,6ch,6dh
	db	0ach,0adh,0a4h,0a5h
	db	06eh,06fh,0aeh,0afh
	db	0aah,0abh

	.code
;
	assume ds:nothing	; going to call from where DS is moot
;
callcheck	proc
	mov	ah,fs:[bx]	; Load the first byte of the instruction
	cmp	ah,0ceh		; into?
	mov	al,1
	jz	chx
	cmp	ah,0cdh		; Interrupt ?
	mov	al,2		; two bytes
	jz	chx		; I do this because some int calls are
				; misbehaved and won't restore the trap flag
	cmp	ah,0e8h		; Near Call?
	mov	al,3		; Yes, this is 3 bytes
	jz	chx		; And execute it
	cmp	ah,09ah		; Far call
	mov	al,5		; This one is 5 bytes
	jz	chx		; Not either of these, just trap
	mov	ax,fs:[bx]
	and	ax,038FFH
	cmp	ax,010ffh
	jz	gotind
	cmp	ax,018ffh
	jz	gotind
	ret
gotind:
	mov	al,2  		; two bytes base
	mov	ah,fs:[bx+1]
       	and	ah,0c7h
	cmp	ah,0c0h		; mod 3, through reg is 2 bytes
	jnc	chx
	test	[pfx67flag],0ffh	; check 16/32 address mode flag
	jnz	call32
	cmp	ah,8		; 16 bit, MOD=0
	jnc	chk16m1
	cmp	ah,6		; yes, direct offset?
	jnz	chx
	add	al,2		; yes 4 bytes total
	jmp	chx
chk16m1:
	and	ah,0c0h		; check for mod 1 or 2
	js	is16m2
	inc	al		; mod 1, add a byte for offset
	jmp	chx
is16m2:
	add	al,2		; else mod 2, two byte offset
	jmp	chx
call32:
	cmp	ah,6		; 32 bit mode, check for 32-bit offset
	jnz	ch32m0
	add	al,4		; yep, add 4
	jmp	ch32sib
ch32m0:
	cmp	ah,8   		; MOD = 0?
	jc	ch32sib		; yep, check for sib
ch32m1:
	or	ah,ah		; MOD = 1?
	js	ch32m2
	add	al,1   		; yep, 1 byte offset
	jmp	ch32sib
ch32m2:
	add	al,4   		; else mod 2
ch32sib:
	and	ah,7
	cmp	ah,4
	jnz	chx
	inc	al		; add in the SIB byte
	mov	ah,byte ptr fs:[bx+1]	; test for MOD 3
	and	ah,0c0h
	cmp	ah,0c0h
	jz	chx		; yep, no further bytes
	mov	ah,byte ptr fs:[bx+2] ; get SIB byte
	and	ah,7		; check for EBP special cases
	cmp	ah,5
	jnz	chx
	inc	al
	test	byte ptr fs:[bx+1],40h ; check if one or 4 bytes disp
	jz	chx
	add	al,3		; MOD 1,3, need 4 bytes
chx:
	add	al,dl		; fix for prefixes
	sub	ah,ah		; clear Z flag...
	ret
callcheck	endp
; used by P command to wade through prefixes to find out if
; we have a string instruction
;
wadeprefix:
	mov	[pfx67flag],0
	sub	dx,dx
wp_lp:
	mov	al,fs:[bx]
	mov	di,offset pretab
	mov	cx,11
	repnz	scasb
	jnz	wp_done
	inc	bx
	inc	dx
	cmp	al,67h
	jnz	wp_lp
	bts	[pfx67flag],0		; flag the addrsiz in case of call
	jmp	wp_lp
wp_done:
	ret
	
cmpstring:
	mov	al,fs:[bx]
	mov	di,offset stringtab
	mov	cx,14
	repnz	scasb
	ret
;
	assume	ds:dgroup	; DS ok again
;
; Execute program
;
go	PROC	
	Call	WadeSpace	; Wade till address
	jz	dogo
	cmp	al,'='
	jnz	checkbreak
	inc	si
	call	ReadAddress
	jc	goerr
	mov	word ptr [RegdumpEIP],bx	; Fix CS:EIP for new routine
	call	defCS		; get CS
checkbreak:
	call	WadeSpace	; Wade
	jz	short dogo	;
	call	ReadAddress	; Read break address
	jc	goerr		; Quit if errir
dogo2:
	sub	ax,ax		; Break 0
	call	SetBreak	; Set the break
dogo:
	call	EnableBreaks	; Enable breaks
	xor	ax,ax		; Not trapping
	jmp	gotrap	; Run the code
goerr:
	stc
	ret
go	ENDP	
;
;
; Limited and semi-buggy proced function
;
PROCEED	PROC	
	call	WadeSpace
	jz	pok
	cmp	al,'r'
	jnz	perr
	inc	si
	call	WadeSpace
	jnz	perr
	mov	cs:[traceon],1
	jmp	gotrap
pok:
	movzx	ebx,word ptr [RegdumpEIP]	;
	mov	fs,[RegdumpCS]	;
	call	wadeprefix	; wade through all prefixes
	call	callcheck  	; noew check for near  & far calls
	jz	short pgo	; and execute it
	mov	ah,fs:[bx]
	mov	al,2
	cmp	ah,0e0h		; Check for loop instructions
	jz	short	pgo
	cmp	ah,0e1h
	jz	short	pgo
	cmp	ah,0e2h
	jz	short	pgo
	call    cmpstring	; see if is string instruction or loop
	jnz	short dotrap	; Not either of these, just trap
	mov	ax,dx
	inc	ax
pgo:
	sub	ah,ah
	movzx	ebx,word ptr [RegdumpEIP]	;
	add	bx,ax		; Ebx = breakpoint
	mov	dx,[RegdumpCS]	; DX:EBX = position to break at
	sub	ax,ax		; Use the scratch breakpoint
	call	SetBreak	; Set a break
	call	EnableBreaks	; Enable breakpoints
	sub	ax,ax		; No trapping
	jmp	gotrap	; Run the code
perr:
	stc
	ret
PROCEED	ENDP	
;
; Trap command
;
trap	PROC	
	call	WadeSpace
	jz	dotrap
	call	ReadNumber
	jc	terr
	push	eax
	call	WadeSpace
	pop	eax
	jz	tnerr
terr:
	stc
	ret
tnerr:
       	or	eax,eax
	jz	dotrap
	dec	eax
	mov	[trapcount],eax
trap	ENDP
dotrap 	PROC
	mov	fs,[RegdumpCS]	;
	mov	bx,word ptr [RegdumpEIP]	;
	mov	ah,fs:[bx]	; Load the first byte of the instruction
	cmp	BYTE PTR fs:[bx],0cdh
	jnz	ReTrap
	mov	al,byte ptr fs:[bx+1]
	cmp	al,20h
	jz	dosvec
	cmp	al,21h
	jnz	stepvec
	mov	ebx,cs:[int21adr]
	jmp	gotadr
stepvec:
	push	0      		; other int instructions do a step
	pop	fs
	jmp	gotadr
dosvec:
	mov	fs,[intpage]
gotadr:
	movzx	bx,al			; trying to trace through a DOS
	shl	bx,2
	mov	ebx,fs:[bx]
	push	es			; vector bypasses our hook
	mov	es,[RegdumpSS]
	mov	di,word ptr [RegdumpESP]
	sub	[RegdumpESP],6
	std
	scasw
	mov	ax,word ptr [RegdumpFLAGS]
	stosw
	mov	ax,[RegdumpCS]
	stosw
	mov	ax,word ptr [RegdumpEIP]
	add	ax,2
	stosw
	cld
	pop	es
	mov	word ptr [RegdumpEIP],bx
	shr	ebx,16
	mov	[RegdumpCS],bx
	call	DisplayRegisters; Display registers
	clc
	ret
dotrap	ENDP
ReTrap	PROC
	mov	ax,TRAPFLAG	; Are trapping on instruction
gotrap	PROC
	push	ax
	mov	si,offset dgroup : veclist	; enable ints
	call	SetRMInts
	pop	ax
	mov	ss,[RegdumpSS]
	mov	esp,[RegdumpESP]	; Load toss
	or	ax,word ptr [RegdumpFLAGS]	; Fill stack frame with FLAGS , CS:EIP
	push	ax		;
	call	SetUserPSP
	push	[RegdumpCS]
	push	word ptr [RegdumpEIP]
	push	[RegdumpDS]
	mov	es,[RegdumpES]
	mov	fs,[RegdumpFS]
	mov	gs,[RegdumpGS]
	mov	eax,[RegdumpEAX]	; Load regs
	mov	ebx,[RegdumpEBX]	;
	mov	ecx,[RegdumpECX]	;
	mov	edx,[RegdumpEDX]	;
	mov	esi,[RegdumpESI]	;
	mov	edi,[RegdumpEDI]	;
	mov	ebp,[RegdumpEBP]	;
	pop	ds		; Load DS
	test	cs:[traceon],1	; if PR go handle first instruction
	jz	doiret
	call	swiftrace
	call	DisplayRegisters; if it was an int 3 come back
	clc
	ret
doiret:
	iret
gotrap	ENDP
Retrap	ENDP	
end