xref: /plan9/sys/src/libmach/access.c (revision f6b7ac0f8cd168a3afda234913095149c2aef9da)
1219b2ee8SDavid du Colombier /*
2219b2ee8SDavid du Colombier  * functions to read and write an executable or file image
3219b2ee8SDavid du Colombier  */
4219b2ee8SDavid du Colombier 
5219b2ee8SDavid du Colombier #include <u.h>
6219b2ee8SDavid du Colombier #include <libc.h>
7219b2ee8SDavid du Colombier #include <bio.h>
8219b2ee8SDavid du Colombier #include <mach.h>
9219b2ee8SDavid du Colombier 
104de34a7eSDavid du Colombier static	int	mget(Map*, uvlong, void*, int);
114de34a7eSDavid du Colombier static	int	mput(Map*, uvlong, void*, int);
124de34a7eSDavid du Colombier static	struct	segment*	reloc(Map*, uvlong, vlong*);
13219b2ee8SDavid du Colombier 
14219b2ee8SDavid du Colombier /*
15219b2ee8SDavid du Colombier  * routines to get/put various types
16219b2ee8SDavid du Colombier  */
174de34a7eSDavid du Colombier int
geta(Map * map,uvlong addr,uvlong * x)184de34a7eSDavid du Colombier geta(Map *map, uvlong addr, uvlong *x)
194de34a7eSDavid du Colombier {
204de34a7eSDavid du Colombier 	ulong l;
214de34a7eSDavid du Colombier 	uvlong vl;
224de34a7eSDavid du Colombier 
234de34a7eSDavid du Colombier 	if (mach->szaddr == 8){
244de34a7eSDavid du Colombier 		if (get8(map, addr, &vl) < 0)
254de34a7eSDavid du Colombier 			return -1;
264de34a7eSDavid du Colombier 		*x = vl;
274de34a7eSDavid du Colombier 		return 1;
284de34a7eSDavid du Colombier 	}
294de34a7eSDavid du Colombier 
304de34a7eSDavid du Colombier 	if (get4(map, addr, &l) < 0)
314de34a7eSDavid du Colombier 		return -1;
324de34a7eSDavid du Colombier 	*x = l;
334de34a7eSDavid du Colombier 
344de34a7eSDavid du Colombier 	return 1;
354de34a7eSDavid du Colombier }
36219b2ee8SDavid du Colombier 
37219b2ee8SDavid du Colombier int
get8(Map * map,uvlong addr,uvlong * x)384de34a7eSDavid du Colombier get8(Map *map, uvlong addr, uvlong *x)
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	if (!map) {
417dd7cddfSDavid du Colombier 		werrstr("get8: invalid map");
427dd7cddfSDavid du Colombier 		return -1;
437dd7cddfSDavid du Colombier 	}
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
464de34a7eSDavid du Colombier 		*x = addr;
477dd7cddfSDavid du Colombier 		return 1;
487dd7cddfSDavid du Colombier 	}
494de34a7eSDavid du Colombier 	if (mget(map, addr, x, 8) < 0)
507dd7cddfSDavid du Colombier 		return -1;
517dd7cddfSDavid du Colombier 	*x = machdata->swav(*x);
524de34a7eSDavid du Colombier 	return 1;
537dd7cddfSDavid du Colombier }
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier int
get4(Map * map,uvlong addr,ulong * x)564de34a7eSDavid du Colombier get4(Map *map, uvlong addr, ulong *x)
57219b2ee8SDavid du Colombier {
58219b2ee8SDavid du Colombier 	if (!map) {
59219b2ee8SDavid du Colombier 		werrstr("get4: invalid map");
60219b2ee8SDavid du Colombier 		return -1;
61219b2ee8SDavid du Colombier 	}
62219b2ee8SDavid du Colombier 
637dd7cddfSDavid du Colombier 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
64219b2ee8SDavid du Colombier 		*x = addr;
65219b2ee8SDavid du Colombier 		return 1;
66219b2ee8SDavid du Colombier 	}
674de34a7eSDavid du Colombier 	if (mget(map, addr, x, 4) < 0)
68219b2ee8SDavid du Colombier 		return -1;
69219b2ee8SDavid du Colombier 	*x = machdata->swal(*x);
704de34a7eSDavid du Colombier 	return 1;
71219b2ee8SDavid du Colombier }
72219b2ee8SDavid du Colombier 
73219b2ee8SDavid du Colombier int
get2(Map * map,uvlong addr,ushort * x)744de34a7eSDavid du Colombier get2(Map *map, uvlong addr, ushort *x)
75219b2ee8SDavid du Colombier {
76219b2ee8SDavid du Colombier 	if (!map) {
77219b2ee8SDavid du Colombier 		werrstr("get2: invalid map");
78219b2ee8SDavid du Colombier 		return -1;
79219b2ee8SDavid du Colombier 	}
80219b2ee8SDavid du Colombier 
817dd7cddfSDavid du Colombier 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
82219b2ee8SDavid du Colombier 		*x = addr;
83219b2ee8SDavid du Colombier 		return 1;
84219b2ee8SDavid du Colombier 	}
854de34a7eSDavid du Colombier 	if (mget(map, addr, x, 2) < 0)
86219b2ee8SDavid du Colombier 		return -1;
87219b2ee8SDavid du Colombier 	*x = machdata->swab(*x);
884de34a7eSDavid du Colombier 	return 1;
89219b2ee8SDavid du Colombier }
90219b2ee8SDavid du Colombier 
91219b2ee8SDavid du Colombier int
get1(Map * map,uvlong addr,uchar * x,int size)924de34a7eSDavid du Colombier get1(Map *map, uvlong addr, uchar *x, int size)
93219b2ee8SDavid du Colombier {
94219b2ee8SDavid du Colombier 	uchar *cp;
95219b2ee8SDavid du Colombier 
96219b2ee8SDavid du Colombier 	if (!map) {
97219b2ee8SDavid du Colombier 		werrstr("get1: invalid map");
98219b2ee8SDavid du Colombier 		return -1;
99219b2ee8SDavid du Colombier 	}
100219b2ee8SDavid du Colombier 
1017dd7cddfSDavid du Colombier 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
102219b2ee8SDavid du Colombier 		cp = (uchar*)&addr;
103219b2ee8SDavid du Colombier 		while (cp < (uchar*)(&addr+1) && size-- > 0)
104219b2ee8SDavid du Colombier 			*x++ = *cp++;
105219b2ee8SDavid du Colombier 		while (size-- > 0)
106219b2ee8SDavid du Colombier 			*x++ = 0;
107219b2ee8SDavid du Colombier 	} else
1084de34a7eSDavid du Colombier 		return mget(map, addr, x, size);
109219b2ee8SDavid du Colombier 	return 1;
110219b2ee8SDavid du Colombier }
111219b2ee8SDavid du Colombier 
112219b2ee8SDavid du Colombier int
puta(Map * map,uvlong addr,uvlong v)1134de34a7eSDavid du Colombier puta(Map *map, uvlong addr, uvlong v)
1144de34a7eSDavid du Colombier {
1154de34a7eSDavid du Colombier 	if (mach->szaddr == 8)
1164de34a7eSDavid du Colombier 		return put8(map, addr, v);
1174de34a7eSDavid du Colombier 
1184de34a7eSDavid du Colombier 	return put4(map, addr, v);
1194de34a7eSDavid du Colombier }
1204de34a7eSDavid du Colombier 
1214de34a7eSDavid du Colombier int
put8(Map * map,uvlong addr,uvlong v)1224de34a7eSDavid du Colombier put8(Map *map, uvlong addr, uvlong v)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier 	if (!map) {
1257dd7cddfSDavid du Colombier 		werrstr("put8: invalid map");
1267dd7cddfSDavid du Colombier 		return -1;
1277dd7cddfSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 	v = machdata->swav(v);
1294de34a7eSDavid du Colombier 	return mput(map, addr, &v, 8);
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier int
put4(Map * map,uvlong addr,ulong v)1334de34a7eSDavid du Colombier put4(Map *map, uvlong addr, ulong v)
134219b2ee8SDavid du Colombier {
1357dd7cddfSDavid du Colombier 	if (!map) {
1367dd7cddfSDavid du Colombier 		werrstr("put4: invalid map");
137219b2ee8SDavid du Colombier 		return -1;
138219b2ee8SDavid du Colombier 	}
139219b2ee8SDavid du Colombier 	v = machdata->swal(v);
1404de34a7eSDavid du Colombier 	return mput(map, addr, &v, 4);
141219b2ee8SDavid du Colombier }
142219b2ee8SDavid du Colombier 
143219b2ee8SDavid du Colombier int
put2(Map * map,uvlong addr,ushort v)1444de34a7eSDavid du Colombier put2(Map *map, uvlong addr, ushort v)
145219b2ee8SDavid du Colombier {
1467dd7cddfSDavid du Colombier 	if (!map) {
1477dd7cddfSDavid du Colombier 		werrstr("put2: invalid map");
148219b2ee8SDavid du Colombier 		return -1;
149219b2ee8SDavid du Colombier 	}
150219b2ee8SDavid du Colombier 	v = machdata->swab(v);
1514de34a7eSDavid du Colombier 	return mput(map, addr, &v, 2);
152219b2ee8SDavid du Colombier }
153219b2ee8SDavid du Colombier 
154219b2ee8SDavid du Colombier int
put1(Map * map,uvlong addr,uchar * v,int size)1554de34a7eSDavid du Colombier put1(Map *map, uvlong addr, uchar *v, int size)
156219b2ee8SDavid du Colombier {
1577dd7cddfSDavid du Colombier 	if (!map) {
1587dd7cddfSDavid du Colombier 		werrstr("put1: invalid map");
159219b2ee8SDavid du Colombier 		return -1;
160219b2ee8SDavid du Colombier 	}
1614de34a7eSDavid du Colombier 	return mput(map, addr, v, size);
162219b2ee8SDavid du Colombier }
163219b2ee8SDavid du Colombier 
164219b2ee8SDavid du Colombier static int
spread(struct segment * s,void * buf,int n,uvlong off)1654de34a7eSDavid du Colombier spread(struct segment *s, void *buf, int n, uvlong off)
166867bfcc6SDavid du Colombier {
1674de34a7eSDavid du Colombier 	uvlong base;
168867bfcc6SDavid du Colombier 
169867bfcc6SDavid du Colombier 	static struct {
170867bfcc6SDavid du Colombier 		struct segment *s;
171867bfcc6SDavid du Colombier 		char a[8192];
1724de34a7eSDavid du Colombier 		uvlong off;
173867bfcc6SDavid du Colombier 	} cache;
174867bfcc6SDavid du Colombier 
175867bfcc6SDavid du Colombier 	if(s->cache){
176867bfcc6SDavid du Colombier 		base = off&~(sizeof cache.a-1);
177867bfcc6SDavid du Colombier 		if(cache.s != s || cache.off != base){
178867bfcc6SDavid du Colombier 			cache.off = ~0;
179867bfcc6SDavid du Colombier 			if(seek(s->fd, base, 0) >= 0
180867bfcc6SDavid du Colombier 			&& readn(s->fd, cache.a, sizeof cache.a) == sizeof cache.a){
181867bfcc6SDavid du Colombier 				cache.s = s;
182867bfcc6SDavid du Colombier 				cache.off = base;
183867bfcc6SDavid du Colombier 			}
184867bfcc6SDavid du Colombier 		}
185867bfcc6SDavid du Colombier 		if(cache.s == s && cache.off == base){
186867bfcc6SDavid du Colombier 			off &= sizeof cache.a-1;
187867bfcc6SDavid du Colombier 			if(off+n > sizeof cache.a)
188867bfcc6SDavid du Colombier 				n = sizeof cache.a - off;
189867bfcc6SDavid du Colombier 			memmove(buf, cache.a+off, n);
190867bfcc6SDavid du Colombier 			return n;
191867bfcc6SDavid du Colombier 		}
192867bfcc6SDavid du Colombier 	}
193867bfcc6SDavid du Colombier 
194867bfcc6SDavid du Colombier 	return pread(s->fd, buf, n, off);
195867bfcc6SDavid du Colombier }
196867bfcc6SDavid du Colombier 
197867bfcc6SDavid du Colombier static int
mget(Map * map,uvlong addr,void * buf,int size)1984de34a7eSDavid du Colombier mget(Map *map, uvlong addr, void *buf, int size)
199219b2ee8SDavid du Colombier {
2004de34a7eSDavid du Colombier 	uvlong off;
201219b2ee8SDavid du Colombier 	int i, j, k;
2027dd7cddfSDavid du Colombier 	struct segment *s;
203219b2ee8SDavid du Colombier 
2044de34a7eSDavid du Colombier 	s = reloc(map, addr, (vlong*)&off);
2057dd7cddfSDavid du Colombier 	if (!s)
206219b2ee8SDavid du Colombier 		return -1;
2077dd7cddfSDavid du Colombier 	if (s->fd < 0) {
2087dd7cddfSDavid du Colombier 		werrstr("unreadable map");
2097dd7cddfSDavid du Colombier 		return -1;
2107dd7cddfSDavid du Colombier 	}
211219b2ee8SDavid du Colombier 	for (i = j = 0; i < 2; i++) {	/* in case read crosses page */
212*f6b7ac0fSDavid du Colombier 		k = spread(s, (void*)((uchar *)buf+j), size-j, off+j);
213219b2ee8SDavid du Colombier 		if (k < 0) {
2144de34a7eSDavid du Colombier 			werrstr("can't read address %llux: %r", addr);
215219b2ee8SDavid du Colombier 			return -1;
216219b2ee8SDavid du Colombier 		}
217219b2ee8SDavid du Colombier 		j += k;
218219b2ee8SDavid du Colombier 		if (j == size)
219219b2ee8SDavid du Colombier 			return j;
220219b2ee8SDavid du Colombier 	}
2214de34a7eSDavid du Colombier 	werrstr("partial read at address %llux (size %d j %d)", addr, size, j);
222219b2ee8SDavid du Colombier 	return -1;
223219b2ee8SDavid du Colombier }
224219b2ee8SDavid du Colombier 
225219b2ee8SDavid du Colombier static int
mput(Map * map,uvlong addr,void * buf,int size)2264de34a7eSDavid du Colombier mput(Map *map, uvlong addr, void *buf, int size)
227219b2ee8SDavid du Colombier {
2284de34a7eSDavid du Colombier 	vlong off;
229219b2ee8SDavid du Colombier 	int i, j, k;
2307dd7cddfSDavid du Colombier 	struct segment *s;
231219b2ee8SDavid du Colombier 
2327dd7cddfSDavid du Colombier 	s = reloc(map, addr, &off);
2337dd7cddfSDavid du Colombier 	if (!s)
234219b2ee8SDavid du Colombier 		return -1;
2357dd7cddfSDavid du Colombier 	if (s->fd < 0) {
2367dd7cddfSDavid du Colombier 		werrstr("unwritable map");
2377dd7cddfSDavid du Colombier 		return -1;
2387dd7cddfSDavid du Colombier 	}
239219b2ee8SDavid du Colombier 
2404de34a7eSDavid du Colombier 	seek(s->fd, off, 0);
241219b2ee8SDavid du Colombier 	for (i = j = 0; i < 2; i++) {	/* in case read crosses page */
2427dd7cddfSDavid du Colombier 		k = write(s->fd, buf, size-j);
243219b2ee8SDavid du Colombier 		if (k < 0) {
2444de34a7eSDavid du Colombier 			werrstr("can't write address %llux: %r", addr);
245219b2ee8SDavid du Colombier 			return -1;
246219b2ee8SDavid du Colombier 		}
247219b2ee8SDavid du Colombier 		j += k;
248219b2ee8SDavid du Colombier 		if (j == size)
249219b2ee8SDavid du Colombier 			return j;
250219b2ee8SDavid du Colombier 	}
2514de34a7eSDavid du Colombier 	werrstr("partial write at address %llux", addr);
252219b2ee8SDavid du Colombier 	return -1;
253219b2ee8SDavid du Colombier }
254219b2ee8SDavid du Colombier 
255219b2ee8SDavid du Colombier /*
256219b2ee8SDavid du Colombier  *	convert address to file offset; returns nonzero if ok
257219b2ee8SDavid du Colombier  */
2587dd7cddfSDavid du Colombier static struct segment*
reloc(Map * map,uvlong addr,vlong * offp)2594de34a7eSDavid du Colombier reloc(Map *map, uvlong addr, vlong *offp)
260219b2ee8SDavid du Colombier {
261219b2ee8SDavid du Colombier 	int i;
262219b2ee8SDavid du Colombier 
263219b2ee8SDavid du Colombier 	for (i = 0; i < map->nsegs; i++) {
264219b2ee8SDavid du Colombier 		if (map->seg[i].inuse)
265219b2ee8SDavid du Colombier 		if (map->seg[i].b <= addr && addr < map->seg[i].e) {
266219b2ee8SDavid du Colombier 			*offp = addr + map->seg[i].f - map->seg[i].b;
2677dd7cddfSDavid du Colombier 			return &map->seg[i];
268219b2ee8SDavid du Colombier 		}
269219b2ee8SDavid du Colombier 	}
2704de34a7eSDavid du Colombier 	werrstr("can't translate address %llux", addr);
2717dd7cddfSDavid du Colombier 	return 0;
272219b2ee8SDavid du Colombier }
273