xref: /inferno-os/utils/libmach/access.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
1 /*
2  * functions to read and write an executable or file image
3  */
4 
5 #include <lib9.h>
6 #include <bio.h>
7 #include "mach.h"
8 
9 static	int	mget(Map*, ulong, char*, int);
10 static	int	mput(Map*, ulong, char*, int);
11 struct segment*	reloc(Map*, ulong, long*);
12 
13 /*
14  * routines to get/put various types
15  */
16 
17 int
18 get8(Map *map, ulong addr, vlong *x)
19 {
20 	if (!map) {
21 		werrstr("get8: invalid map");
22 		return -1;
23 	}
24 
25 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
26 		*x = (vlong)addr;
27 		return 1;
28 	}
29 	if (mget(map, addr, (char *)x, 8) < 0)
30 		return -1;
31 	*x = machdata->swav(*x);
32 	return (1);
33 }
34 
35 int
36 get4(Map *map, ulong addr, long *x)
37 {
38 	if (!map) {
39 		werrstr("get4: invalid map");
40 		return -1;
41 	}
42 
43 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
44 		*x = addr;
45 		return 1;
46 	}
47 	if (mget(map, addr, (char *)x, 4) < 0)
48 		return -1;
49 	*x = machdata->swal(*x);
50 	return (1);
51 }
52 
53 int
54 get2(Map *map, ulong addr, ushort *x)
55 {
56 	if (!map) {
57 		werrstr("get2: invalid map");
58 		return -1;
59 	}
60 
61 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
62 		*x = addr;
63 		return 1;
64 	}
65 	if (mget(map, addr, (char *)x, 2) < 0)
66 		return -1;
67 	*x = machdata->swab(*x);
68 	return (1);
69 }
70 
71 int
72 get1(Map *map, ulong addr, uchar *x, int size)
73 {
74 	uchar *cp;
75 
76 	if (!map) {
77 		werrstr("get1: invalid map");
78 		return -1;
79 	}
80 
81 	if (map->nsegs == 1 && map->seg[0].fd < 0) {
82 		cp = (uchar*)&addr;
83 		while (cp < (uchar*)(&addr+1) && size-- > 0)
84 			*x++ = *cp++;
85 		while (size-- > 0)
86 			*x++ = 0;
87 	} else
88 		return mget(map, addr, (char*)x, size);
89 	return 1;
90 }
91 
92 int
93 put8(Map *map, ulong addr, vlong v)
94 {
95 	if (!map) {
96 		werrstr("put8: invalid map");
97 		return -1;
98 	}
99 	v = machdata->swav(v);
100 	return mput(map, addr, (char *)&v, 8);
101 }
102 
103 int
104 put4(Map *map, ulong addr, long v)
105 {
106 	if (!map) {
107 		werrstr("put4: invalid map");
108 		return -1;
109 	}
110 	v = machdata->swal(v);
111 	return mput(map, addr, (char *)&v, 4);
112 }
113 
114 int
115 put2(Map *map, ulong addr, ushort v)
116 {
117 	if (!map) {
118 		werrstr("put2: invalid map");
119 		return -1;
120 	}
121 	v = machdata->swab(v);
122 	return mput(map, addr, (char *)&v, 2);
123 }
124 
125 int
126 put1(Map *map, ulong addr, uchar *v, int size)
127 {
128 	if (!map) {
129 		werrstr("put1: invalid map");
130 		return -1;
131 	}
132 	return mput(map, addr, (char *)v, size);
133 }
134 
135 static int
136 mget(Map *map, ulong addr, char *buf, int size)
137 {
138 	long off;
139 	int i, j, k;
140 	struct segment *s;
141 
142 	s = reloc(map, addr, &off);
143 	if (!s)
144 		return -1;
145 	if (s->fd < 0) {
146 		werrstr("unreadable map");
147 		return -1;
148 	}
149 	if (s->mget)
150 		return s->mget(s, addr, off, buf, size);
151 	seek(s->fd, off, 0);
152 	for (i = j = 0; i < 2; i++) {	/* in case read crosses page */
153 		k = read(s->fd, buf, size-j);
154 		if (k < 0) {
155 			werrstr("can't read address %lux: %r", addr);
156 			return -1;
157 		}
158 		j += k;
159 		if (j == size)
160 			return j;
161 	}
162 	werrstr("partial read at address %lux", addr);
163 	return -1;
164 }
165 
166 static int
167 mput(Map *map, ulong addr, char *buf, int size)
168 {
169 	long off;
170 	int i, j, k;
171 	struct segment *s;
172 
173 	s = reloc(map, addr, &off);
174 	if (!s)
175 		return -1;
176 	if (s->fd < 0) {
177 		werrstr("unwritable map");
178 		return -1;
179 	}
180 	if (s->mput)
181 		return s->mput(s, addr, off, buf, size);
182 
183 	seek(s->fd, off, 0);
184 	for (i = j = 0; i < 2; i++) {	/* in case read crosses page */
185 		k = write(s->fd, buf, size-j);
186 		if (k < 0) {
187 			werrstr("can't write address %lux: %r", addr);
188 			return -1;
189 		}
190 		j += k;
191 		if (j == size)
192 			return j;
193 	}
194 	werrstr("partial write at address %lux", addr);
195 	return -1;
196 }
197 
198 /*
199  *	convert address to file offset; returns nonzero if ok
200  */
201 struct segment*
202 reloc(Map *map, ulong addr, long *offp)
203 {
204 	int i;
205 
206 	for (i = 0; i < map->nsegs; i++) {
207 		if (map->seg[i].inuse)
208 		if (map->seg[i].b <= addr && addr < map->seg[i].e) {
209 			*offp = addr + map->seg[i].f - map->seg[i].b;
210 			return &map->seg[i];
211 		}
212 	}
213 	werrstr("can't translate address %lux", addr);
214 	return 0;
215 }
216