174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth * functions to read and write an executable or file image
374a4d8c2SCharles.Forsyth */
474a4d8c2SCharles.Forsyth
574a4d8c2SCharles.Forsyth #include <lib9.h>
674a4d8c2SCharles.Forsyth #include <bio.h>
774a4d8c2SCharles.Forsyth #include "mach.h"
874a4d8c2SCharles.Forsyth
9*d67b7dadSforsyth static int mget(Map*, uvlong, void*, int);
10*d67b7dadSforsyth static int mput(Map*, uvlong, void*, int);
11*d67b7dadSforsyth static struct segment* reloc(Map*, uvlong, vlong*);
1274a4d8c2SCharles.Forsyth
1374a4d8c2SCharles.Forsyth /*
1474a4d8c2SCharles.Forsyth * routines to get/put various types
1574a4d8c2SCharles.Forsyth */
16*d67b7dadSforsyth int
geta(Map * map,uvlong addr,uvlong * x)17*d67b7dadSforsyth geta(Map *map, uvlong addr, uvlong *x)
18*d67b7dadSforsyth {
19*d67b7dadSforsyth ulong l;
20*d67b7dadSforsyth uvlong vl;
21*d67b7dadSforsyth
22*d67b7dadSforsyth if (mach->szaddr == 8){
23*d67b7dadSforsyth if (get8(map, addr, &vl) < 0)
24*d67b7dadSforsyth return -1;
25*d67b7dadSforsyth *x = vl;
26*d67b7dadSforsyth return 1;
27*d67b7dadSforsyth }
28*d67b7dadSforsyth
29*d67b7dadSforsyth if (get4(map, addr, &l) < 0)
30*d67b7dadSforsyth return -1;
31*d67b7dadSforsyth *x = l;
32*d67b7dadSforsyth
33*d67b7dadSforsyth return 1;
34*d67b7dadSforsyth }
3574a4d8c2SCharles.Forsyth
3674a4d8c2SCharles.Forsyth int
get8(Map * map,uvlong addr,uvlong * x)37*d67b7dadSforsyth get8(Map *map, uvlong addr, uvlong *x)
3874a4d8c2SCharles.Forsyth {
3974a4d8c2SCharles.Forsyth if (!map) {
4074a4d8c2SCharles.Forsyth werrstr("get8: invalid map");
4174a4d8c2SCharles.Forsyth return -1;
4274a4d8c2SCharles.Forsyth }
4374a4d8c2SCharles.Forsyth
4474a4d8c2SCharles.Forsyth if (map->nsegs == 1 && map->seg[0].fd < 0) {
45*d67b7dadSforsyth *x = addr;
4674a4d8c2SCharles.Forsyth return 1;
4774a4d8c2SCharles.Forsyth }
48*d67b7dadSforsyth if (mget(map, addr, x, 8) < 0)
4974a4d8c2SCharles.Forsyth return -1;
5074a4d8c2SCharles.Forsyth *x = machdata->swav(*x);
51*d67b7dadSforsyth return 1;
5274a4d8c2SCharles.Forsyth }
5374a4d8c2SCharles.Forsyth
5474a4d8c2SCharles.Forsyth int
get4(Map * map,uvlong addr,ulong * x)55*d67b7dadSforsyth get4(Map *map, uvlong addr, ulong *x)
5674a4d8c2SCharles.Forsyth {
5774a4d8c2SCharles.Forsyth if (!map) {
5874a4d8c2SCharles.Forsyth werrstr("get4: invalid map");
5974a4d8c2SCharles.Forsyth return -1;
6074a4d8c2SCharles.Forsyth }
6174a4d8c2SCharles.Forsyth
6274a4d8c2SCharles.Forsyth if (map->nsegs == 1 && map->seg[0].fd < 0) {
6374a4d8c2SCharles.Forsyth *x = addr;
6474a4d8c2SCharles.Forsyth return 1;
6574a4d8c2SCharles.Forsyth }
66*d67b7dadSforsyth if (mget(map, addr, x, 4) < 0)
6774a4d8c2SCharles.Forsyth return -1;
6874a4d8c2SCharles.Forsyth *x = machdata->swal(*x);
69*d67b7dadSforsyth return 1;
7074a4d8c2SCharles.Forsyth }
7174a4d8c2SCharles.Forsyth
7274a4d8c2SCharles.Forsyth int
get2(Map * map,uvlong addr,ushort * x)73*d67b7dadSforsyth get2(Map *map, uvlong addr, ushort *x)
7474a4d8c2SCharles.Forsyth {
7574a4d8c2SCharles.Forsyth if (!map) {
7674a4d8c2SCharles.Forsyth werrstr("get2: invalid map");
7774a4d8c2SCharles.Forsyth return -1;
7874a4d8c2SCharles.Forsyth }
7974a4d8c2SCharles.Forsyth
8074a4d8c2SCharles.Forsyth if (map->nsegs == 1 && map->seg[0].fd < 0) {
8174a4d8c2SCharles.Forsyth *x = addr;
8274a4d8c2SCharles.Forsyth return 1;
8374a4d8c2SCharles.Forsyth }
84*d67b7dadSforsyth if (mget(map, addr, x, 2) < 0)
8574a4d8c2SCharles.Forsyth return -1;
8674a4d8c2SCharles.Forsyth *x = machdata->swab(*x);
87*d67b7dadSforsyth return 1;
8874a4d8c2SCharles.Forsyth }
8974a4d8c2SCharles.Forsyth
9074a4d8c2SCharles.Forsyth int
get1(Map * map,uvlong addr,uchar * x,int size)91*d67b7dadSforsyth get1(Map *map, uvlong addr, uchar *x, int size)
9274a4d8c2SCharles.Forsyth {
9374a4d8c2SCharles.Forsyth uchar *cp;
9474a4d8c2SCharles.Forsyth
9574a4d8c2SCharles.Forsyth if (!map) {
9674a4d8c2SCharles.Forsyth werrstr("get1: invalid map");
9774a4d8c2SCharles.Forsyth return -1;
9874a4d8c2SCharles.Forsyth }
9974a4d8c2SCharles.Forsyth
10074a4d8c2SCharles.Forsyth if (map->nsegs == 1 && map->seg[0].fd < 0) {
10174a4d8c2SCharles.Forsyth cp = (uchar*)&addr;
10274a4d8c2SCharles.Forsyth while (cp < (uchar*)(&addr+1) && size-- > 0)
10374a4d8c2SCharles.Forsyth *x++ = *cp++;
10474a4d8c2SCharles.Forsyth while (size-- > 0)
10574a4d8c2SCharles.Forsyth *x++ = 0;
10674a4d8c2SCharles.Forsyth } else
107*d67b7dadSforsyth return mget(map, addr, x, size);
10874a4d8c2SCharles.Forsyth return 1;
10974a4d8c2SCharles.Forsyth }
11074a4d8c2SCharles.Forsyth
11174a4d8c2SCharles.Forsyth int
puta(Map * map,uvlong addr,uvlong v)112*d67b7dadSforsyth puta(Map *map, uvlong addr, uvlong v)
113*d67b7dadSforsyth {
114*d67b7dadSforsyth if (mach->szaddr == 8)
115*d67b7dadSforsyth return put8(map, addr, v);
116*d67b7dadSforsyth
117*d67b7dadSforsyth return put4(map, addr, v);
118*d67b7dadSforsyth }
119*d67b7dadSforsyth
120*d67b7dadSforsyth int
put8(Map * map,uvlong addr,uvlong v)121*d67b7dadSforsyth put8(Map *map, uvlong addr, uvlong v)
12274a4d8c2SCharles.Forsyth {
12374a4d8c2SCharles.Forsyth if (!map) {
12474a4d8c2SCharles.Forsyth werrstr("put8: invalid map");
12574a4d8c2SCharles.Forsyth return -1;
12674a4d8c2SCharles.Forsyth }
12774a4d8c2SCharles.Forsyth v = machdata->swav(v);
128*d67b7dadSforsyth return mput(map, addr, &v, 8);
12974a4d8c2SCharles.Forsyth }
13074a4d8c2SCharles.Forsyth
13174a4d8c2SCharles.Forsyth int
put4(Map * map,uvlong addr,ulong v)132*d67b7dadSforsyth put4(Map *map, uvlong addr, ulong v)
13374a4d8c2SCharles.Forsyth {
13474a4d8c2SCharles.Forsyth if (!map) {
13574a4d8c2SCharles.Forsyth werrstr("put4: invalid map");
13674a4d8c2SCharles.Forsyth return -1;
13774a4d8c2SCharles.Forsyth }
13874a4d8c2SCharles.Forsyth v = machdata->swal(v);
139*d67b7dadSforsyth return mput(map, addr, &v, 4);
14074a4d8c2SCharles.Forsyth }
14174a4d8c2SCharles.Forsyth
14274a4d8c2SCharles.Forsyth int
put2(Map * map,uvlong addr,ushort v)143*d67b7dadSforsyth put2(Map *map, uvlong addr, ushort v)
14474a4d8c2SCharles.Forsyth {
14574a4d8c2SCharles.Forsyth if (!map) {
14674a4d8c2SCharles.Forsyth werrstr("put2: invalid map");
14774a4d8c2SCharles.Forsyth return -1;
14874a4d8c2SCharles.Forsyth }
14974a4d8c2SCharles.Forsyth v = machdata->swab(v);
150*d67b7dadSforsyth return mput(map, addr, &v, 2);
15174a4d8c2SCharles.Forsyth }
15274a4d8c2SCharles.Forsyth
15374a4d8c2SCharles.Forsyth int
put1(Map * map,uvlong addr,uchar * v,int size)154*d67b7dadSforsyth put1(Map *map, uvlong addr, uchar *v, int size)
15574a4d8c2SCharles.Forsyth {
15674a4d8c2SCharles.Forsyth if (!map) {
15774a4d8c2SCharles.Forsyth werrstr("put1: invalid map");
15874a4d8c2SCharles.Forsyth return -1;
15974a4d8c2SCharles.Forsyth }
160*d67b7dadSforsyth return mput(map, addr, v, size);
16174a4d8c2SCharles.Forsyth }
16274a4d8c2SCharles.Forsyth
16374a4d8c2SCharles.Forsyth static int
spread(struct segment * s,void * buf,int n,uvlong off)164*d67b7dadSforsyth spread(struct segment *s, void *buf, int n, uvlong off)
16574a4d8c2SCharles.Forsyth {
166*d67b7dadSforsyth uvlong base;
167*d67b7dadSforsyth
168*d67b7dadSforsyth static struct {
169*d67b7dadSforsyth struct segment *s;
170*d67b7dadSforsyth char a[8192];
171*d67b7dadSforsyth uvlong off;
172*d67b7dadSforsyth } cache;
173*d67b7dadSforsyth
174*d67b7dadSforsyth if(s->cache){
175*d67b7dadSforsyth base = off&~(sizeof cache.a-1);
176*d67b7dadSforsyth if(cache.s != s || cache.off != base){
177*d67b7dadSforsyth cache.off = ~0;
178*d67b7dadSforsyth if(seek(s->fd, base, 0) >= 0
179*d67b7dadSforsyth && readn(s->fd, cache.a, sizeof cache.a) == sizeof cache.a){
180*d67b7dadSforsyth cache.s = s;
181*d67b7dadSforsyth cache.off = base;
182*d67b7dadSforsyth }
183*d67b7dadSforsyth }
184*d67b7dadSforsyth if(cache.s == s && cache.off == base){
185*d67b7dadSforsyth off &= sizeof cache.a-1;
186*d67b7dadSforsyth if(off+n > sizeof cache.a)
187*d67b7dadSforsyth n = sizeof cache.a - off;
188*d67b7dadSforsyth memmove(buf, cache.a+off, n);
189*d67b7dadSforsyth return n;
190*d67b7dadSforsyth }
191*d67b7dadSforsyth }
192*d67b7dadSforsyth
193*d67b7dadSforsyth return pread(s->fd, buf, n, off);
194*d67b7dadSforsyth }
195*d67b7dadSforsyth
196*d67b7dadSforsyth static int
mget(Map * map,uvlong addr,void * buf,int size)197*d67b7dadSforsyth mget(Map *map, uvlong addr, void *buf, int size)
198*d67b7dadSforsyth {
199*d67b7dadSforsyth uvlong off;
20074a4d8c2SCharles.Forsyth int i, j, k;
20174a4d8c2SCharles.Forsyth struct segment *s;
20274a4d8c2SCharles.Forsyth
203*d67b7dadSforsyth s = reloc(map, addr, (vlong*)&off);
20474a4d8c2SCharles.Forsyth if (!s)
20574a4d8c2SCharles.Forsyth return -1;
20674a4d8c2SCharles.Forsyth if (s->fd < 0) {
20774a4d8c2SCharles.Forsyth werrstr("unreadable map");
20874a4d8c2SCharles.Forsyth return -1;
20974a4d8c2SCharles.Forsyth }
21074a4d8c2SCharles.Forsyth if (s->mget)
21174a4d8c2SCharles.Forsyth return s->mget(s, addr, off, buf, size);
21274a4d8c2SCharles.Forsyth for (i = j = 0; i < 2; i++) { /* in case read crosses page */
213*d67b7dadSforsyth k = spread(s, (void*)((uchar *)buf+j), size-j, off+j);
21474a4d8c2SCharles.Forsyth if (k < 0) {
215*d67b7dadSforsyth werrstr("can't read address %llux: %r", addr);
21674a4d8c2SCharles.Forsyth return -1;
21774a4d8c2SCharles.Forsyth }
21874a4d8c2SCharles.Forsyth j += k;
21974a4d8c2SCharles.Forsyth if (j == size)
22074a4d8c2SCharles.Forsyth return j;
22174a4d8c2SCharles.Forsyth }
222*d67b7dadSforsyth werrstr("partial read at address %llux (size %d j %d)", addr, size, j);
22374a4d8c2SCharles.Forsyth return -1;
22474a4d8c2SCharles.Forsyth }
22574a4d8c2SCharles.Forsyth
22674a4d8c2SCharles.Forsyth static int
mput(Map * map,uvlong addr,void * buf,int size)227*d67b7dadSforsyth mput(Map *map, uvlong addr, void *buf, int size)
22874a4d8c2SCharles.Forsyth {
229*d67b7dadSforsyth vlong off;
23074a4d8c2SCharles.Forsyth int i, j, k;
23174a4d8c2SCharles.Forsyth struct segment *s;
23274a4d8c2SCharles.Forsyth
23374a4d8c2SCharles.Forsyth s = reloc(map, addr, &off);
23474a4d8c2SCharles.Forsyth if (!s)
23574a4d8c2SCharles.Forsyth return -1;
23674a4d8c2SCharles.Forsyth if (s->fd < 0) {
23774a4d8c2SCharles.Forsyth werrstr("unwritable map");
23874a4d8c2SCharles.Forsyth return -1;
23974a4d8c2SCharles.Forsyth }
24074a4d8c2SCharles.Forsyth if (s->mput)
24174a4d8c2SCharles.Forsyth return s->mput(s, addr, off, buf, size);
24274a4d8c2SCharles.Forsyth
24374a4d8c2SCharles.Forsyth seek(s->fd, off, 0);
24474a4d8c2SCharles.Forsyth for (i = j = 0; i < 2; i++) { /* in case read crosses page */
24574a4d8c2SCharles.Forsyth k = write(s->fd, buf, size-j);
24674a4d8c2SCharles.Forsyth if (k < 0) {
247*d67b7dadSforsyth werrstr("can't write address %llux: %r", addr);
24874a4d8c2SCharles.Forsyth return -1;
24974a4d8c2SCharles.Forsyth }
25074a4d8c2SCharles.Forsyth j += k;
25174a4d8c2SCharles.Forsyth if (j == size)
25274a4d8c2SCharles.Forsyth return j;
25374a4d8c2SCharles.Forsyth }
254*d67b7dadSforsyth werrstr("partial write at address %llux", addr);
25574a4d8c2SCharles.Forsyth return -1;
25674a4d8c2SCharles.Forsyth }
25774a4d8c2SCharles.Forsyth
25874a4d8c2SCharles.Forsyth /*
25974a4d8c2SCharles.Forsyth * convert address to file offset; returns nonzero if ok
26074a4d8c2SCharles.Forsyth */
261*d67b7dadSforsyth static struct segment*
reloc(Map * map,uvlong addr,vlong * offp)262*d67b7dadSforsyth reloc(Map *map, uvlong addr, vlong *offp)
26374a4d8c2SCharles.Forsyth {
26474a4d8c2SCharles.Forsyth int i;
26574a4d8c2SCharles.Forsyth
26674a4d8c2SCharles.Forsyth for (i = 0; i < map->nsegs; i++) {
26774a4d8c2SCharles.Forsyth if (map->seg[i].inuse)
26874a4d8c2SCharles.Forsyth if (map->seg[i].b <= addr && addr < map->seg[i].e) {
26974a4d8c2SCharles.Forsyth *offp = addr + map->seg[i].f - map->seg[i].b;
27074a4d8c2SCharles.Forsyth return &map->seg[i];
27174a4d8c2SCharles.Forsyth }
27274a4d8c2SCharles.Forsyth }
273*d67b7dadSforsyth werrstr("can't translate address %llux", addr);
27474a4d8c2SCharles.Forsyth return 0;
27574a4d8c2SCharles.Forsyth }
276