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