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