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