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*, uvlong, void*, int);
10 static int mput(Map*, uvlong, void*, int);
11 static struct segment* reloc(Map*, uvlong, vlong*);
12
13 /*
14 * routines to get/put various types
15 */
16 int
geta(Map * map,uvlong addr,uvlong * x)17 geta(Map *map, uvlong addr, uvlong *x)
18 {
19 ulong l;
20 uvlong vl;
21
22 if (mach->szaddr == 8){
23 if (get8(map, addr, &vl) < 0)
24 return -1;
25 *x = vl;
26 return 1;
27 }
28
29 if (get4(map, addr, &l) < 0)
30 return -1;
31 *x = l;
32
33 return 1;
34 }
35
36 int
get8(Map * map,uvlong addr,uvlong * x)37 get8(Map *map, uvlong addr, uvlong *x)
38 {
39 if (!map) {
40 werrstr("get8: invalid map");
41 return -1;
42 }
43
44 if (map->nsegs == 1 && map->seg[0].fd < 0) {
45 *x = addr;
46 return 1;
47 }
48 if (mget(map, addr, x, 8) < 0)
49 return -1;
50 *x = machdata->swav(*x);
51 return 1;
52 }
53
54 int
get4(Map * map,uvlong addr,ulong * x)55 get4(Map *map, uvlong addr, ulong *x)
56 {
57 if (!map) {
58 werrstr("get4: invalid map");
59 return -1;
60 }
61
62 if (map->nsegs == 1 && map->seg[0].fd < 0) {
63 *x = addr;
64 return 1;
65 }
66 if (mget(map, addr, x, 4) < 0)
67 return -1;
68 *x = machdata->swal(*x);
69 return 1;
70 }
71
72 int
get2(Map * map,uvlong addr,ushort * x)73 get2(Map *map, uvlong addr, ushort *x)
74 {
75 if (!map) {
76 werrstr("get2: invalid map");
77 return -1;
78 }
79
80 if (map->nsegs == 1 && map->seg[0].fd < 0) {
81 *x = addr;
82 return 1;
83 }
84 if (mget(map, addr, x, 2) < 0)
85 return -1;
86 *x = machdata->swab(*x);
87 return 1;
88 }
89
90 int
get1(Map * map,uvlong addr,uchar * x,int size)91 get1(Map *map, uvlong addr, uchar *x, int size)
92 {
93 uchar *cp;
94
95 if (!map) {
96 werrstr("get1: invalid map");
97 return -1;
98 }
99
100 if (map->nsegs == 1 && map->seg[0].fd < 0) {
101 cp = (uchar*)&addr;
102 while (cp < (uchar*)(&addr+1) && size-- > 0)
103 *x++ = *cp++;
104 while (size-- > 0)
105 *x++ = 0;
106 } else
107 return mget(map, addr, x, size);
108 return 1;
109 }
110
111 int
puta(Map * map,uvlong addr,uvlong v)112 puta(Map *map, uvlong addr, uvlong v)
113 {
114 if (mach->szaddr == 8)
115 return put8(map, addr, v);
116
117 return put4(map, addr, v);
118 }
119
120 int
put8(Map * map,uvlong addr,uvlong v)121 put8(Map *map, uvlong addr, uvlong v)
122 {
123 if (!map) {
124 werrstr("put8: invalid map");
125 return -1;
126 }
127 v = machdata->swav(v);
128 return mput(map, addr, &v, 8);
129 }
130
131 int
put4(Map * map,uvlong addr,ulong v)132 put4(Map *map, uvlong addr, ulong v)
133 {
134 if (!map) {
135 werrstr("put4: invalid map");
136 return -1;
137 }
138 v = machdata->swal(v);
139 return mput(map, addr, &v, 4);
140 }
141
142 int
put2(Map * map,uvlong addr,ushort v)143 put2(Map *map, uvlong addr, ushort v)
144 {
145 if (!map) {
146 werrstr("put2: invalid map");
147 return -1;
148 }
149 v = machdata->swab(v);
150 return mput(map, addr, &v, 2);
151 }
152
153 int
put1(Map * map,uvlong addr,uchar * v,int size)154 put1(Map *map, uvlong addr, uchar *v, int size)
155 {
156 if (!map) {
157 werrstr("put1: invalid map");
158 return -1;
159 }
160 return mput(map, addr, v, size);
161 }
162
163 static int
spread(struct segment * s,void * buf,int n,uvlong off)164 spread(struct segment *s, void *buf, int n, uvlong off)
165 {
166 uvlong base;
167
168 static struct {
169 struct segment *s;
170 char a[8192];
171 uvlong off;
172 } cache;
173
174 if(s->cache){
175 base = off&~(sizeof cache.a-1);
176 if(cache.s != s || cache.off != base){
177 cache.off = ~0;
178 if(seek(s->fd, base, 0) >= 0
179 && readn(s->fd, cache.a, sizeof cache.a) == sizeof cache.a){
180 cache.s = s;
181 cache.off = base;
182 }
183 }
184 if(cache.s == s && cache.off == base){
185 off &= sizeof cache.a-1;
186 if(off+n > sizeof cache.a)
187 n = sizeof cache.a - off;
188 memmove(buf, cache.a+off, n);
189 return n;
190 }
191 }
192
193 return pread(s->fd, buf, n, off);
194 }
195
196 static int
mget(Map * map,uvlong addr,void * buf,int size)197 mget(Map *map, uvlong addr, void *buf, int size)
198 {
199 uvlong off;
200 int i, j, k;
201 struct segment *s;
202
203 s = reloc(map, addr, (vlong*)&off);
204 if (!s)
205 return -1;
206 if (s->fd < 0) {
207 werrstr("unreadable map");
208 return -1;
209 }
210 if (s->mget)
211 return s->mget(s, addr, off, buf, size);
212 for (i = j = 0; i < 2; i++) { /* in case read crosses page */
213 k = spread(s, (void*)((uchar *)buf+j), size-j, off+j);
214 if (k < 0) {
215 werrstr("can't read address %llux: %r", addr);
216 return -1;
217 }
218 j += k;
219 if (j == size)
220 return j;
221 }
222 werrstr("partial read at address %llux (size %d j %d)", addr, size, j);
223 return -1;
224 }
225
226 static int
mput(Map * map,uvlong addr,void * buf,int size)227 mput(Map *map, uvlong addr, void *buf, int size)
228 {
229 vlong off;
230 int i, j, k;
231 struct segment *s;
232
233 s = reloc(map, addr, &off);
234 if (!s)
235 return -1;
236 if (s->fd < 0) {
237 werrstr("unwritable map");
238 return -1;
239 }
240 if (s->mput)
241 return s->mput(s, addr, off, buf, size);
242
243 seek(s->fd, off, 0);
244 for (i = j = 0; i < 2; i++) { /* in case read crosses page */
245 k = write(s->fd, buf, size-j);
246 if (k < 0) {
247 werrstr("can't write address %llux: %r", addr);
248 return -1;
249 }
250 j += k;
251 if (j == size)
252 return j;
253 }
254 werrstr("partial write at address %llux", addr);
255 return -1;
256 }
257
258 /*
259 * convert address to file offset; returns nonzero if ok
260 */
261 static struct segment*
reloc(Map * map,uvlong addr,vlong * offp)262 reloc(Map *map, uvlong addr, vlong *offp)
263 {
264 int i;
265
266 for (i = 0; i < map->nsegs; i++) {
267 if (map->seg[i].inuse)
268 if (map->seg[i].b <= addr && addr < map->seg[i].e) {
269 *offp = addr + map->seg[i].f - map->seg[i].b;
270 return &map->seg[i];
271 }
272 }
273 werrstr("can't translate address %llux", addr);
274 return 0;
275 }
276