aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/map.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/map.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/map.c')
-rw-r--r--src/libmach/map.c306
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;
+}