libmach
This commit is contained in:
parent
0e3cc9f456
commit
a84cbb2a17
53 changed files with 12038 additions and 0 deletions
306
src/libmach/map.c
Normal file
306
src/libmach/map.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue