Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
			*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
}