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 } 273