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