]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/access.c
python: arm64 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 && map->seg[0].read == nil) {
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 && map->seg[0].read == nil) {
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 && map->seg[0].read == nil) {
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 && map->seg[0].read == nil) {
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->read != nil)
176                 return s->read(s->fd, buf, n, off);
177
178         if(s->cache){
179                 base = off&~(sizeof cache.a-1);
180                 if(cache.s != s || cache.off != base){
181                         cache.off = ~0;
182                         if(seek(s->fd, base, 0) >= 0
183                         && readn(s->fd, cache.a, sizeof cache.a) == sizeof cache.a){
184                                 cache.s = s;
185                                 cache.off = base;
186                         }
187                 }
188                 if(cache.s == s && cache.off == base){
189                         off &= sizeof cache.a-1;
190                         if(off+n > sizeof cache.a)
191                                 n = sizeof cache.a - off;
192                         memmove(buf, cache.a+off, n);
193                         return n;
194                 }
195         }
196
197         return pread(s->fd, buf, n, off);
198 }
199
200 static int
201 mget(Map *map, uvlong addr, void *buf, int size)
202 {
203         uvlong off;
204         int i, j, k;
205         struct segment *s;
206
207         s = reloc(map, addr, (vlong*)&off);
208         if (!s)
209                 return -1;
210         if (s->fd < 0 && s->read == nil) {
211                 werrstr("unreadable map");
212                 return -1;
213         }
214         for (i = j = 0; i < 2; i++) {   /* in case read crosses page */
215                 k = spread(s, (void*)((uchar *)buf+j), size-j, off+j);
216                 if (k < 0) {
217                         werrstr("can't read address %llux: %r", addr);
218                         return -1;
219                 }
220                 j += k;
221                 if (j == size)
222                         return j;
223         }
224         werrstr("partial read at address %llux (size %d j %d)", addr, size, j);
225         return -1;
226 }
227
228 static int
229 mput(Map *map, uvlong addr, void *buf, int size)
230 {
231         vlong off;
232         int i, j, k;
233         struct segment *s;
234
235         s = reloc(map, addr, &off);
236         if (!s)
237                 return -1;
238         if (s->fd < 0) {
239                 werrstr("unwritable map");
240                 return -1;
241         }
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*
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                         addr += map->seg[i].f - map->seg[i].b;
270
271                         /*
272                          * avoid negative file offsets for kernel
273                          * addresses by clearing the sign bit.
274                          * devproc sign extends back to 64 bit.
275                          */
276                         addr <<= 1;
277                         addr >>= 1;
278
279                         *offp = addr;
280                         return &map->seg[i];
281                 }
282         }
283         werrstr("can't translate address %llux", addr);
284         return 0;
285 }