136559Sbostic #ifndef lint 2*36679Storek static char sccsid[] = "@(#)access.c 5.2 (Berkeley) 02/04/89"; 336559Sbostic #endif 436559Sbostic 536559Sbostic /* 636559Sbostic * Adb: access data in file/process address space. 736559Sbostic */ 836559Sbostic 936559Sbostic #include "defs.h" 1036559Sbostic #include <sys/file.h> 1136559Sbostic #include <sys/ptrace.h> 1236559Sbostic 1336559Sbostic off_t lseek(); 1436559Sbostic 1536559Sbostic /* 1636559Sbostic * Read or write from or to the given address, accessing or altering 1736559Sbostic * only the given byte(s). Return the number of bytes transferred. 1836559Sbostic * Remote (debuggee) addresses are specified as a <space,address> pair. 1936559Sbostic * Neither the remote nor the local address need be aligned. 2036559Sbostic * 2136559Sbostic * If there is a current process, ask the system to do this (via ptrace 2236559Sbostic * [ick]). If debugging the kernel, use vtophys() to map virtual to 2336559Sbostic * physical locations (in a system-dependent manner). Otherwise we 2436559Sbostic * can just read or write the files being debugged directly. 2536559Sbostic */ 2636559Sbostic int 2736559Sbostic adbio(rw, space, rmtaddr, localaddr, cnt) 2836559Sbostic enum rwmode rw; 2936559Sbostic int space; 3036559Sbostic addr_t rmtaddr; 3136559Sbostic caddr_t localaddr; 3236559Sbostic int cnt; 3336559Sbostic { 3436559Sbostic register int ret; 3536559Sbostic register struct map *mp; 3636559Sbostic struct m1 *mm; 3736559Sbostic 3836559Sbostic static char derr[] = "data address not found"; 3936559Sbostic static char terr[] = "text address not found"; 4036559Sbostic #define rwerr() errflag = space & SP_DATA ? derr : terr 4136559Sbostic #define within(which) (rmtaddr >= which.b && rmtaddr < which.e) 4236559Sbostic 4336559Sbostic if (space == SP_NONE) { 4436559Sbostic /* The no-space is all zero. */ 4536559Sbostic bzero(localaddr, cnt); 4636559Sbostic return (cnt); 4736559Sbostic } 4836559Sbostic if (pid) { 4936559Sbostic ret = io_ptrace(rw, space, rmtaddr, localaddr, cnt); 5036559Sbostic if (ret != cnt) 5136559Sbostic rwerr(); 5236559Sbostic return (ret); 5336559Sbostic } 5436559Sbostic if (rw == RWMODE_WRITE && !wtflag) 5536559Sbostic error("not in write mode"); 5636559Sbostic mp = space & SP_DATA ? &datmap : &txtmap; 5736559Sbostic if ((space & SP_STAR) == 0 && within(mp->m1)) 5836559Sbostic mm = &mp->m1; 5936559Sbostic else if (within(mp->m2)) 6036559Sbostic mm = &mp->m2; 6136559Sbostic else { 6236559Sbostic rwerr(); 6336559Sbostic return (0); 6436559Sbostic } 6536559Sbostic rmtaddr += mm->f - mm->b; 6636559Sbostic if (kernel && space == SP_DATA) { 6736559Sbostic char *err = NULL; 6836559Sbostic 6936559Sbostic rmtaddr = vtophys(rmtaddr, &err); 7036559Sbostic if (err) { 7136559Sbostic errflag = err; 7236559Sbostic return (0); 7336559Sbostic } 7436559Sbostic } 7536559Sbostic if (lseek(mp->ufd, (off_t)rmtaddr, 0) == -1) { 7636559Sbostic rwerr(); 7736559Sbostic return (0); 7836559Sbostic } 7936559Sbostic if (rw == RWMODE_READ) { 8036559Sbostic ret = read(mp->ufd, localaddr, cnt); 8136559Sbostic /* gratuitously supply extra zeroes at end of file */ 8236559Sbostic if (ret > 0 && ret < cnt) { 8336559Sbostic bzero(localaddr + ret, cnt - ret); 8436559Sbostic ret = cnt; 8536559Sbostic } 8636559Sbostic } else 8736559Sbostic ret = write(mp->ufd, localaddr, cnt); 8836559Sbostic if (ret != cnt) 8936559Sbostic rwerr(); 9036559Sbostic return (ret); 9136559Sbostic #undef rwerr 9236559Sbostic #undef within 9336559Sbostic } 9436559Sbostic 9536559Sbostic /* 9636559Sbostic * Read a single object of length `len' from the core file at the 9736559Sbostic * given offset. Return the length read. (This routine allows vtophys 9836559Sbostic * and kernel crash startup code to read ptes, etc.) 9936559Sbostic */ 10036559Sbostic int 10136559Sbostic readcore(off, addr, len) 10236559Sbostic off_t off; 10336559Sbostic caddr_t addr; 10436559Sbostic int len; 10536559Sbostic { 10636559Sbostic 10736559Sbostic if (lseek(corefile.fd, off, L_SET) == -1) 10836559Sbostic return (-1); 10936559Sbostic return (read(corefile.fd, addr, len)); 11036559Sbostic } 11136559Sbostic 11236559Sbostic /* 11336559Sbostic * THE FOLLOWING IS GROSS. WE SHOULD REPLACE PTRACE WITH SPECIAL 11436559Sbostic * FILES A LA /proc. 11536559Sbostic * 11636559Sbostic * Read or write using ptrace. io_ptrace arranges that the 11736559Sbostic * addresses passed to ptrace are an even multiple of sizeof(int), 11836559Sbostic * and is able to read or write single bytes. 11936559Sbostic * 12036559Sbostic * Since ptrace is so horribly slow, and some commands do repeated 12136559Sbostic * reading of units smaller than an `int', io_ptrace calls cptrace 12236559Sbostic * (cached ptrace) to allow some cacheing. cptrace also converts a 12336559Sbostic * read/write op and a space into a ptrace op, and returns 0 on success 12436559Sbostic * and hence takes a pointer to the value cell rather than the value. 12536559Sbostic */ 126*36679Storek struct cache { 127*36679Storek short rop, wop; /* ptrace ops for read and write */ 128*36679Storek int valid; /* true iff cache entry valid */ 129*36679Storek int *addr; /* address of cached value */ 130*36679Storek int val; /* and the value */ 131*36679Storek }; 132*36679Storek static struct cache icache = { PT_READ_I, PT_WRITE_I }; 133*36679Storek static struct cache dcache = { PT_READ_D, PT_WRITE_D }; 134*36679Storek 135*36679Storek /* 136*36679Storek * Invalidate one or both caches. 137*36679Storek * This is the only function that accepts two spaces simultaneously. 138*36679Storek */ 139*36679Storek cacheinval(space) 140*36679Storek int space; 141*36679Storek { 142*36679Storek 143*36679Storek if (space & SP_INSTR) 144*36679Storek icache.valid = 0; 145*36679Storek if (space & SP_DATA) 146*36679Storek dcache.valid = 0; 147*36679Storek } 148*36679Storek 14936559Sbostic int cachehit, cachemiss; /* statistics */ 15036559Sbostic 15136559Sbostic static int 15236559Sbostic cptrace(rw, space, p, addr, val) 15336559Sbostic enum rwmode rw; 15436559Sbostic int space, p, *addr, *val; 15536559Sbostic { 156*36679Storek register struct cache *c = space & SP_DATA ? &dcache : &icache; 15736559Sbostic int v; 15836559Sbostic 15936559Sbostic if (rw == RWMODE_READ) { 160*36679Storek if (c->valid && c->addr == addr) { 16136559Sbostic cachehit++; 16236559Sbostic *val = c->val; 16336559Sbostic return (0); 16436559Sbostic } 16536559Sbostic cachemiss++; 16636559Sbostic errno = 0; 16736559Sbostic if ((v = ptrace(c->rop, p, addr, 0)) == -1 && errno) 16836559Sbostic return (-1); 16936559Sbostic *val = v; 17036559Sbostic } else { 171*36679Storek c->valid = 0; /* paranoia */ 17236559Sbostic errno = 0; 17336559Sbostic if (ptrace(c->wop, p, addr, v = *val) == -1 && errno) 17436559Sbostic return (-1); 17536559Sbostic } 176*36679Storek c->valid = 1; 17736559Sbostic c->addr = addr; 17836559Sbostic c->val = v; 17936559Sbostic return (0); 18036559Sbostic } 18136559Sbostic 18236559Sbostic int 18336559Sbostic io_ptrace(rw, space, rmtaddr, localaddr, cnt) 18436559Sbostic register enum rwmode rw; 18536559Sbostic register int space; 18636559Sbostic addr_t rmtaddr; 18736559Sbostic register caddr_t localaddr; 18836559Sbostic register int cnt; 18936559Sbostic { 19036559Sbostic register addr_t addr; 19136559Sbostic register int nbytes, ret = 0, off; 19236559Sbostic int tmp; 19336559Sbostic 19436559Sbostic /* 19536559Sbostic * Start by aligning rmtaddr; set nbytes to the number of bytes of 19636559Sbostic * useful data we shall obtain. 19736559Sbostic */ 19836559Sbostic off = rmtaddr % sizeof(int); /* addr_t is unsigned */ 19936559Sbostic addr = rmtaddr - off; 20036559Sbostic nbytes = sizeof(int) - off; 20136559Sbostic while (cnt != 0) { 20236559Sbostic if (cnt < nbytes) 20336559Sbostic nbytes = cnt; 20436559Sbostic if (rw == RWMODE_READ) { 20536559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp)) 20636559Sbostic return (ret); 20736559Sbostic bcopy((caddr_t)&tmp + off, localaddr, nbytes); 20836559Sbostic } else { 20936559Sbostic if (nbytes < sizeof(int) && 21036559Sbostic cptrace(RWMODE_READ, space, pid, (int *)addr, &tmp)) 21136559Sbostic return (ret); 21236559Sbostic bcopy(localaddr, (caddr_t)&tmp + off, nbytes); 21336559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp)) 21436559Sbostic return (ret); 21536559Sbostic } 21636559Sbostic addr += sizeof(int); 21736559Sbostic localaddr += nbytes; 21836559Sbostic ret += nbytes; 21936559Sbostic cnt -= nbytes; 22036559Sbostic /* 22136559Sbostic * For the rest of the loop, the offset is 0 and we can 22236559Sbostic * use all the bytes obtained. 22336559Sbostic */ 22436559Sbostic off = 0; 22536559Sbostic nbytes = sizeof(int); 22636559Sbostic } 22736559Sbostic return (ret); 22836559Sbostic } 229