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
adbio(rw,space,rmtaddr,localaddr,cnt)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
readcore(off,addr,len)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 */
cacheinval(space)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
cptrace(rw,space,p,addr,val)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
io_ptrace(rw,space,rmtaddr,localaddr,cnt)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