diff options
author | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
commit | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch) | |
tree | 59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/map.c | |
parent | 0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff) | |
download | plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2 plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip |
libmach
Diffstat (limited to 'src/libmach/map.c')
-rw-r--r-- | src/libmach/map.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/libmach/map.c b/src/libmach/map.c new file mode 100644 index 00000000..144b7042 --- /dev/null +++ b/src/libmach/map.c @@ -0,0 +1,306 @@ +/* + * File map routines + */ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +static int fdrw(Map*, Seg*, ulong, void*, uint, int); +static int zerorw(Map*, Seg*, ulong, void*, uint, int); +static int mrw(Map*, ulong, void*, uint, int); +static int datarw(Map*, Seg*, ulong, void*, uint, int); + +Map* +allocmap(void) +{ + return mallocz(sizeof(Map), 1); +} + +void +freemap(Map *map) +{ + if(map == nil) + return; + free(map->seg); + free(map); +} + +int +addseg(Map *map, Seg seg) +{ + Seg *ss; + + if(map == 0){ + werrstr("invalid map"); + return -1; + } + + ss = realloc(map->seg, (map->nseg+1)*sizeof(ss[0])); + if(ss == nil) + return -1; + map->seg = ss; + if(seg.rw == nil){ + if(seg.name && strcmp(seg.name, "zero") == 0) + seg.rw = zerorw; + else if(seg.p) + seg.rw = datarw; + else + seg.rw = fdrw; + } + map->seg[map->nseg] = seg; + return map->nseg++; +} + +int +findseg(Map *map, char *name, char *file) +{ + int i; + + if(map == 0) + return -1; + for(i=0; i<map->nseg; i++){ + if(name && (!map->seg[i].name || strcmp(map->seg[i].name, name) != 0)) + continue; + if(file && (!map->seg[i].file || strcmp(map->seg[i].file, file) != 0)) + continue; + return i; + } + werrstr("segment %s in %s not found", name, file); + return -1; +} + +int +addrtoseg(Map *map, ulong addr, Seg *sp) +{ + int i; + Seg *s; + + if(map == nil){ + werrstr("no map"); + return -1; + } + for(i=map->nseg-1; i>=0; i--){ + s = &map->seg[i]; + if(s->base <= addr && addr-s->base < s->size){ + if(sp) + *sp = *s; + return i; + } + } + werrstr("address 0x%lux is not mapped", addr); + return -1; +} + +int +addrtosegafter(Map *map, ulong addr, Seg *sp) +{ + int i; + Seg *s, *best; + ulong bdist; + + if(map == nil){ + werrstr("no map"); + return -1; + } + + /* + * If segments were sorted this would be easier, + * but since segments may overlap, sorting also + * requires splitting and rejoining, and that's just + * too complicated. + */ + best = nil; + bdist = 0; + for(i=map->nseg-1; i>=0; i--){ + s = &map->seg[i]; + if(s->base > addr){ + if(best==nil || s->base-addr < bdist){ + bdist = s->base - addr; + best = s; + } + } + } + if(best){ + if(sp) + *sp = *best; + return best-map->seg; + } + werrstr("nothing mapped after address 0x%lux", addr); + return -1; +} + +void +removeseg(Map *map, int i) +{ + if(map == nil) + return; + if(i < 0 || i >= map->nseg) + return; + memmove(&map->seg[i], &map->seg[i+1], (map->nseg-(i+1))*sizeof(Seg)); + map->nseg--; +} + +int +get1(Map *map, ulong addr, uchar *a, uint n) +{ + return mrw(map, addr, a, n, 1); +} + +int +get2(Map *map, ulong addr, u16int *u) +{ + u16int v; + + if(mrw(map, addr, &v, 2, 1) < 0) + return -1; + *u = mach->swap2(v); + return 2; +} + +int +get4(Map *map, ulong addr, u32int *u) +{ + u32int v; + + if(mrw(map, addr, &v, 4, 1) < 0) + return -1; + *u = mach->swap4(v); + return 4; +} + +int +get8(Map *map, ulong addr, u64int *u) +{ + u64int v; + + if(mrw(map, addr, &v, 4, 1) < 0) + return -1; + *u = mach->swap8(v); + return 8; +} + +int +put1(Map *map, ulong addr, uchar *a, uint n) +{ + return mrw(map, addr, a, n, 0); +} + +int +put2(Map *map, ulong addr, u16int u) +{ + u = mach->swap2(u); + return mrw(map, addr, &u, 2, 0); +} + +int +put4(Map *map, ulong addr, u32int u) +{ + u = mach->swap4(u); + return mrw(map, addr, &u, 4, 0); +} + +int +put8(Map *map, ulong addr, u64int u) +{ + u = mach->swap8(u); + return mrw(map, addr, &u, 8, 0); +} + +static Seg* +reloc(Map *map, ulong addr, uint n, ulong *off, uint *nn) +{ + int i; + ulong o; + + if(map == nil){ + werrstr("invalid map"); + return nil; + } + + for(i=map->nseg-1; i>=0; i--){ + if(map->seg[i].base <= addr){ + o = addr - map->seg[i].base; + if(o >= map->seg[i].size) + continue; + if(o+n > map->seg[i].size) + *nn = map->seg[i].size - o; + else + *nn = n; + *off = o; + return &map->seg[i]; + } + } + werrstr("address 0x%lux not mapped", addr); + return nil; +} + +static int +mrw(Map *map, ulong addr, void *a, uint n, int r) +{ + uint nn; + uint tot; + Seg *s; + ulong off; + + for(tot=0; tot<n; tot+=nn){ + s = reloc(map, addr+tot, n-tot, &off, &nn); + if(s == nil) + return -1; + if(s->rw(map, s, off, a, nn, r) < 0) + return -1; + } + return 0; +} + +static int +fdrw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r) +{ + int nn; + uint tot; + ulong off; + + USED(map); + off = seg->offset + addr; + for(tot=0; tot<n; tot+=nn){ + if(r) + nn = pread(seg->fd, a, n-tot, off+tot); + else + nn = pwrite(seg->fd, a, n-tot, off+tot); + if(nn < 0) + return -1; + if(nn == 0){ + werrstr("partial %s at address 0x%lux in %s", + r ? "read" : "write", off+tot, seg->file); + return -1; + } + } + return 0; +} + +static int +zerorw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r) +{ + USED(map); + USED(seg); + USED(addr); + + if(r==0){ + werrstr("cannot write zero segment"); + return -1; + } + memset(a, 0, n); + return 0; +} + +static int +datarw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r) +{ + USED(map); + + if(r) + memmove(a, seg->p+addr, n); + else + memmove(seg->p+addr, a, n); + return 0; +} |