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
geta(Map * map,uvlong addr,uvlong * x)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
get8(Map * map,uvlong addr,uvlong * x)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
get4(Map * map,uvlong addr,ulong * x)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
get2(Map * map,uvlong addr,ushort * x)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
get1(Map * map,uvlong addr,uchar * x,int size)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
puta(Map * map,uvlong addr,uvlong v)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
put8(Map * map,uvlong addr,uvlong v)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
put4(Map * map,uvlong addr,ulong v)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
put2(Map * map,uvlong addr,ushort v)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
put1(Map * map,uvlong addr,uchar * v,int size)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
spread(struct segment * s,void * buf,int n,uvlong off)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
mget(Map * map,uvlong addr,void * buf,int size)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
mput(Map * map,uvlong addr,void * buf,int size)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*
reloc(Map * map,uvlong addr,vlong * offp)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 *offp = addr + map->seg[i].f - map->seg[i].b;
267 return &map->seg[i];
268 }
269 }
270 werrstr("can't translate address %llux", addr);
271 return 0;
272 }
273