1*47822Sbostic /*-
2*47822Sbostic * Copyright (c) 1991 The Regents of the University of California.
3*47822Sbostic * All rights reserved.
4*47822Sbostic *
5*47822Sbostic * %sccs.include.proprietary.c%
6*47822Sbostic */
7*47822Sbostic
836559Sbostic #ifndef lint
9*47822Sbostic static char sccsid[] = "@(#)access.c 5.4 (Berkeley) 04/04/91";
10*47822Sbostic #endif /* not lint */
1136559Sbostic
1236559Sbostic /*
1336559Sbostic * Adb: access data in file/process address space.
1436559Sbostic */
1536559Sbostic
1636559Sbostic #include "defs.h"
1736559Sbostic #include <sys/file.h>
1836559Sbostic #include <sys/ptrace.h>
1936559Sbostic
2036559Sbostic off_t lseek();
2136559Sbostic
2236559Sbostic /*
2336559Sbostic * Read or write from or to the given address, accessing or altering
2436559Sbostic * only the given byte(s). Return the number of bytes transferred.
2536559Sbostic * Remote (debuggee) addresses are specified as a <space,address> pair.
2636559Sbostic * Neither the remote nor the local address need be aligned.
2736559Sbostic *
2836559Sbostic * If there is a current process, ask the system to do this (via ptrace
2936559Sbostic * [ick]). If debugging the kernel, use vtophys() to map virtual to
3036559Sbostic * physical locations (in a system-dependent manner). Otherwise we
3136559Sbostic * can just read or write the files being debugged directly.
3236559Sbostic */
3336559Sbostic int
adbio(rw,space,rmtaddr,localaddr,cnt)3436559Sbostic adbio(rw, space, rmtaddr, localaddr, cnt)
3536559Sbostic enum rwmode rw;
3636559Sbostic int space;
3736559Sbostic addr_t rmtaddr;
3836559Sbostic caddr_t localaddr;
3936559Sbostic int cnt;
4036559Sbostic {
4136559Sbostic register int ret;
4236559Sbostic register struct map *mp;
4336559Sbostic struct m1 *mm;
4436559Sbostic
4539151Sbostic static char *derr = "data address not found";
4639151Sbostic static char *terr = "text address not found";
4736559Sbostic #define rwerr() errflag = space & SP_DATA ? derr : terr
4836559Sbostic #define within(which) (rmtaddr >= which.b && rmtaddr < which.e)
4936559Sbostic
5036559Sbostic if (space == SP_NONE) {
5136559Sbostic /* The no-space is all zero. */
5236559Sbostic bzero(localaddr, cnt);
5336559Sbostic return (cnt);
5436559Sbostic }
5536559Sbostic if (pid) {
5636559Sbostic ret = io_ptrace(rw, space, rmtaddr, localaddr, cnt);
5736559Sbostic if (ret != cnt)
5836559Sbostic rwerr();
5936559Sbostic return (ret);
6036559Sbostic }
6136559Sbostic if (rw == RWMODE_WRITE && !wtflag)
6236559Sbostic error("not in write mode");
6336559Sbostic mp = space & SP_DATA ? &datmap : &txtmap;
6436559Sbostic if ((space & SP_STAR) == 0 && within(mp->m1))
6536559Sbostic mm = &mp->m1;
6636559Sbostic else if (within(mp->m2))
6736559Sbostic mm = &mp->m2;
6836559Sbostic else {
6936559Sbostic rwerr();
7036559Sbostic return (0);
7136559Sbostic }
7236559Sbostic rmtaddr += mm->f - mm->b;
7336559Sbostic if (kernel && space == SP_DATA) {
7436559Sbostic char *err = NULL;
7536559Sbostic
7636559Sbostic rmtaddr = vtophys(rmtaddr, &err);
7736559Sbostic if (err) {
7836559Sbostic errflag = err;
7936559Sbostic return (0);
8036559Sbostic }
8136559Sbostic }
8236559Sbostic if (lseek(mp->ufd, (off_t)rmtaddr, 0) == -1) {
8336559Sbostic rwerr();
8436559Sbostic return (0);
8536559Sbostic }
8636559Sbostic if (rw == RWMODE_READ) {
8736559Sbostic ret = read(mp->ufd, localaddr, cnt);
8836559Sbostic /* gratuitously supply extra zeroes at end of file */
8936559Sbostic if (ret > 0 && ret < cnt) {
9036559Sbostic bzero(localaddr + ret, cnt - ret);
9136559Sbostic ret = cnt;
9236559Sbostic }
9336559Sbostic } else
9436559Sbostic ret = write(mp->ufd, localaddr, cnt);
9536559Sbostic if (ret != cnt)
9636559Sbostic rwerr();
9736559Sbostic return (ret);
9836559Sbostic #undef rwerr
9936559Sbostic #undef within
10036559Sbostic }
10136559Sbostic
10236559Sbostic /*
10336559Sbostic * Read a single object of length `len' from the core file at the
10436559Sbostic * given offset. Return the length read. (This routine allows vtophys
10536559Sbostic * and kernel crash startup code to read ptes, etc.)
10636559Sbostic */
10736559Sbostic int
readcore(off,addr,len)10836559Sbostic readcore(off, addr, len)
10936559Sbostic off_t off;
11036559Sbostic caddr_t addr;
11136559Sbostic int len;
11236559Sbostic {
11336559Sbostic
11436559Sbostic if (lseek(corefile.fd, off, L_SET) == -1)
11536559Sbostic return (-1);
11636559Sbostic return (read(corefile.fd, addr, len));
11736559Sbostic }
11836559Sbostic
11936559Sbostic /*
12036559Sbostic * THE FOLLOWING IS GROSS. WE SHOULD REPLACE PTRACE WITH SPECIAL
12136559Sbostic * FILES A LA /proc.
12236559Sbostic *
12336559Sbostic * Read or write using ptrace. io_ptrace arranges that the
12436559Sbostic * addresses passed to ptrace are an even multiple of sizeof(int),
12536559Sbostic * and is able to read or write single bytes.
12636559Sbostic *
12736559Sbostic * Since ptrace is so horribly slow, and some commands do repeated
12836559Sbostic * reading of units smaller than an `int', io_ptrace calls cptrace
12936559Sbostic * (cached ptrace) to allow some cacheing. cptrace also converts a
13036559Sbostic * read/write op and a space into a ptrace op, and returns 0 on success
13136559Sbostic * and hence takes a pointer to the value cell rather than the value.
13236559Sbostic */
13336679Storek struct cache {
13436679Storek short rop, wop; /* ptrace ops for read and write */
13536679Storek int valid; /* true iff cache entry valid */
13636679Storek int *addr; /* address of cached value */
13736679Storek int val; /* and the value */
13836679Storek };
13936679Storek static struct cache icache = { PT_READ_I, PT_WRITE_I };
14036679Storek static struct cache dcache = { PT_READ_D, PT_WRITE_D };
14136679Storek
14236679Storek /*
14336679Storek * Invalidate one or both caches.
14436679Storek * This is the only function that accepts two spaces simultaneously.
14536679Storek */
cacheinval(space)14636679Storek cacheinval(space)
14736679Storek int space;
14836679Storek {
14936679Storek
15036679Storek if (space & SP_INSTR)
15136679Storek icache.valid = 0;
15236679Storek if (space & SP_DATA)
15336679Storek dcache.valid = 0;
15436679Storek }
15536679Storek
15636559Sbostic int cachehit, cachemiss; /* statistics */
15736559Sbostic
15836559Sbostic static int
cptrace(rw,space,p,addr,val)15936559Sbostic cptrace(rw, space, p, addr, val)
16036559Sbostic enum rwmode rw;
16136559Sbostic int space, p, *addr, *val;
16236559Sbostic {
16336679Storek register struct cache *c = space & SP_DATA ? &dcache : &icache;
16436559Sbostic int v;
16536559Sbostic
16636559Sbostic if (rw == RWMODE_READ) {
16736679Storek if (c->valid && c->addr == addr) {
16836559Sbostic cachehit++;
16936559Sbostic *val = c->val;
17036559Sbostic return (0);
17136559Sbostic }
17236559Sbostic cachemiss++;
17336559Sbostic errno = 0;
17436559Sbostic if ((v = ptrace(c->rop, p, addr, 0)) == -1 && errno)
17536559Sbostic return (-1);
17636559Sbostic *val = v;
17736559Sbostic } else {
17836679Storek c->valid = 0; /* paranoia */
17936559Sbostic errno = 0;
18036559Sbostic if (ptrace(c->wop, p, addr, v = *val) == -1 && errno)
18136559Sbostic return (-1);
18236559Sbostic }
18336679Storek c->valid = 1;
18436559Sbostic c->addr = addr;
18536559Sbostic c->val = v;
18636559Sbostic return (0);
18736559Sbostic }
18836559Sbostic
18936559Sbostic int
io_ptrace(rw,space,rmtaddr,localaddr,cnt)19036559Sbostic io_ptrace(rw, space, rmtaddr, localaddr, cnt)
19136559Sbostic register enum rwmode rw;
19236559Sbostic register int space;
19336559Sbostic addr_t rmtaddr;
19436559Sbostic register caddr_t localaddr;
19536559Sbostic register int cnt;
19636559Sbostic {
19736559Sbostic register addr_t addr;
19836559Sbostic register int nbytes, ret = 0, off;
19936559Sbostic int tmp;
20036559Sbostic
20136559Sbostic /*
20236559Sbostic * Start by aligning rmtaddr; set nbytes to the number of bytes of
20336559Sbostic * useful data we shall obtain.
20436559Sbostic */
20536559Sbostic off = rmtaddr % sizeof(int); /* addr_t is unsigned */
20636559Sbostic addr = rmtaddr - off;
20736559Sbostic nbytes = sizeof(int) - off;
20836559Sbostic while (cnt != 0) {
20936559Sbostic if (cnt < nbytes)
21036559Sbostic nbytes = cnt;
21136559Sbostic if (rw == RWMODE_READ) {
21236559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp))
21336559Sbostic return (ret);
21436559Sbostic bcopy((caddr_t)&tmp + off, localaddr, nbytes);
21536559Sbostic } else {
21636559Sbostic if (nbytes < sizeof(int) &&
21736559Sbostic cptrace(RWMODE_READ, space, pid, (int *)addr, &tmp))
21836559Sbostic return (ret);
21936559Sbostic bcopy(localaddr, (caddr_t)&tmp + off, nbytes);
22036559Sbostic if (cptrace(rw, space, pid, (int *)addr, &tmp))
22136559Sbostic return (ret);
22236559Sbostic }
22336559Sbostic addr += sizeof(int);
22436559Sbostic localaddr += nbytes;
22536559Sbostic ret += nbytes;
22636559Sbostic cnt -= nbytes;
22736559Sbostic /*
22836559Sbostic * For the rest of the loop, the offset is 0 and we can
22936559Sbostic * use all the bytes obtained.
23036559Sbostic */
23136559Sbostic off = 0;
23236559Sbostic nbytes = sizeof(int);
23336559Sbostic }
23436559Sbostic return (ret);
23536559Sbostic }
236