;       SCCSID = @(#)debucmd.asm	6.1 90/11/17
PAGE	, 132
NAME	DEBUCMD
TITLE	DEBUCMD.ASM - unassemble command routines
.286p

SCCSID	equ	"@(#)debucmd.asm	13.9 90/06/13"

;***	DEBUCMD.ASM
;
;	Code for the UASSEMble command in the debugger
;
;

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

DataSegmentStart

Extern DisAddr,		BYTE			; AddrS struc for disassembler
Extern DebData,		BYTE
Extern pRegSA,		WORD
Extern DefType,		WORD

Global opbuf,		OPBUFLEN,	0

Static discnt,		WORD,		0
Static linesflag,	BYTE,		0

; Temporary AddrS structure

TempAddrS	AddrS	<>

; Buffer for symbol returns

SymbolBuf	db	(MAX_NAME_SIZE * 3) DUP (?)

DataSegmentEnd


CodeSegmentStart

DefProc unassem, NEAR, PUBLIC
	mov	linesflag,FALSE		; display the number of bytes if FALSE
	mov	bx,dataOFFSET DisAddr
	Pcall	EvalRange, <bx, bx, 12>
	jcxz	short una4		; don't do anything if count is 0
	jc	short una1
	mov	linesflag,TRUE		; display the number of lines if TRUE
una1:	mov	discnt,cx		; No of lines or bytes to display
	Pcall	CheckAddr, <bx>
una2:	Pcall	disasln			; Disassemble one line
	or	ax,ax
	jz	short una4
	mov	dx,dataOFFSET opbuf
	Pcall	rprbuf			; Print disassembled instructions
	Pcall	crlf
	cmp	linesflag,FALSE
	je	short una3
	dec	discnt			; decrement number of lines
una3:	cmp	discnt,0		; See if we've used up the range
	jg	short una2
una4:
EndProc

;***	disasln
;
;	Disassemble line into "opbuf".
;
;	ENTRY:	(pRegSA)  = the pointer to the RegSA_frame
;		(DisAddr) = the disassembly address
;
;	EXIT:	(opbuf) = the disassembled line
;		(AX)	= number of bytes disassembled
;
;	USES:	AX, BX, CX, DX, DI, SI, ES, Flags

DefProc disasln, NEAR, PUBLIC
	Pcall	GetSymbolBuf, <dataOFFSET SymbolBuf, \
			       dataOFFSET DisAddr, \
			       <MAP_GETMAPNAME or MAP_GETGROUP>, \
			       0>
	jc	short dsa1		; jump if no symbol found
	Pcall	prtstr, <dataOFFSET SymbolBuf>
	mov	al,':'
	Pcall	putchar
	Pcall	crlf
dsa1:	Ccall	disasm, <dataOFFSET opbuf, dataOFFSET DisAddr>

;	(AX) = number of disassembled bytes

	cmp	linesflag,FALSE
	jne	short dsa2
	sub	discnt,ax
dsa2:	mov	bx,dataOFFSET DisAddr	; (BX) = pointer to DisAddr struc
	Pcall	AddAddr, <ax, 0>	; add byte count to address
EndProc

;***	checkbp
;
;	bpnum = checkbp(addrptr);
;
;	Put the breakpoint/character comment in disasemable buffer.
;
;	ENTRY:	(addrptr) = pointer to AddrS structure
;
;	EXIT:	(AX) = breakpoint number or -1 if none
;
;	USES:	AX, BX, CX, Flags
;
;	Uses the C calling convention.

DefProc	checkbp, NEAR, PUBLIC, C

ArgVar	addrptr, WORD

BeginProc
	SaveReg	<si,di>
	mov	bx,addrptr			; (BX) = AddrS pointer
	Pcall	ChkBPaddr			; Is there a breakpoint here?
	mov	ax,-1				; (AX) = no breakpoint
	jnz	dcm1				;  no, skip to exit
	jnc	dcm1				; jump if GO breakpoint
	mov	ax,cx				; (AX) = breakpoint number
dcm1:	RestReg	<di,si>
EndProc

;***	getmemc - get bytes from memory and place in buffer
;
;	Gets as many bytes from user memory as possible.  Returns
;	an error if the first byte is invalid. This routine ignores
;	the selector limits and stops at not present pages.
;
;	errcode = getmemc(addrptr,buffer,cb,pcb);
;
;	ENTRY:	(paddrs) = offset of AddrS structure
;		(p) = offset of buffer
;		(cb) = number of bytes to get
;		(pcb) = pointer to put the number of bytes read
;
;	EXIT:	(error code) - 0 if no errors, !0 if error
;
;	USES:	AX, BX, CX, Flags
;
;	Uses C calling convention.

DefProc	getmemc, NEAR, PUBLIC, C

ArgVar	gmb_paddrs, WORD
ArgVar	gmb_p, WORD
ArgVar	gmb_cb, WORD
ArgVar	gmb_pcb, WORD

BeginProc
	SaveReg	<di>
	mov	bx,[gmb_paddrs]		; (BX) = offset of AddrS structure
	mov	cx,[gmb_cb]		; (CX) = number of bytes to get
	mov	di,[gmb_p]		; (DI) = buffer offset
	Pcall	GetMem			; go get bytes
	jc	short gmbx		; jump if error, (AX) = error code
	xor	ax,ax
	mov	di,[gmb_pcb]
	mov	[di],cx			; (CX) = number of bytes read
gmbx:	RestReg	<di>
EndProc

;***	getbuffc - get bytes from memory and place in buffer
;
;	err = getbuffc(addrptr,buffer,count);
;
;	ENTRY:	(addrptr) = offset of AddrS structure
;		(buffer) = offset of buffer
;		(count) = number of bytes to get
;
;	EXIT:	(AX) = error code (0 = no error)
;
;	USES:	AX, BX, CX, DX, Flags
;
;	Uses C calling convention.

DefProc	getbuffc, NEAR, PUBLIC, C

ArgVar	addrptr, WORD
ArgVar	buffer, WORD
ArgVar	count, WORD

BeginProc
	SaveReg	<di>
	mov	bx,addrptr		; (BX) = offset of AddrS structure
	mov	cx,count		; (CX) = number of bytes to get
	mov	di,buffer		; (DI) = buffer offset
	Pcall	GetBuff			; go get bytes
	sbb	ax,ax			; (AX) = 0 if carry clear, -1 if set
	RestReg	<di>
EndProc

;***	regval - get value of client's register
;
;	regvalue = regval(regnum);
;
;	ENTRY:	(regnum) = general register number
;
;	EXIT:	(DX:AX) = register value
;
;	USES:	AX, BX, DX, Flags
;
;	Uses C calling convention.

regtab	label	word
	dw	EAXsav			; 0 = EAX
	dw	ECXsav			; 1 = ECX
	dw	EDXsav			; 2 = EDX
	dw	EBXsav			; 3 = EBX
	dw	ESPsav			; 4 = ESP
	dw	EBPsav			; 5 = EBP
	dw	ESIsav			; 6 = ESI
	dw	EDIsav			; 7 = EDI

DefProc	regval, NEAR, PUBLIC, C

ArgVar	regnum, WORD

BeginProc
	mov	bx,regnum		; (BX) = register number
	add	bx,bx			; Scale number
	mov	bx,cs:regtab[bx]	; (BX) = offset in save area
	add	bx,pRegSA		; (BX) = offset of register
	mov	ax,[bx].LowWord		; (AX) = low word of register
	mov	dx,[bx].HighWord	; (DX) = high word of register
EndProc

;***	segregval - get client's segment register value
;
;	segvalue = segregval(segregnum);
;
;	ENTRY:	(segregnum) = segment register number
;
;	EXIT:	(AX) = segment register value
;
;	USES:	AX, BX, Flags
;
;	Uses C calling convention.

segregtab label word
	dw	ESsav			; 0 = ES
	dw	CSsav			; 1 = CS
	dw	SSsav			; 2 = SS
	dw	DSsav			; 3 = DS
	dw	FSsav			; 4 = FS
	dw	GSsav			; 5 = GS
	dw	DSsav			; 6 = Unused
	dw	DSsav			; 7 = Unused
	dw	DSsav			; 8 = Default (DS)

DefProc	segregval, NEAR, PUBLIC, C

ArgVar	segregnum, WORD

BeginProc
	mov	bx,segregnum		; (BX) = segment register number
	add	bx,bx			; Scale number
	mov	bx,cs:segregtab[bx]	; (BX) = offset in save area
	add	bx,pRegSA		; (BX) = offset of register
	mov	ax,[bx]			; (AX) = value
EndProc

;***	getdbit - return the "D" bit for the address passed
;
;	dbit = getdbit(addrptr);
;
;	ENTRY	(addrptr) = pointer to AddrS structure
;	EXIT	(AX) = D bit (0 if bit not set, !0 if bit is set).
;	USES	AX, BX, CX, DX, Flags
;
;	Uses C calling conventions.

DefProc	getdbit, NEAR, PUBLIC, C

ArgVar	gdb_addrptr, WORD

BeginProc
	SaveReg	<si, di>
	mov	bx,[gdb_addrptr]
	Pcall	GetAddrInfo		; (BX) = attribute/access byte
	mov	al,bh
	jnc	short gdb40		; use D bit in attribute byte

	mov	bx,[gdb_addrptr]
	Pcall	GetAddrType		; (AL) = address type
	cmp	al,EXPR_TYPE_SEG
	mov	ax,0
	jz	short gdbx		; assume D bit clear for seg address
	test	[DebData].InitFlag,INIT_ENV386
	jz	short gdbx		; assume D bit clear for 286 env
	mov	ax,D_COPER32		; assume D bit set for 386 env
gdb40:	and	ax,D_COPER32
gdbx:	RestReg	<di, si>
EndProc

;***	lowercase - lower case string if lower case option is set
;
;	lowercase(strptr);
;
;	ENTRY:	(strptr) = offset of string
;
;	EXIT:	NONE
;
;	USES:	AX, CX, Flags
;
;	Uses C calling convention.

DefProc	lowercase, NEAR, PUBLIC, C

ArgVar	strptr, WORD

BeginProc
	test	DebData.InitFlag,INIT_DISLWR
	jz	short lwc2
	SaveReg	<si>
	mov	si,strptr
lwc1:	lodsb
	Pcall	lower
	mov	[si-1],al
	or	al,al
	jnz	short lwc1
	RestReg	<si>
lwc2:
EndProc

;***	strlen - find length of null-terminated string
;
;	len = strlen(strptr);
;
;	ENTRY:	(strptr) = offset of string
;
;	EXIT:	(AX) = length of string (excluding terminator)
;
;	USES:	AX, CX, Flags
;
;	Uses C calling convention.

DefProc	strlen, NEAR, PUBLIC, C

ArgVar	strptr, WORD

BeginProc
	push	di
	mov	di,strptr
	xor	ax,ax
	mov	cx,-1
	repne scasb
	mov	ax,cx
	not	ax
	dec	ax			; don't count null
	pop	di
EndProc

;***	strcpylc - copy string and lower case if lower case option set
;
;	dest = strcpylc(dest, source);
;
;	ENTRY:	(dest) = offset of destination string
;		(source) = offset of source string
;
;	EXIT:	(AX) = offset of destination string
;
;	USES:	AX, ES, Flags
;
;	Uses C calling convention.

DefProc	strcpylc, NEAR, PUBLIC, C

ArgVar	dest, WORD
ArgVar	source, WORD

	test	DebData.InitFlag,INIT_DISLWR
	jz	short strcpy
BeginProc
	SaveReg	<si, di>
	mov	si,source
	mov	di,dest
scl1:	lodsb
	Pcall	lower
	stosb
	or	al,al
	jnz	short scl1
	mov	ax,dest
	RestReg	<di, si>
EndProc

;***	strcpy - copy string
;
;	dest = strcpy(dest, source);
;
;	ENTRY:	(dest) = offset of destination string
;		(source) = offset of source string
;
;	EXIT:	(AX) = offset of destination string
;
;	USES:	AX, ES, Flags
;
;	Uses C calling convention.

DefProc	strcpy, NEAR, PUBLIC, C

ArgVar	dest, WORD
ArgVar	source, WORD

BeginProc
	SaveReg	<si, di>
	mov	si,dest
	mov	di,source
	mov	cx,-1
	xor	ax,ax
	repne scasb
	not	cx
	sub	di,cx
	xchg	si,di
	shr	cx,1
	rep movsw
	adc	cx,cx
	rep movsb
	mov	ax,dest
	RestReg	<di, si>
EndProc

;***	prntf - print format string
;
;	prntf(fmt, parm)
;
;	ENTRY:	(fmt) = format string
;		(parm) = first parameter (if any)
;
;	EXIT:	NONE
;
;	USES:	Flags
;
;	Uses C calling convention.

DefProc	prntf, NEAR, PUBLIC, C

ArgVar	fmt, WORD
ArgVar	parm, WORD
LocVar	buffer, 256

BeginProc
	SaveReg	<ax, bx, cx, dx>
	lea	ax,buffer
	lea	bx,parm
	Ccall	_sprntf, <ax, fmt, bx>
	lea	dx,buffer
	Pcall	rprbuf
	RestReg	<dx, cx, bx, ax>
EndProc

;***	__aNlshl - long shift left
;
;	ENTRY:	(DX:AX) = long integer
;		(CL) = shift count
;
;	EXIT:	(DX:AX) = long integer shifted left by shift count
;
;	USES:	AX, CX, DX, Flags
;

DefProc	__aNlshl, NEAR, PUBLIC, C
	and	cx,1Fh			; Mask shift count
	jz	short sl1		; Exit if count zero
sl0:	shl	ax,1			; Shift AX left once
	rcl	dx,1			; Rotate DX left through carry once
	loop	short sl0		; Loop until done
sl1:
EndProc

;***	__aNlshr - long shift right
;
;	ENTRY:	(DX:AX) = long integer
;		(CL) = shift count
;
;	EXIT:	(DX:AX) = long integer shifted right by shift count
;
;	USES:	AX, CX, DX, Flags

DefProc	__aNlshr, NEAR, PUBLIC, C
	and	cx,1Fh			; Mask shift count
	jz	short sr1		; Exit if count zero
sr0:	sar	dx,1			; Shift DX right once, propagate sign
	rcr	ax,1			; Rotate AX right through carry once
	loop	short sr0		; Loop until done
sr1:
EndProc

;***	__aNulshr - unsigned long shift right
;
;	ENTRY:	(DX:AX) = unsigned long integer
;		(CL) = shift count
;
;	EXIT:	(DX:AX) = unsigned long integer shifted right by shift count
;
;	USES:	AX, CX, DX, Flags

DefProc	__aNulshr, NEAR, PUBLIC, C
	and	cx,1Fh			; Mask shift count
	jz	short usr1		; Exit if count zero
usr0:	shr	dx,1			; Shift DX right once
	rcr	ax,1			; Rotate AX right through carry once
	loop	short usr0		; Loop until done
usr1:
EndProc

CodeSegmentEnd

	end
