Subject: adb(1) bug displaying FP regs for traced process (#405)
Index:	bin/adb/*.[ch] 2.11BSD

Description:
	1) adb displays garbage for the FloatingPoint registers of a 
	   traced process.

	2) adb displays the FP registers in the wrong order when examining
	   a coredump.

	3) adb uses private/local definitions for ptrace(2) function calls
	   rather than using the system provided ones in <sys/ptrace.h>.
	   adb also uses local definitions of system functions/variables 
	   such as lseek() and errno.

Repeat-By:
	1)  Set a breakpoint in a function using FP register.  Enter the
	    $f command to display the FP registers.  Note that the values
	    printed and reality have nothing in common.

	From the comments added to readregs() in runpcs.c:

/*
 * The following section was totally and completely broken.  It had been that
 * way since V7.  If you've ever wondered why the FP regs couldn't be displayed
 * for a traced program that was the reason.  The reading of the FP regs was
 * redone 1998/4/21 for 2.11BSD.
*/

	The problem was the line:

 		DO corhdr[i] = ptrace(RUREGS,pid,i,0); OD

	'i' can not be used as an 'offset' to ptrace() and an index into
	corhdr[] at the same time.  Values to ptrace() are the byte offset
	into the 'u' area (i.e. "i" has been scaled by "sizeof int") while
	corhdr[] is an array of 'int'.  Thus using 'i' as an index into
	an array of 'int' would cause 'i' to be multiplied by 'sizeof int'.

	2) From the comments added to printfregs():

/*
 * ARGH.  Completely incorrect.  Apparently the way the FP regs were stored
 * in the U area changed between V7 and 2.10/2.11BSD and adb was never fixed.
 * The kernel always saves the FP regs as 'double' and saves the registers in
 * order (0 thru 5) now.  Tended to 1998/4/21
*/

	Earlier versions of the system stored the FP regs both out of sequence
	and in variable precision.  If the program was in Double mode at the 
	time then the FP regs were stored 'double', if the program was in Single
	mode at the time the FP regs were stored 'single'.  Adb was supposed to
	sort this out by looking at the 'FP status' word.

		2.11BSD always stores the FP regs IN ORDER and in double mode.

	3)  Observation.  The local include file contained definitions which
	    duplicated under different names all the definitions present in
	    <sys/ptrace.h>.

Fix:

	To install this update cut where indicated saving to a file (/tmp/405).

	Then:

		patch -p0 < /tmp/405
		cd /usr/src/bin/adb
		make clean
		make
		make install
		make clean
		rm /tmp/405

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.IIPO.GTEGSC.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.

----------------------------cut here-------------------------
*** /usr/src/bin/adb/runpcs.c.old	Wed Jan 12 21:30:33 1994
--- /usr/src/bin/adb/runpcs.c	Tue Apr 21 20:27:54 1998
***************
*** 27,33 ****
  	long	loopcnt;
  	long	var[];
  	int	userpc=1;
- extern	int	errno;
  
  /* service routines for sub process control */
  
--- 27,32 ----
***************
*** 79,85 ****
  	register BKPTR       bkptr;
  
  	IF pid
! 	THEN ptrace(EXIT,pid,0,0); pid=0; userpc=1;
  	     FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt
  	     DO IF bkptr->flag
  		THEN bkptr->flag=BKPTSET;
--- 78,84 ----
  	register BKPTR       bkptr;
  
  	IF pid
! 	THEN ptrace(PT_KILL,pid,0,0); pid=0; userpc=1;
  	     FOR bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt
  	     DO IF bkptr->flag
  		THEN bkptr->flag=BKPTSET;
***************
*** 93,99 ****
  
  	close(fsym); fsym = -1;
  	IF (pid = fork()) == 0
! 	THEN ptrace(SETTRC,0,0,0);
  	     signal(SIGINT,sigint); signal(SIGQUIT,sigqit);
  	     doexec(); exit(0);
  	ELIF pid == -1
--- 92,98 ----
  
  	close(fsym); fsym = -1;
  	IF (pid = fork()) == 0
! 	THEN ptrace(PT_TRACE_ME,0,0,0);
  	     signal(SIGINT,sigint); signal(SIGQUIT,sigqit);
  	     doexec(); exit(0);
  	ELIF pid == -1
***************
*** 115,125 ****
  	printf("exbkpt: %d\n",bkptr->count);
  #endif
  	bkptloc = bkptr->loc;
! 	ptrace(WIUSER,pid,bkptloc,bkptr->ins);
  	stty(0,&usrtty);
! 	ptrace(SINGLE,pid,bkptloc,0);
  	bpwait(); chkerr();
! 	ptrace(WIUSER,pid,bkptloc,BPT);
  	bkptr->flag=BKPTSET;
  }
  
--- 114,124 ----
  	printf("exbkpt: %d\n",bkptr->count);
  #endif
  	bkptloc = bkptr->loc;
! 	ptrace(PT_WRITE_I,pid,bkptloc,bkptr->ins);
  	stty(0,&usrtty);
! 	ptrace(PT_STEP,pid,bkptloc,0);
  	bpwait(); chkerr();
! 	ptrace(PT_WRITE_I,pid,bkptloc,BPT);
  	bkptr->flag=BKPTSET;
  }
  
***************
*** 188,194 ****
  {
  	if (bkptr->ovly)
  		choverlay(bkptr->ovly);
! 	ptrace(WIUSER,pid,bkptr->loc,bkptr->ins);
  }
  
  /* change overlay in subprocess */
--- 187,193 ----
  {
  	if (bkptr->ovly)
  		choverlay(bkptr->ovly);
! 	ptrace(PT_WRITE_I,pid,bkptr->loc,bkptr->ins);
  }
  
  /* change overlay in subprocess */
***************
*** 197,203 ****
  {
  	errno = 0;
  	if (overlay && pid && ovno>0 && ovno<=NOVL)
! 		ptrace(WUREGS,pid,&(((U*)0)->u_ovdata.uo_curov),ovno);
  	IF errno
  	THEN printf("cannot change to overlay %d\n", ovno);
  	FI
--- 196,202 ----
  {
  	errno = 0;
  	if (overlay && pid && ovno>0 && ovno<=NOVL)
! 		ptrace(PT_WRITE_U,pid,&(((U*)0)->u_ovdata.uo_curov),ovno);
  	IF errno
  	THEN printf("cannot change to overlay %d\n", ovno);
  	FI
***************
*** 221,228 ****
  	a = bkptr->loc;
  	if (bkptr->ovly)
  		choverlay(bkptr->ovly);
! 	bkptr->ins = ptrace(RIUSER, pid, a, 0);
! 	ptrace(WIUSER, pid, a, BPT);
  	IF errno
  	THEN printf("cannot set breakpoint: ");
  	     psymoff(leng(bkptr->loc),ISYM,"\n");
--- 220,227 ----
  	a = bkptr->loc;
  	if (bkptr->ovly)
  		choverlay(bkptr->ovly);
! 	bkptr->ins = ptrace(PT_READ_I, pid, a, 0);
! 	ptrace(PT_WRITE_I, pid, a, BPT);
  	IF errno
  	THEN printf("cannot set breakpoint: ");
  	     psymoff(leng(bkptr->loc),ISYM,"\n");
***************
*** 265,276 ****
  readregs()
  {
  	/*get REG values from pcs*/
! 	register int i;
  	char	ovno;
  
  	FOR i=0; i<NREG; i++
  	DO uar0[reglist[i].roffs] =
! 		    ptrace(RUREGS, pid,
   		        (int *)((int)&uar0[reglist[i].roffs] - (int)&corhdr),
   			0);
  	OD
--- 264,275 ----
  readregs()
  {
  	/*get REG values from pcs*/
! 	register u_int i, *afp;
  	char	ovno;
  
  	FOR i=0; i<NREG; i++
  	DO uar0[reglist[i].roffs] =
! 		    ptrace(PT_READ_U, pid,
   		        (int *)((int)&uar0[reglist[i].roffs] - (int)&corhdr),
   			0);
  	OD
***************
*** 277,290 ****
  	/* if overlaid, get ov */
  	IF overlay
  	THEN
! 		ovno = ptrace(RUREGS, pid,
  		    &(((struct user *)0)->u_ovdata.uo_curov),0);
  		var[VARC] = ovno;
  		((U *)corhdr)->u_ovdata.uo_curov = ovno;
  		setovmap(ovno);
  	FI
! 
! 	/* REALing poINT                */
! 	FOR i=FROFF; i<FRLEN+FROFF; i++
! 	DO corhdr[i] = ptrace(RUREGS,pid,i,0); OD
  }
--- 276,298 ----
  	/* if overlaid, get ov */
  	IF overlay
  	THEN
! 		ovno = ptrace(PT_READ_U, pid,
  		    &(((struct user *)0)->u_ovdata.uo_curov),0);
  		var[VARC] = ovno;
  		((U *)corhdr)->u_ovdata.uo_curov = ovno;
  		setovmap(ovno);
  	FI
! /*
!  * The following section was totally and completely broken.  It had been that
!  * way since V7.  If you've ever wondered why the FP regs couldn't be displayed
!  * for a traced program that was the reason.  The reading of the FP regs was
!  * redone 1998/4/21 for 2.11BSD.
! */
! 	i = offsetof(struct user, u_fps);
! 	afp = (u_int *)&((U *)corhdr)->u_fps;
! 	while	(i < offsetof(struct user, u_fps) + sizeof (struct fps))
! 		{
! 		*afp++ = ptrace(PT_READ_U, pid, i, 0);
! 		i += sizeof (u_int);
! 		}
  }
*** /usr/src/bin/adb/defs.h.old	Thu Jan 13 20:28:34 1994
--- /usr/src/bin/adb/defs.h	Tue Apr 21 21:51:52 1998
***************
*** 2,7 ****
--- 2,9 ----
   *
   *      UNIX debugger - common definitions
   *
+  *	1998/4/21 - remove local redefinitions used with ptrace
+  *
   *      Layout of a.out file (fsym):
   *
   *	This has changed over time - see a.out.h, sys/exec.h and nlist.h
***************
*** 13,19 ****
--- 15,23 ----
  #include <machine/reg.h>
  #include <sgtty.h>
  #include <setjmp.h>
+ #include <unistd.h>
  #include <a.out.h>
+ #include <sys/ptrace.h>
  
  #define	MAXSYMLEN	32
  #define MAXCOM	64
***************
*** 105,120 ****
  	int	roffs;
  };
  
- struct Sfp {
- 	int	fpsr;
- 	float	Sfr[6];
- };
- 
- struct Lfp {
- 	int	fpsr;
- 	double	Lfr[6];
- };
- 
  /*
   * Internal variables ---
   *  They are addressed by name. (e.g. (`0'-`9', `a'-`b'))
--- 109,114 ----
***************
*** 145,166 ****
  #define BKPTEXEC 2
  
  #define BPT     03
- #define FD      0200
- #define SETTRC  0
- #define RDUSER  2
- #define RIUSER  1
- #define WDUSER  5
- #define WIUSER  4
- #define RUREGS  3
- #define WUREGS  6
- #define CONTIN  7
- #define SINGLE  9
- #define EXIT    8
  
- #define FROFF   ((int)&(((U*)0)->u_fps))
- #define FRLEN   25
- #define FRMAX   6
- 
  #define NOREG   32767           /* impossible return from getreg() */
  #define NREG    9       /* 8 regs + PS from kernel stack */
  /*
--- 139,145 ----
***************
*** 217,220 ****
  
  struct sgttyb adbtty, usrtty;
  jmp_buf erradb;
- extern	off_t	lseek();
--- 196,198 ----
*** /usr/src/bin/adb/access.c.old	Fri Dec 31 11:14:34 1993
--- /usr/src/bin/adb/access.c	Tue Apr 21 20:07:44 1998
***************
*** 13,21 ****
  	char	curov;
  	int	overlay;
  	long	var[];
- 
- extern	int     errno;
- 
  	static	within();
  
  /* file handling and access routines */
--- 13,18 ----
***************
*** 55,61 ****
  
  	IF pid          /* tracing on? */
  	THEN IF (adr&01) ANDF !rd THEN error(ODDADR); FI
! 	     pmode = (space&DSP?(rd?RDUSER:WDUSER):(rd?RIUSER:WIUSER));
  	     if (bkptr=scanbkpt((u_int)adr)) {
  		if (rd) {
  		    return(bkptr->ins);
--- 52,58 ----
  
  	IF pid          /* tracing on? */
  	THEN IF (adr&01) ANDF !rd THEN error(ODDADR); FI
! 	     pmode = (space&DSP?(rd?PT_READ_D:PT_WRITE_D):(rd?PT_READ_I:PT_WRITE_I));
  	     if (bkptr=scanbkpt((u_int)adr)) {
  		if (rd) {
  		    return(bkptr->ins);
*** /usr/src/bin/adb/command.c.old	Wed Jan 12 23:03:10 1994
--- /usr/src/bin/adb/command.c	Tue Apr 21 20:08:19 1998
***************
*** 176,182 ****
  		lastcom=0; savc=rdc();
  		IF (regptr=getreg(savc)) != NOREG
  		THEN uar0[regptr]=shorten(dot);
! 		     ptrace(WUREGS,pid,(int)&uar0[regptr]-(int)&corhdr,
  			uar0[regptr]);
  		     IF (uar0+regptr) == &(((U*)corhdr)->u_ovdata.uo_curov)
  		     THEN var[VARC]=dot; setovmap((char)dot); FI
--- 176,182 ----
  		lastcom=0; savc=rdc();
  		IF (regptr=getreg(savc)) != NOREG
  		THEN uar0[regptr]=shorten(dot);
! 		     ptrace(PT_WRITE_U,pid,(int)&uar0[regptr]-(int)&corhdr,
  			uar0[regptr]);
  		     IF (uar0+regptr) == &(((U*)corhdr)->u_ovdata.uo_curov)
  		     THEN var[VARC]=dot; setovmap((char)dot); FI
*** /usr/src/bin/adb/pcs.c.old	Fri Dec 31 11:12:12 1993
--- /usr/src/bin/adb/pcs.c	Tue Apr 21 20:12:41 1998
***************
*** 93,104 ****
  		endpcs();
  		setup();
  		setbp();
! 		runmode=CONTIN;
  		break;
  
  	    /* single step */
  	    case 's': case 'S':
! 		runmode=SINGLE;
  		IF pid
  		THEN execsig=getsig(signo);
  		ELSE setup(); loopcnt--;
--- 93,104 ----
  		endpcs();
  		setup();
  		setbp();
! 		runmode=PT_CONTINUE;
  		break;
  
  	    /* single step */
  	    case 's': case 'S':
! 		runmode=PT_STEP;
  		IF pid
  		THEN execsig=getsig(signo);
  		ELSE setup(); loopcnt--;
***************
*** 108,114 ****
  	    /* continue with optional signal */
  	    case 'c': case 'C': case 0:
  		IF pid==0 THEN error(NOPCS); FI
! 		runmode=CONTIN;
  		execsig=getsig(signo);
  		break;
  
--- 108,114 ----
  	    /* continue with optional signal */
  	    case 'c': case 'C': case 0:
  		IF pid==0 THEN error(NOPCS); FI
! 		runmode=PT_CONTINUE;
  		execsig=getsig(signo);
  		break;
  
*** /usr/src/bin/adb/print.c.old	Wed Jan 12 23:30:43 1994
--- /usr/src/bin/adb/print.c	Tue Apr 21 21:44:12 1998
***************
*** 22,28 ****
  	int	octal;
  	long	localval;
  	BKPTR   bkpthead;
- static	char	frnames[] = { 0, 3, 4, 5, 1, 2 };
  	char    lastc;
  	u_int	corhdr[];
  	u_int	*uar0;
--- 22,27 ----
***************
*** 333,354 ****
  	printc(EOR);
  }
  
  printfregs(longpr)
! {
  	register int i;
! 	double f;
! 	struct Lfp *pfp;
  
! 	pfp = (struct Lfp *)&((U*)corhdr)->u_fps.u_fpsr;
! 	printf("fpsr\t%o\n", pfp->fpsr);
! 	FOR i=0; i<FRMAX; i++
! 	DO      IF ((U*)corhdr)->u_fps.u_fpsr&FD ORF longpr /* long mode */
! 		THEN    f = pfp->Lfr[frnames[i]];
! 		ELSE    f = ((struct Sfp *)pfp)->Sfr[frnames[i]];
! 		FI
! 		printf("fr%-8d%-32.18f\n", i, f);
! 	OD
! }
  
  printregs()
  {
--- 332,360 ----
  	printc(EOR);
  }
  
+ /*
+  * ARGH.  Completely incorrect.  Apparently the way the FP regs were stored
+  * in the U area changed between V7 and 2.10/2.11BSD and adb was never fixed.
+  * The kernel always saves the FP regs as 'double' and saves the registers in
+  * order (0 thru 5) now.  Tended to 1998/4/21
+ */
+ 
  printfregs(longpr)
! 	int	longpr;
! 	{
  	register int i;
! 	int	prec;
! 	register struct fps *pfp;
  
! 	pfp = (struct fps *)&((U*)corhdr)->u_fps;
! 	printf("fpsr\t%o\n", pfp->u_fpsr);
! 	if	(longpr || (pfp->u_fpsr & 0200))
! 		prec = 16;
! 	else
! 		prec = 8;
! 	for	(i = 0; i < 6; i++)
! 		printf("fr%d\t%-24.*f\n", i, prec, pfp->u_fpregs[i]);
! 	}
  
  printregs()
  {
*** /usr/src/bin/adb/Makefile.old	Thu Jan 13 23:25:06 1994
--- /usr/src/bin/adb/Makefile	Tue Apr 21 22:07:48 1998
***************
*** 12,18 ****
  	${CC} ${SEPFLAG} ${LDFLAGS} -o adb ${OFILES}
  
  install: adb
! 	install -s adb ${DESTDIR}/bin
  
  clean:
  	-rm -f adb ${OFILES}
--- 12,18 ----
  	${CC} ${SEPFLAG} ${LDFLAGS} -o adb ${OFILES}
  
  install: adb
! 	install -m 755 -s adb ${DESTDIR}/bin
  
  clean:
  	-rm -f adb ${OFILES}
*** /VERSION.old	Fri Apr 24 19:51:28 1998
--- /VERSION	Thu Apr 30 20:09:49 1998
***************
*** 1,5 ****
! Current Patch Level: 404
! Date: April 24, 1998
  
  2.11 BSD
  ============
--- 1,5 ----
! Current Patch Level: 405
! Date: April 30, 1998
  
  2.11 BSD
  ============
