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 . 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 . 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; iu_ovdata.uo_curov),0); var[VARC] = ovno; ((U *)corhdr)->u_ovdata.uo_curov = ovno; setovmap(ovno); FI ! ! /* REALing poINT */ ! FOR i=FROFF; iu_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 #include #include + #include #include + #include #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; iu_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 ============