| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include <mach.h> |
| |
| int |
| locfmt(Fmt *fmt) |
| { |
| Loc l; |
| |
| l = va_arg(fmt->args, Loc); |
| switch(l.type){ |
| default: |
| return fmtprint(fmt, "<loc%d>", l.type); |
| case LCONST: |
| return fmtprint(fmt, "0x%lux", l.addr); |
| case LADDR: |
| return fmtprint(fmt, "*0x%lux", l.addr); |
| case LOFFSET: |
| return fmtprint(fmt, "%ld(%s)", l.offset, l.reg); |
| case LREG: |
| return fmtprint(fmt, "%s", l.reg); |
| } |
| } |
| |
| int |
| loccmp(Loc *a, Loc *b) |
| { |
| int i; |
| |
| if(a->type < b->type) |
| return -1; |
| if(a->type > b->type) |
| return 1; |
| switch(a->type){ |
| default: |
| return 0; |
| case LADDR: |
| if(a->addr < b->addr) |
| return -1; |
| if(a->addr > b->addr) |
| return 1; |
| return 0; |
| case LOFFSET: |
| i = strcmp(a->reg, b->reg); |
| if(i != 0) |
| return i; |
| if(a->offset < b->offset) |
| return -1; |
| if(a->offset > b->offset) |
| return 1; |
| return 0; |
| case LREG: |
| return strcmp(a->reg, b->reg); |
| } |
| } |
| |
| int |
| lget1(Map *map, Regs *regs, Loc loc, uchar *a, uint n) |
| { |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return get1(map, loc.addr, a, n); |
| /* could do more here - i'm lazy */ |
| werrstr("bad location for lget1"); |
| return -1; |
| } |
| |
| int |
| lget2(Map *map, Regs *regs, Loc loc, u16int *u) |
| { |
| u64int ul; |
| |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return get2(map, loc.addr, u); |
| if(loc.type == LCONST){ |
| *u = loc.addr; |
| return 0; |
| } |
| if(loc.type == LREG){ |
| if(rget(regs, loc.reg, &ul) < 0) |
| return -1; |
| *u = ul; |
| return 0; |
| } |
| werrstr("bad location for lget2"); |
| return -1; |
| } |
| |
| int |
| lget4(Map *map, Regs *regs, Loc loc, u32int *u) |
| { |
| u64int ul; |
| |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return get4(map, loc.addr, u); |
| if(loc.type == LCONST){ |
| *u = loc.addr; |
| return 0; |
| } |
| if(loc.type == LREG){ |
| if(rget(regs, loc.reg, &ul) < 0) |
| return -1; |
| *u = ul; |
| return 0; |
| } |
| werrstr("bad location for lget4"); |
| return -1; |
| } |
| |
| int |
| lgeta(Map *map, Regs *regs, Loc loc, u64int *u) |
| { |
| u32int v; |
| |
| if(machcpu == &machamd64) |
| return lget8(map, regs, loc, u); |
| if(lget4(map, regs, loc, &v) < 0) |
| return -1; |
| *u = v; |
| return 4; |
| } |
| |
| int |
| lget8(Map *map, Regs *regs, Loc loc, u64int *u) |
| { |
| u64int ul; |
| |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return get8(map, loc.addr, u); |
| if(loc.type == LCONST){ |
| *u = loc.addr; |
| return 0; |
| } |
| if(loc.type == LREG){ |
| if(rget(regs, loc.reg, &ul) < 0) |
| return -1; |
| *u = ul; |
| return 0; |
| } |
| werrstr("bad location for lget8"); |
| return -1; |
| } |
| |
| int |
| lput1(Map *map, Regs *regs, Loc loc, uchar *a, uint n) |
| { |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return put1(map, loc.addr, a, n); |
| /* could do more here - i'm lazy */ |
| werrstr("bad location for lput1"); |
| return -1; |
| } |
| |
| int |
| lput2(Map *map, Regs *regs, Loc loc, u16int u) |
| { |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return put2(map, loc.addr, u); |
| if(loc.type == LREG) |
| return rput(regs, loc.reg, u); |
| werrstr("bad location for lput2"); |
| return -1; |
| } |
| |
| int |
| lput4(Map *map, Regs *regs, Loc loc, u32int u) |
| { |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return put4(map, loc.addr, u); |
| if(loc.type == LREG) |
| return rput(regs, loc.reg, u); |
| werrstr("bad location for lput4"); |
| return -1; |
| } |
| |
| int |
| lput8(Map *map, Regs *regs, Loc loc, u64int u) |
| { |
| if(locsimplify(map, regs, loc, &loc) < 0) |
| return -1; |
| if(loc.type == LADDR) |
| return put8(map, loc.addr, u); |
| if(loc.type == LREG) |
| return rput(regs, loc.reg, u); |
| werrstr("bad location for lput8"); |
| return -1; |
| } |
| |
| static Loc zl; |
| |
| Loc |
| locaddr(u64int addr) |
| { |
| Loc l; |
| |
| l = zl; |
| l.type = LADDR; |
| l.addr = addr; |
| return l; |
| } |
| |
| Loc |
| locindir(char *reg, long offset) |
| { |
| Loc l; |
| |
| l = zl; |
| l.type = LOFFSET; |
| l.reg = reg; |
| l.offset = offset; |
| l.addr = 0; /* SHUT UP GCC 4.0 */ |
| return l; |
| } |
| |
| Loc |
| locconst(u64int con) |
| { |
| Loc l; |
| |
| l = zl; |
| l.type = LCONST; |
| l.addr = con; |
| return l; |
| } |
| |
| Loc |
| locnone(void) |
| { |
| Loc l; |
| |
| l = zl; |
| l.type = LNONE; |
| return l; |
| } |
| |
| Loc |
| locreg(char *reg) |
| { |
| Loc l; |
| |
| l = zl; |
| l.type = LREG; |
| l.reg = reg; |
| return l; |
| } |
| |
| int |
| locsimplify(Map *map, Regs *regs, Loc loc, Loc *newloc) |
| { |
| u64int u; |
| |
| if(loc.type == LOFFSET){ |
| if(rget(regs, loc.reg, &u) < 0) |
| return -1; |
| *newloc = locaddr(u + loc.offset); |
| }else |
| *newloc = loc; |
| return 0; |
| } |
| |