map.c (5086B)
1 /* 2 * File map routines 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <bio.h> 7 #include <mach.h> 8 9 static int fdrw(Map*, Seg*, u64int, void*, uint, int); 10 static int zerorw(Map*, Seg*, u64int, void*, uint, int); 11 static int mrw(Map*, u64int, void*, uint, int); 12 static int datarw(Map*, Seg*, u64int, void*, uint, int); 13 14 Map* 15 allocmap(void) 16 { 17 return mallocz(sizeof(Map), 1); 18 } 19 20 void 21 freemap(Map *map) 22 { 23 if(map == nil) 24 return; 25 free(map->seg); 26 free(map); 27 } 28 29 int 30 addseg(Map *map, Seg seg) 31 { 32 Seg *ss; 33 34 if(map == nil){ 35 werrstr("invalid map"); 36 return -1; 37 } 38 39 ss = realloc(map->seg, (map->nseg+1)*sizeof(ss[0])); 40 if(ss == nil) 41 return -1; 42 map->seg = ss; 43 if(seg.rw == 0){ 44 if(seg.name && strcmp(seg.name, "zero") == 0) 45 seg.rw = zerorw; 46 else if(seg.p) 47 seg.rw = datarw; 48 else 49 seg.rw = fdrw; 50 } 51 map->seg[map->nseg] = seg; 52 return map->nseg++; 53 } 54 55 int 56 findseg(Map *map, char *name, char *file) 57 { 58 int i; 59 60 if(map == nil) 61 return -1; 62 for(i=0; i<map->nseg; i++){ 63 if(name && (!map->seg[i].name || strcmp(map->seg[i].name, name) != 0)) 64 continue; 65 if(file && (!map->seg[i].file || strcmp(map->seg[i].file, file) != 0)) 66 continue; 67 return i; 68 } 69 werrstr("segment %s in %s not found", name, file); 70 return -1; 71 } 72 73 int 74 addrtoseg(Map *map, u64int addr, Seg *sp) 75 { 76 int i; 77 Seg *s; 78 79 if(map == nil){ 80 werrstr("no map"); 81 return -1; 82 } 83 for(i=map->nseg-1; i>=0; i--){ 84 s = &map->seg[i]; 85 if(s->base <= addr && addr-s->base < s->size){ 86 if(sp) 87 *sp = *s; 88 return i; 89 } 90 } 91 werrstr("address 0x%lux is not mapped", addr); 92 return -1; 93 } 94 95 int 96 addrtosegafter(Map *map, u64int addr, Seg *sp) 97 { 98 int i; 99 Seg *s, *best; 100 ulong bdist; 101 102 if(map == nil){ 103 werrstr("no map"); 104 return -1; 105 } 106 107 /* 108 * If segments were sorted this would be easier, 109 * but since segments may overlap, sorting also 110 * requires splitting and rejoining, and that's just 111 * too complicated. 112 */ 113 best = nil; 114 bdist = 0; 115 for(i=map->nseg-1; i>=0; i--){ 116 s = &map->seg[i]; 117 if(s->base > addr){ 118 if(best==nil || s->base-addr < bdist){ 119 bdist = s->base - addr; 120 best = s; 121 } 122 } 123 } 124 if(best){ 125 if(sp) 126 *sp = *best; 127 return best-map->seg; 128 } 129 werrstr("nothing mapped after address 0x%lux", addr); 130 return -1; 131 } 132 133 void 134 removeseg(Map *map, int i) 135 { 136 if(map == nil) 137 return; 138 if(i < 0 || i >= map->nseg) 139 return; 140 memmove(&map->seg[i], &map->seg[i+1], (map->nseg-(i+1))*sizeof(Seg)); 141 map->nseg--; 142 } 143 144 int 145 get1(Map *map, u64int addr, uchar *a, uint n) 146 { 147 return mrw(map, addr, a, n, 1); 148 } 149 150 int 151 get2(Map *map, u64int addr, u16int *u) 152 { 153 u16int v; 154 155 if(mrw(map, addr, &v, 2, 1) < 0) 156 return -1; 157 *u = mach->swap2(v); 158 return 2; 159 } 160 161 int 162 get4(Map *map, u64int addr, u32int *u) 163 { 164 u32int v; 165 166 if(mrw(map, addr, &v, 4, 1) < 0) 167 return -1; 168 *u = mach->swap4(v); 169 return 4; 170 } 171 172 int 173 get8(Map *map, u64int addr, u64int *u) 174 { 175 u64int v; 176 177 if(mrw(map, addr, &v, 8, 1) < 0) 178 return -1; 179 *u = mach->swap8(v); 180 return 8; 181 } 182 183 int 184 geta(Map *map, u64int addr, u64int *u) 185 { 186 u32int v; 187 188 if(machcpu == &machamd64) 189 return get8(map, addr, u); 190 if(get4(map, addr, &v) < 0) 191 return -1; 192 *u = v; 193 return 4; 194 } 195 196 int 197 put1(Map *map, u64int addr, uchar *a, uint n) 198 { 199 return mrw(map, addr, a, n, 0); 200 } 201 202 int 203 put2(Map *map, u64int addr, u16int u) 204 { 205 u = mach->swap2(u); 206 return mrw(map, addr, &u, 2, 0); 207 } 208 209 int 210 put4(Map *map, u64int addr, u32int u) 211 { 212 u = mach->swap4(u); 213 return mrw(map, addr, &u, 4, 0); 214 } 215 216 int 217 put8(Map *map, u64int addr, u64int u) 218 { 219 u = mach->swap8(u); 220 return mrw(map, addr, &u, 8, 0); 221 } 222 223 static Seg* 224 reloc(Map *map, u64int addr, uint n, u64int *off, uint *nn) 225 { 226 int i; 227 ulong o; 228 229 if(map == nil){ 230 werrstr("invalid map"); 231 return nil; 232 } 233 234 for(i=map->nseg-1; i>=0; i--){ 235 if(map->seg[i].base <= addr){ 236 o = addr - map->seg[i].base; 237 if(o >= map->seg[i].size) 238 continue; 239 if(o+n > map->seg[i].size) 240 *nn = map->seg[i].size - o; 241 else 242 *nn = n; 243 *off = o; 244 return &map->seg[i]; 245 } 246 } 247 werrstr("address 0x%lux not mapped", addr); 248 return nil; 249 } 250 251 static int 252 mrw(Map *map, u64int addr, void *a, uint n, int r) 253 { 254 uint nn; 255 uint tot; 256 Seg *s; 257 u64int off; 258 259 for(tot=0; tot<n; tot+=nn){ 260 s = reloc(map, addr+tot, n-tot, &off, &nn); 261 if(s == nil) 262 return -1; 263 if(s->rw(map, s, off, a, nn, r) < 0) 264 return -1; 265 } 266 return 0; 267 } 268 269 static int 270 fdrw(Map *map, Seg *seg, u64int addr, void *a, uint n, int r) 271 { 272 int nn; 273 uint tot; 274 ulong off; 275 276 USED(map); 277 off = seg->offset + addr; 278 for(tot=0; tot<n; tot+=nn){ 279 if(r) 280 nn = pread(seg->fd, a, n-tot, off+tot); 281 else 282 nn = pwrite(seg->fd, a, n-tot, off+tot); 283 if(nn < 0) 284 return -1; 285 if(nn == 0){ 286 werrstr("partial %s at address 0x%lux in %s", 287 r ? "read" : "write", off+tot, seg->file); 288 return -1; 289 } 290 } 291 return 0; 292 } 293 294 static int 295 zerorw(Map *map, Seg *seg, u64int addr, void *a, uint n, int r) 296 { 297 USED(map); 298 USED(seg); 299 USED(addr); 300 301 if(r==0){ 302 werrstr("cannot write zero segment"); 303 return -1; 304 } 305 memset(a, 0, n); 306 return 0; 307 } 308 309 static int 310 datarw(Map *map, Seg *seg, u64int addr, void *a, uint n, int r) 311 { 312 USED(map); 313 314 if(r) 315 memmove(a, seg->p+addr, n); 316 else 317 memmove(seg->p+addr, a, n); 318 return 0; 319 }