* Copyright (c) 1991 The Regents of the University of California.
* This module is believed to contain source code proprietary to AT&T.
* Use and redistribution is subject to the Berkeley Software License
* Agreement and your Software Agreement with AT&T (Western Electric).
static char sccsid
[] = "@(#)access.c 5.4 (Berkeley) 4/4/91";
* Adb: access data in file/process address space.
* Read or write from or to the given address, accessing or altering
* only the given byte(s). Return the number of bytes transferred.
* Remote (debuggee) addresses are specified as a <space,address> pair.
* Neither the remote nor the local address need be aligned.
* If there is a current process, ask the system to do this (via ptrace
* [ick]). If debugging the kernel, use vtophys() to map virtual to
* physical locations (in a system-dependent manner). Otherwise we
* can just read or write the files being debugged directly.
adbio(rw
, space
, rmtaddr
, localaddr
, cnt
)
static char *derr
= "data address not found";
static char *terr
= "text address not found";
#define rwerr() errflag = space & SP_DATA ? derr : terr
#define within(which) (rmtaddr >= which.b && rmtaddr < which.e)
/* The no-space is all zero. */
ret
= io_ptrace(rw
, space
, rmtaddr
, localaddr
, cnt
);
if (rw
== RWMODE_WRITE
&& !wtflag
)
error("not in write mode");
mp
= space
& SP_DATA
? &datmap
: &txtmap
;
if ((space
& SP_STAR
) == 0 && within(mp
->m1
))
rmtaddr
+= mm
->f
- mm
->b
;
if (kernel
&& space
== SP_DATA
) {
rmtaddr
= vtophys(rmtaddr
, &err
);
if (lseek(mp
->ufd
, (off_t
)rmtaddr
, 0) == -1) {
ret
= read(mp
->ufd
, localaddr
, cnt
);
/* gratuitously supply extra zeroes at end of file */
if (ret
> 0 && ret
< cnt
) {
bzero(localaddr
+ ret
, cnt
- ret
);
ret
= write(mp
->ufd
, localaddr
, cnt
);
* Read a single object of length `len' from the core file at the
* given offset. Return the length read. (This routine allows vtophys
* and kernel crash startup code to read ptes, etc.)
if (lseek(corefile
.fd
, off
, L_SET
) == -1)
return (read(corefile
.fd
, addr
, len
));
* THE FOLLOWING IS GROSS. WE SHOULD REPLACE PTRACE WITH SPECIAL
* Read or write using ptrace. io_ptrace arranges that the
* addresses passed to ptrace are an even multiple of sizeof(int),
* and is able to read or write single bytes.
* Since ptrace is so horribly slow, and some commands do repeated
* reading of units smaller than an `int', io_ptrace calls cptrace
* (cached ptrace) to allow some cacheing. cptrace also converts a
* read/write op and a space into a ptrace op, and returns 0 on success
* and hence takes a pointer to the value cell rather than the value.
short rop
, wop
; /* ptrace ops for read and write */
int valid
; /* true iff cache entry valid */
int *addr
; /* address of cached value */
int val
; /* and the value */
static struct cache icache
= { PT_READ_I
, PT_WRITE_I
};
static struct cache dcache
= { PT_READ_D
, PT_WRITE_D
};
* Invalidate one or both caches.
* This is the only function that accepts two spaces simultaneously.
int cachehit
, cachemiss
; /* statistics */
cptrace(rw
, space
, p
, addr
, val
)
int space
, p
, *addr
, *val
;
register struct cache
*c
= space
& SP_DATA
? &dcache
: &icache
;
if (c
->valid
&& c
->addr
== addr
) {
if ((v
= ptrace(c
->rop
, p
, addr
, 0)) == -1 && errno
)
c
->valid
= 0; /* paranoia */
if (ptrace(c
->wop
, p
, addr
, v
= *val
) == -1 && errno
)
io_ptrace(rw
, space
, rmtaddr
, localaddr
, cnt
)
register caddr_t localaddr
;
register int nbytes
, ret
= 0, off
;
* Start by aligning rmtaddr; set nbytes to the number of bytes of
* useful data we shall obtain.
off
= rmtaddr
% sizeof(int); /* addr_t is unsigned */
nbytes
= sizeof(int) - off
;
if (cptrace(rw
, space
, pid
, (int *)addr
, &tmp
))
bcopy((caddr_t
)&tmp
+ off
, localaddr
, nbytes
);
if (nbytes
< sizeof(int) &&
cptrace(RWMODE_READ
, space
, pid
, (int *)addr
, &tmp
))
bcopy(localaddr
, (caddr_t
)&tmp
+ off
, nbytes
);
if (cptrace(rw
, space
, pid
, (int *)addr
, &tmp
))
* For the rest of the loop, the offset is 0 and we can
* use all the bytes obtained.