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