306 lines · 4.8 KB · C
RawDownload
/* * 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);} voidfreemap(Map *map){	if(map == nil)		return;	free(map->seg);	free(map);} intaddseg(Map *map, Seg seg){	Seg *ss; 	if(map == nil){		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 == 0){		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++;} intfindseg(Map *map, char *name, char *file){	int i; 	if(map == nil)		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;} intaddrtoseg(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;} intaddrtosegafter(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;} voidremoveseg(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--;} intget1(Map *map, ulong addr, uchar *a, uint n){	return mrw(map, addr, a, n, 1);} intget2(Map *map, ulong addr, u16int *u){	u16int v; 	if(mrw(map, addr, &v, 2, 1) < 0)		return -1;	*u = mach->swap2(v);	return 2;} intget4(Map *map, ulong addr, u32int *u){	u32int v; 	if(mrw(map, addr, &v, 4, 1) < 0)		return -1;	*u = mach->swap4(v);	return 4;} intget8(Map *map, ulong addr, u64int *u){	u64int v; 	if(mrw(map, addr, &v, 8, 1) < 0)		return -1;	*u = mach->swap8(v);	return 8;} intput1(Map *map, ulong addr, uchar *a, uint n){	return mrw(map, addr, a, n, 0);} intput2(Map *map, ulong addr, u16int u){	u = mach->swap2(u);	return mrw(map, addr, &u, 2, 0);} intput4(Map *map, ulong addr, u32int u){	u = mach->swap4(u);	return mrw(map, addr, &u, 4, 0);} intput8(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 intmrw(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 intfdrw(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 intzerorw(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 intdatarw(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;}