.Xr botch fix
[unix-history] / usr / src / old / adb / common_source / access.c
CommitLineData
f582ecdc 1#ifndef lint
23f18bc6 2static char sccsid[] = "@(#)access.c 5.3 (Berkeley) %G%";
f582ecdc
KB
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
13off_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 */
26int
27adbio(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
23f18bc6
KB
38 static char *derr = "data address not found";
39 static char *terr = "text address not found";
f582ecdc
KB
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 */
100int
101readcore(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.
f582ecdc 125 */
3ffa3d77
CT
126struct cache {
127 short rop, wop; /* ptrace ops for read and write */
128 int valid; /* true iff cache entry valid */
129 int *addr; /* address of cached value */
130 int val; /* and the value */
131};
132static struct cache icache = { PT_READ_I, PT_WRITE_I };
133static struct cache dcache = { PT_READ_D, PT_WRITE_D };
134
135/*
136 * Invalidate one or both caches.
137 * This is the only function that accepts two spaces simultaneously.
138 */
139cacheinval(space)
140 int space;
141{
142
143 if (space & SP_INSTR)
144 icache.valid = 0;
145 if (space & SP_DATA)
146 dcache.valid = 0;
147}
148
f582ecdc
KB
149int cachehit, cachemiss; /* statistics */
150
151static int
152cptrace(rw, space, p, addr, val)
153 enum rwmode rw;
154 int space, p, *addr, *val;
155{
3ffa3d77 156 register struct cache *c = space & SP_DATA ? &dcache : &icache;
f582ecdc
KB
157 int v;
158
f582ecdc 159 if (rw == RWMODE_READ) {
3ffa3d77 160 if (c->valid && c->addr == addr) {
f582ecdc
KB
161 cachehit++;
162 *val = c->val;
163 return (0);
164 }
165 cachemiss++;
166 errno = 0;
167 if ((v = ptrace(c->rop, p, addr, 0)) == -1 && errno)
168 return (-1);
169 *val = v;
170 } else {
3ffa3d77 171 c->valid = 0; /* paranoia */
f582ecdc
KB
172 errno = 0;
173 if (ptrace(c->wop, p, addr, v = *val) == -1 && errno)
174 return (-1);
175 }
3ffa3d77 176 c->valid = 1;
f582ecdc
KB
177 c->addr = addr;
178 c->val = v;
179 return (0);
180}
181
182int
183io_ptrace(rw, space, rmtaddr, localaddr, cnt)
184 register enum rwmode rw;
185 register int space;
186 addr_t rmtaddr;
187 register caddr_t localaddr;
188 register int cnt;
189{
190 register addr_t addr;
191 register int nbytes, ret = 0, off;
192 int tmp;
193
194 /*
195 * Start by aligning rmtaddr; set nbytes to the number of bytes of
196 * useful data we shall obtain.
197 */
198 off = rmtaddr % sizeof(int); /* addr_t is unsigned */
199 addr = rmtaddr - off;
200 nbytes = sizeof(int) - off;
201 while (cnt != 0) {
202 if (cnt < nbytes)
203 nbytes = cnt;
204 if (rw == RWMODE_READ) {
205 if (cptrace(rw, space, pid, (int *)addr, &tmp))
206 return (ret);
207 bcopy((caddr_t)&tmp + off, localaddr, nbytes);
208 } else {
209 if (nbytes < sizeof(int) &&
210 cptrace(RWMODE_READ, space, pid, (int *)addr, &tmp))
211 return (ret);
212 bcopy(localaddr, (caddr_t)&tmp + off, nbytes);
213 if (cptrace(rw, space, pid, (int *)addr, &tmp))
214 return (ret);
215 }
216 addr += sizeof(int);
217 localaddr += nbytes;
218 ret += nbytes;
219 cnt -= nbytes;
220 /*
221 * For the rest of the loop, the offset is 0 and we can
222 * use all the bytes obtained.
223 */
224 off = 0;
225 nbytes = sizeof(int);
226 }
227 return (ret);
228}