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