1*36559Sbostic #ifndef lint 2*36559Sbostic static char sccsid[] = "@(#)access.c 5.1 (Berkeley) 01/16/89"; 3*36559Sbostic #endif 4*36559Sbostic 5*36559Sbostic /* 6*36559Sbostic * Adb: access data in file/process address space. 7*36559Sbostic */ 8*36559Sbostic 9*36559Sbostic #include "defs.h" 10*36559Sbostic #include <sys/file.h> 11*36559Sbostic #include <sys/ptrace.h> 12*36559Sbostic 13*36559Sbostic off_t lseek(); 14*36559Sbostic 15*36559Sbostic /* 16*36559Sbostic * Read or write from or to the given address, accessing or altering 17*36559Sbostic * only the given byte(s). Return the number of bytes transferred. 18*36559Sbostic * Remote (debuggee) addresses are specified as a <space,address> pair. 19*36559Sbostic * Neither the remote nor the local address need be aligned. 20*36559Sbostic * 21*36559Sbostic * If there is a current process, ask the system to do this (via ptrace 22*36559Sbostic * [ick]). If debugging the kernel, use vtophys() to map virtual to 23*36559Sbostic * physical locations (in a system-dependent manner). Otherwise we 24*36559Sbostic * can just read or write the files being debugged directly. 25*36559Sbostic */ 26*36559Sbostic int 27*36559Sbostic adbio(rw, space, rmtaddr, localaddr, cnt) 28*36559Sbostic enum rwmode rw; 29*36559Sbostic int space; 30*36559Sbostic addr_t rmtaddr; 31*36559Sbostic caddr_t localaddr; 32*36559Sbostic int cnt; 33*36559Sbostic { 34*36559Sbostic register int ret; 35*36559Sbostic register struct map *mp; 36*36559Sbostic struct m1 *mm; 37*36559Sbostic 38*36559Sbostic static char derr[] = "data address not found"; 39*36559Sbostic static char terr[] = "text address not found"; 40*36559Sbostic #define rwerr() errflag = space & SP_DATA ? derr : terr 41*36559Sbostic #define within(which) (rmtaddr >= which.b && rmtaddr < which.e) 42*36559Sbostic 43*36559Sbostic if (space == SP_NONE) { 44*36559Sbostic /* The no-space is all zero. */ 45*36559Sbostic bzero(localaddr, cnt); 46*36559Sbostic return (cnt); 47*36559Sbostic } 48*36559Sbostic if (pid) { 49*36559Sbostic ret = io_ptrace(rw, space, rmtaddr, localaddr, cnt); 50*36559Sbostic if (ret != cnt) 51*36559Sbostic rwerr(); 52*36559Sbostic return (ret); 53*36559Sbostic } 54*36559Sbostic if (rw == RWMODE_WRITE && !wtflag) 55*36559Sbostic error("not in write mode"); 56*36559Sbostic mp = space & SP_DATA ? &datmap : &txtmap; 57*36559Sbostic if ((space & SP_STAR) == 0 && within(mp->m1)) 58*36559Sbostic mm = &mp->m1; 59*36559Sbostic else if (within(mp->m2)) 60*36559Sbostic mm = &mp->m2; 61*36559Sbostic else { 62*36559Sbostic rwerr(); 63*36559Sbostic return (0); 64*36559Sbostic } 65*36559Sbostic rmtaddr += mm->f - mm->b; 66*36559Sbostic if (kernel && space == SP_DATA) { 67*36559Sbostic char *err = NULL; 68*36559Sbostic 69*36559Sbostic rmtaddr = vtophys(rmtaddr, &err); 70*36559Sbostic if (err) { 71*36559Sbostic errflag = err; 72*36559Sbostic return (0); 73*36559Sbostic } 74*36559Sbostic } 75*36559Sbostic if (lseek(mp->ufd, (off_t)rmtaddr, 0) == -1) { 76*36559Sbostic rwerr(); 77*36559Sbostic return (0); 78*36559Sbostic } 79*36559Sbostic if (rw == RWMODE_READ) { 80*36559Sbostic ret = read(mp->ufd, localaddr, cnt); 81*36559Sbostic /* gratuitously supply extra zeroes at end of file */ 82*36559Sbostic if (ret > 0 && ret < cnt) { 83*36559Sbostic bzero(localaddr + ret, cnt - ret); 84*36559Sbostic ret = cnt; 85*36559Sbostic } 86*36559Sbostic } else 87*36559Sbostic ret = write(mp->ufd, localaddr, cnt); 88*36559Sbostic if (ret != cnt) 89*36559Sbostic rwerr(); 90*36559Sbostic return (ret); 91*36559Sbostic #undef rwerr 92*36559Sbostic #undef within 93*36559Sbostic } 94*36559Sbostic 95*36559Sbostic /* 96*36559Sbostic * Read a single object of length `len' from the core file at the 97*36559Sbostic * given offset. Return the length read. (This routine allows vtophys 98*36559Sbostic * and kernel crash startup code to read ptes, etc.) 99*36559Sbostic */ 100*36559Sbostic int 101*36559Sbostic readcore(off, addr, len) 102*36559Sbostic off_t off; 103*36559Sbostic caddr_t addr; 104*36559Sbostic int len; 105*36559Sbostic { 106*36559Sbostic 107*36559Sbostic if (lseek(corefile.fd, off, L_SET) == -1) 108*36559Sbostic return (-1); 109*36559Sbostic return (read(corefile.fd, addr, len)); 110*36559Sbostic } 111*36559Sbostic 112*36559Sbostic /* 113*36559Sbostic * THE FOLLOWING IS GROSS. WE SHOULD REPLACE PTRACE WITH SPECIAL 114*36559Sbostic * FILES A LA /proc. 115*36559Sbostic * 116*36559Sbostic * Read or write using ptrace. io_ptrace arranges that the 117*36559Sbostic * addresses passed to ptrace are an even multiple of sizeof(int), 118*36559Sbostic * and is able to read or write single bytes. 119*36559Sbostic * 120*36559Sbostic * Since ptrace is so horribly slow, and some commands do repeated 121*36559Sbostic * reading of units smaller than an `int', io_ptrace calls cptrace 122*36559Sbostic * (cached ptrace) to allow some cacheing. cptrace also converts a 123*36559Sbostic * read/write op and a space into a ptrace op, and returns 0 on success 124*36559Sbostic * and hence takes a pointer to the value cell rather than the value. 125*36559Sbostic * 126*36559Sbostic * N.B.: The cache retains the pid, so that killing and restarting 127*36559Sbostic * a process invalidates the cache entry. If pid's were reused fast 128*36559Sbostic * enough this could fail, and we would need a cache-invalidate 129*36559Sbostic * routine, to be called whenever a process is started. Fortunately 130*36559Sbostic * that is not now the case. 131*36559Sbostic */ 132*36559Sbostic int cachehit, cachemiss; /* statistics */ 133*36559Sbostic 134*36559Sbostic static int 135*36559Sbostic cptrace(rw, space, p, addr, val) 136*36559Sbostic enum rwmode rw; 137*36559Sbostic int space, p, *addr, *val; 138*36559Sbostic { 139*36559Sbostic static struct cache { 140*36559Sbostic short rop, wop; /* ptrace ops for read and write */ 141*36559Sbostic int pid; /* pid, iff cache entry valid */ 142*36559Sbostic int *addr; /* address of cached value */ 143*36559Sbostic int val; /* and the value */ 144*36559Sbostic } cache[2] = { {PT_READ_D, PT_WRITE_D}, {PT_READ_I, PT_WRITE_I} }; 145*36559Sbostic register struct cache *c; 146*36559Sbostic int v; 147*36559Sbostic 148*36559Sbostic /* set c to point to cache[0] for dspace, cache[1] for ispace */ 149*36559Sbostic c = space & SP_DATA ? &cache[0] : &cache[1]; 150*36559Sbostic if (rw == RWMODE_READ) { 151*36559Sbostic if (c->pid == p && c->addr == addr) { 152*36559Sbostic cachehit++; 153*36559Sbostic *val = c->val; 154*36559Sbostic return (0); 155*36559Sbostic } 156*36559Sbostic cachemiss++; 157*36559Sbostic errno = 0; 158*36559Sbostic if ((v = ptrace(c->rop, p, addr, 0)) == -1 && errno) 159*36559Sbostic return (-1); 160*36559Sbostic *val = v; 161*36559Sbostic } else { 162*36559Sbostic c->pid = 0; /* paranoia */ 163*36559Sbostic errno = 0; 164*36559Sbostic if (ptrace(c->wop, p, addr, v = *val) == -1 && errno) 165*36559Sbostic return (-1); 166*36559Sbostic } 167*36559Sbostic c->pid = p; 168*36559Sbostic c->addr = addr; 169*36559Sbostic c->val = v; 170*36559Sbostic return (0); 171*36559Sbostic } 172*36559Sbostic 173*36559Sbostic int 174*36559Sbostic io_ptrace(rw, space, rmtaddr, localaddr, cnt) 175*36559Sbostic register enum rwmode rw; 176*36559Sbostic register int space; 177*36559Sbostic addr_t rmtaddr; 178*36559Sbostic register caddr_t localaddr; 179*36559Sbostic register int cnt; 180*36559Sbostic { 181*36559Sbostic register addr_t addr; 182*36559Sbostic register int nbytes, ret = 0, off; 183*36559Sbostic int tmp; 184*36559Sbostic 185*36559Sbostic /* 186*36559Sbostic * Start by aligning rmtaddr; set nbytes to the number of bytes of 187*36559Sbostic * useful data we shall obtain. 188*36559Sbostic */ 189*36559Sbostic off = rmtaddr % sizeof(int); /* addr_t is unsigned */ 190*36559Sbostic addr = rmtaddr - off; 191*36559Sbostic nbytes = sizeof(int) - off; 192*36559Sbostic while (cnt != 0) { 193*36559Sbostic if (cnt < nbytes) 194*36559Sbostic nbytes = cnt; 195*36559Sbostic if (rw == RWMODE_READ) { 196*36559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp)) 197*36559Sbostic return (ret); 198*36559Sbostic bcopy((caddr_t)&tmp + off, localaddr, nbytes); 199*36559Sbostic } else { 200*36559Sbostic if (nbytes < sizeof(int) && 201*36559Sbostic cptrace(RWMODE_READ, space, pid, (int *)addr, &tmp)) 202*36559Sbostic return (ret); 203*36559Sbostic bcopy(localaddr, (caddr_t)&tmp + off, nbytes); 204*36559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp)) 205*36559Sbostic return (ret); 206*36559Sbostic } 207*36559Sbostic addr += sizeof(int); 208*36559Sbostic localaddr += nbytes; 209*36559Sbostic ret += nbytes; 210*36559Sbostic cnt -= nbytes; 211*36559Sbostic /* 212*36559Sbostic * For the rest of the loop, the offset is 0 and we can 213*36559Sbostic * use all the bytes obtained. 214*36559Sbostic */ 215*36559Sbostic off = 0; 216*36559Sbostic nbytes = sizeof(int); 217*36559Sbostic } 218*36559Sbostic return (ret); 219*36559Sbostic } 220