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