xref: /csrg-svn/old/adb/common_source/access.c (revision 36679)
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