diff --git a/include/ureg_arm.h b/include/ureg_arm.h new file mode 100644 index 0000000000..c740b03021 --- /dev/null +++ b/include/ureg_arm.h @@ -0,0 +1,49 @@ +// Inferno utils/libmach/ureg5.h +// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg5.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. +// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). +// Portions Copyright © 1997-1999 Vita Nuova Limited. +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). +// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +struct Ureg { + uint r0; + uint r1; + uint r2; + uint r3; + uint r4; + uint r5; + uint r6; + uint r7; + uint r8; + uint r9; + uint r10; + uint r11; + uint r12; + uint r13; + uint r14; + uint link; + uint type; + uint psr; + uint pc; +}; diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 6cd4b2390c..a375b8bf87 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -671,7 +671,10 @@ putsymb(char *s, int t, int32 v, int ver) cput(s[i]); cput(0); } - symsize += 4 + 1 + i + 1; + // TODO(rsc): handle go parameter + lput(0); + + symsize += 4 + 1 + i + 1 + 4; if(debug['n']) { if(t == 'z' || t == 'Z') { diff --git a/src/libmach/5.c b/src/libmach/5.c new file mode 100644 index 0000000000..67bd88db4c --- /dev/null +++ b/src/libmach/5.c @@ -0,0 +1,92 @@ +// Inferno libmach/5.c +// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. +// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). +// Portions Copyright © 1997-1999 Vita Nuova Limited. +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). +// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * arm definition + */ +#include +#include +#include +#include "ureg_arm.h" +#include + +#define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x) + +#define SP REGOFF(r13) +#define PC REGOFF(pc) + +#define REGSIZE sizeof(struct Ureg) + +Reglist armreglist[] = +{ + {"LINK", REGOFF(link), RINT|RRDONLY, 'X'}, + {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'}, + {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'}, + {"PC", PC, RINT, 'X'}, + {"SP", SP, RINT, 'X'}, + {"R15", PC, RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + {"R0", REGOFF(r0), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach marm = +{ + "arm", + MARM, /* machine type */ + armreglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R15", /* name of link register */ + "setR12", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0xC0000000, /* kernel base */ + 0, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/src/libmach/5db.c b/src/libmach/5db.c new file mode 100644 index 0000000000..aea391edfc --- /dev/null +++ b/src/libmach/5db.c @@ -0,0 +1,1095 @@ +// Inferno libmach/5db.c +// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. +// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). +// Portions Copyright © 1997-1999 Vita Nuova Limited. +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). +// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include "ureg_arm.h" +#include + +static int debug = 0; + +#define BITS(a, b) ((1<<(b+1))-(1<> (s)) +#define ASR(v, s) ((long)(v) >> (s)) +#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) + + + +typedef struct Instr Instr; +struct Instr +{ + Map *map; + ulong w; + ulong addr; + uchar op; /* super opcode */ + + uchar cond; /* bits 28-31 */ + uchar store; /* bit 20 */ + + uchar rd; /* bits 12-15 */ + uchar rn; /* bits 16-19 */ + uchar rs; /* bits 0-11 (shifter operand) */ + + long imm; /* rotated imm */ + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ + char* err; /* error message */ +}; + +typedef struct Opcode Opcode; +struct Opcode +{ + char* o; + void (*fmt)(Opcode*, Instr*); + ulong (*foll)(Map*, Rgetter, Instr*, ulong); + char* a; +}; + +static void format(char*, Instr*, char*); +static char FRAMENAME[] = ".frame"; + +/* + * Arm-specific debugger interface + */ + +extern char *armexcep(Map*, Rgetter); +static int armfoll(Map*, uvlong, Rgetter, uvlong*); +static int arminst(Map*, uvlong, char, char*, int); +static int armdas(Map*, uvlong, char*, int); +static int arminstlen(Map*, uvlong); + +/* + * Debugger interface + */ +Machdata armmach = +{ + {0, 0, 0, 0xD}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + armexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precision float printer */ + armfoll, /* following addresses */ + arminst, /* print instruction */ + armdas, /* dissembler */ + arminstlen, /* instruction size */ +}; + +char* +armexcep(Map *map, Rgetter rget) +{ + long c; + + c = (*rget)(map, "TYPE"); + switch (c&0x1f) { + case 0x11: + return "Fiq interrupt"; + case 0x12: + return "Mirq interrupt"; + case 0x13: + return "SVC/SWI Exception"; + case 0x17: + return "Prefetch Abort/Data Abort"; + case 0x18: + return "Data Abort"; + case 0x1b: + return "Undefined instruction/Breakpoint"; + case 0x1f: + return "Sys trap"; + default: + return "Undefined trap"; + } +} + +static +char* cond[16] = +{ + "EQ", "NE", "CS", "CC", + "MI", "PL", "VS", "VC", + "HI", "LS", "GE", "LT", + "GT", "LE", 0, "NV" +}; + +static +char* shtype[4] = +{ + "<<", ">>", "->", "@>" +}; + +static +char *hb[4] = +{ + "???", "HU", "B", "H" +}; + +static +char* addsub[2] = +{ + "-", "+", +}; + +int +armclass(long w) +{ + int op; + + op = (w >> 25) & 0x7; + switch(op) { + case 0: /* data processing r,r,r */ + op = ((w >> 4) & 0xf); + if(op == 0x9) { + op = 48+16; /* mul */ + if(w & (1<<24)) { + op += 2; + if(w & (1<<22)) + op++; /* swap */ + break; + } + if(w & (1<<21)) + op++; /* mla */ + break; + } + if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */ + { + op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + } + op = (w >> 21) & 0xf; + if(w & (1<<4)) + op += 32; + else + if(w & (31<<7)) + op += 16; + break; + case 1: /* data processing i,r,r */ + op = (48) + ((w >> 21) & 0xf); + break; + case 2: /* load/store byte/word i(r) */ + op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 3: /* load/store byte/word (r)(r) */ + op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 4: /* block data transfer (r)(r) */ + op = (48+24+4+4) + ((w >> 20) & 0x1); + break; + case 5: /* branch / branch link */ + op = (48+24+4+4+2) + ((w >> 24) & 0x1); + break; + case 7: /* coprocessor crap */ + op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1); + break; + default: + op = (48+24+4+4+2+2+4); + break; + } + return op; +} + +static int +decode(Map *map, ulong pc, Instr *i) +{ + uint32 w; + + if(get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->w = w; + i->addr = pc; + i->cond = (w >> 28) & 0xF; + i->op = armclass(w); + i->map = map; + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +plocal(Instr *i) +{ + char *reg; + Symbol s; + char *fn; + int class; + int offset; + + if(!findsym(i->addr, CTEXT, &s)) { + if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr); + return 0; + } + fn = s.name; + if (!findlocal(&s, FRAMENAME, &s)) { + if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name); + return 0; + } + if(s.value > i->imm) { + class = CAUTO; + offset = s.value-i->imm; + reg = "(SP)"; + } else { + class = CPARAM; + offset = i->imm-s.value-4; + reg = "(FP)"; + } + if(!getauto(&s, offset, class, &s)) { + if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn, + class == CAUTO ? " auto" : "param", offset); + return 0; + } + bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg); + return 1; +} + +/* + * Print value v as name[+offset] + */ +int +gsymoff(char *buf, int n, long v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0 || delta >= 4096) + return snprint(buf, n, "#%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "#%lux", v); + if (!delta) + return snprint(buf, n, "%s", s.name); + if (s.type != 't' && s.type != 'T') + return snprint(buf, n, "%s+%lux", s.name, v-s.value); + else + return snprint(buf, n, "#%lux", v); +} + +static void +armdps(Opcode *o, Instr *i) +{ + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = (i->w >> 0) & 0xf; + if(i->rn == 15 && i->rs == 0) { + if(i->op == 8) { + format("MOVW", i,"CPSR, R%d"); + return; + } else + if(i->op == 10) { + format("MOVW", i,"SPSR, R%d"); + return; + } + } else + if(i->rn == 9 && i->rd == 15) { + if(i->op == 9) { + format("MOVW", i, "R%s, CPSR"); + return; + } else + if(i->op == 11) { + format("MOVW", i, "R%s, SPSR"); + return; + } + } + format(o->o, i, o->a); +} + +static void +armdpi(Opcode *o, Instr *i) +{ + ulong v; + int c; + + v = (i->w >> 0) & 0xff; + c = (i->w >> 8) & 0xf; + while(c) { + v = (v<<30) | (v>>2); + c--; + } + i->imm = v; + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0x0f; + + /* RET is encoded as ADD #0,R14,R15 */ + if((i->w & 0x0fffffff) == 0x028ef000){ + format("RET%C", i, ""); + return; + } + if((i->w & 0x0ff0ffff) == 0x0280f000){ + format("B%C", i, "0(R%n)"); + return; + } + format(o->o, i, o->a); +} + +static void +armsdti(Opcode *o, Instr *i) +{ + ulong v; + + v = i->w & 0xfff; + if(!(i->w & (1<<23))) + v = -v; + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->imm = v; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + /* RET is encoded as LW.P x,R13,R15 */ + if ((i->w & 0x0ffff000) == 0x049df000) + { + format("RET%C%p", i, "%I"); + return; + } + format(o->o, i, o->a); +} + +/* arm V4 ld/st halfword, signed byte */ +static void +armhwby(Opcode *o, Instr *i) +{ + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf); + if (!(i->w & (1 << 23))) + i->imm = - i->imm; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = (i->w >> 0) & 0xf; + format(o->o, i, o->a); +} + +static void +armsdts(Opcode *o, Instr *i) +{ + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->rs = (i->w >> 0) & 0xf; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + format(o->o, i, o->a); +} + +static void +armbdt(Opcode *o, Instr *i) +{ + i->store = (i->w >> 21) & 0x3; /* S & W bits */ + i->rn = (i->w >> 16) & 0xf; + i->imm = i->w & 0xffff; + if(i->w == 0xe8fd8000) + format("RFE", i, ""); + else + format(o->o, i, o->a); +} + +/* +static void +armund(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armcdt(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} +*/ + +static void +armunk(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armb(Opcode *o, Instr *i) +{ + ulong v; + + v = i->w & 0xffffff; + if(v & 0x800000) + v |= ~0xffffff; + i->imm = (v<<2) + i->addr + 8; + format(o->o, i, o->a); +} + +static void +armco(Opcode *o, Instr *i) /* coprocessor instructions */ +{ + int op, p, cp; + + char buf[1024]; + + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0xf; + cp = (i->w >> 8) & 0xf; + p = (i->w >> 5) & 0x7; + if(i->w&(1<<4)) { + op = (i->w >> 21) & 0x07; + snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } else { + op = (i->w >> 20) & 0x0f; + snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } + format(o->o, i, buf); +} + +static int +armcondpass(Map *map, Rgetter rget, uchar cond) +{ + ulong psr; + uchar n; + uchar z; + uchar c; + uchar v; + + psr = rget(map, "PSR"); + n = (psr >> 31) & 1; + z = (psr >> 30) & 1; + c = (psr >> 29) & 1; + v = (psr >> 28) & 1; + + switch(cond) { + case 0: return z; + case 1: return !z; + case 2: return c; + case 3: return !c; + case 4: return n; + case 5: return !n; + case 6: return v; + case 7: return !v; + case 8: return c && !z; + case 9: return !c || z; + case 10: return n == v; + case 11: return n != v; + case 12: return !z && (n == v); + case 13: return z && (n != v); + case 14: return 1; + case 15: return 0; + } + return 0; +} + +static ulong +armshiftval(Map *map, Rgetter rget, Instr *i) +{ + if(i->w & (1 << 25)) { /* immediate */ + ulong imm = i->w & BITS(0, 7); + ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */ + return ROR(imm, s); + } else { + char buf[8]; + ulong v; + ulong s = (i->w & BITS(7,11)) >> 7; + + sprint(buf, "R%ld", i->w & 0xf); + v = rget(map, buf); + + switch((i->w & BITS(4, 6)) >> 4) { + case 0: /* LSLIMM */ + return v << s; + case 1: /* LSLREG */ + sprint(buf, "R%lud", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) return 0; + return v << s; + case 2: /* LSRIMM */ + return LSR(v, s); + case 3: /* LSRREG */ + sprint(buf, "R%ld", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) return 0; + return LSR(v, s); + case 4: /* ASRIMM */ + if(s == 0) { + if((v & (1U<<31)) == 0) + return 0; + return 0xFFFFFFFF; + } + return ASR(v, s); + case 5: /* ASRREG */ + sprint(buf, "R%ld", s >> 1); + s = rget(map, buf) & 0xFF; + if(s >= 32) { + if((v & (1U<<31)) == 0) + return 0; + return 0xFFFFFFFF; + } + return ASR(v, s); + case 6: /* RORIMM */ + if(s == 0) { + ulong c = (rget(map, "PSR") >> 29) & 1; + + return (c << 31) | LSR(v, 1); + } + return ROR(v, s); + case 7: /* RORREG */ + sprint(buf, "R%ld", (s>>1)&0xF); + s = rget(map, buf); + if(s == 0 || (s & 0xF) == 0) + return v; + return ROR(v, s & 0xF); + } + } + return 0; +} + +static int +nbits(ulong v) +{ + int n = 0; + int i; + + for(i=0; i < 32 ; i++) { + if(v & 1) ++n; + v >>= 1; + } + + return n; +} + +static ulong +armmaddr(Map *map, Rgetter rget, Instr *i) +{ + ulong v; + ulong nb; + char buf[8]; + ulong rn; + + rn = (i->w >> 16) & 0xf; + sprint(buf,"R%ld", rn); + + v = rget(map, buf); + nb = nbits(i->w & ((1 << 15) - 1)); + + switch((i->w >> 23) & 3) { + case 0: return (v - (nb*4)) + 4; + case 1: return v; + case 2: return v - (nb*4); + case 3: return v + 4; + } + return 0; +} + +static ulong +armaddr(Map *map, Rgetter rget, Instr *i) +{ + char buf[8]; + ulong rn; + + sprint(buf, "R%ld", (i->w >> 16) & 0xf); + rn = rget(map, buf); + + if((i->w & (1<<24)) == 0) { /* POSTIDX */ + sprint(buf, "R%ld", rn); + return rget(map, buf); + } + + if((i->w & (1<<25)) == 0) { /* OFFSET */ + sprint(buf, "R%ld", rn); + if(i->w & (1U<<23)) + return rget(map, buf) + (i->w & BITS(0,11)); + return rget(map, buf) - (i->w & BITS(0,11)); + } else { /* REGOFF */ + ulong index = 0; + uchar c; + uchar rm; + + sprint(buf, "R%ld", i->w & 0xf); + rm = rget(map, buf); + + switch((i->w & BITS(5,6)) >> 5) { + case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break; + case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break; + case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break; + case 3: + if((i->w & BITS(7,11)) == 0) { + c = (rget(map, "PSR") >> 29) & 1; + index = c << 31 | LSR(rm, 1); + } else { + index = ROR(rm, ((i->w & BITS(7,11)) >> 7)); + } + break; + } + if(i->w & (1<<23)) + return rn + index; + return rn - index; + } +} + +static ulong +armfadd(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + char buf[8]; + int r; + + r = (i->w >> 12) & 0xf; + if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf)) + return pc+4; + + r = (i->w >> 16) & 0xf; + sprint(buf, "R%d", r); + + return rget(map, buf) + armshiftval(map, rget, i); +} + +static ulong +armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + uint32 v; + ulong addr; + + v = i->w & 1<<15; + if(!v || !armcondpass(map, rget, (i->w>>28)&0xf)) + return pc+4; + + addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15)); + if(get4(map, addr, &v) < 0) { + werrstr("can't read addr: %r"); + return -1; + } + return v; +} + +static ulong +armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + if(!armcondpass(map, rget, (i->w >> 28) & 0xf)) + return pc+4; + + return pc + (((signed long)i->w << 8) >> 6) + 8; +} + +static ulong +armfmov(Map *map, Rgetter rget, Instr *i, ulong pc) +{ + ulong rd; + uint32 v; + + rd = (i->w >> 12) & 0xf; + if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf)) + return pc+4; + + /* LDR */ + /* BUG: Needs LDH/B, too */ + if(((i->w>>26)&0x3) == 1) { + if(get4(map, armaddr(map, rget, i), &v) < 0) { + werrstr("can't read instruction: %r"); + return pc+4; + } + return v; + } + + /* MOV */ + return armshiftval(map, rget, i); +} + +static Opcode opcodes[] = +{ + "AND%C%S", armdps, 0, "R%s,R%n,R%d", + "EOR%C%S", armdps, 0, "R%s,R%n,R%d", + "SUB%C%S", armdps, 0, "R%s,R%n,R%d", + "RSB%C%S", armdps, 0, "R%s,R%n,R%d", + "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d", + "ADC%C%S", armdps, 0, "R%s,R%n,R%d", + "SBC%C%S", armdps, 0, "R%s,R%n,R%d", + "RSC%C%S", armdps, 0, "R%s,R%n,R%d", + "TST%C%S", armdps, 0, "R%s,R%n", + "TEQ%C%S", armdps, 0, "R%s,R%n", + "CMP%C%S", armdps, 0, "R%s,R%n", + "CMN%C%S", armdps, 0, "R%s,R%n", + "ORR%C%S", armdps, 0, "R%s,R%n,R%d", + "MOVW%C%S", armdps, armfmov, "R%s,R%d", + "BIC%C%S", armdps, 0, "R%s,R%n,R%d", + "MVN%C%S", armdps, 0, "R%s,R%d", + +/* 16 */ + "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d", + "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "TST%C%S", armdps, 0, "(R%s%h%m),R%n", + "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n", + "CMP%C%S", armdps, 0, "(R%s%h%m),R%n", + "CMN%C%S", armdps, 0, "(R%s%h%m),R%n", + "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d", + "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d", + "MVN%C%S", armdps, 0, "(R%s%h%m),R%d", + +/* 32 */ + "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d", + "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "TST%C%S", armdps, 0, "(R%s%hR%M),R%n", + "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n", + "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n", + "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n", + "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d", + "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d", + "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d", + +/* 48 */ + "AND%C%S", armdpi, 0, "$#%i,R%n,R%d", + "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d", + "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d", + "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d", + "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d", + "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "TST%C%S", armdpi, 0, "$#%i,R%n", + "TEQ%C%S", armdpi, 0, "$#%i,R%n", + "CMP%C%S", armdpi, 0, "$#%i,R%n", + "CMN%C%S", armdpi, 0, "$#%i,R%n", + "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d", + "MOVW%C%S", armdpi, armfmov, "$#%i,R%d", + "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d", + "MVN%C%S", armdpi, 0, "$#%i,R%d", + +/* 48+16 */ + "MUL%C%S", armdpi, 0, "R%s,R%M,R%n", + "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d", + "SWPW", armdpi, 0, "R%s,(R%n),R%d", + "SWPB", armdpi, 0, "R%s,(R%n),R%d", + +/* 48+16+4 */ + "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)", + "MOV%u%C%p", armhwby, 0, "R%d,%I", + "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d", + "MOV%u%C%p", armhwby, armfmov, "%I,R%d", + +/* 48+24 */ + "MOVW%C%p", armsdti, 0, "R%d,%I", + "MOVB%C%p", armsdti, 0, "R%d,%I", + "MOVW%C%p", armsdti, armfmov, "%I,R%d", + "MOVBU%C%p", armsdti, armfmov, "%I,R%d", + + "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", + "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)", + "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", + "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d", + + "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)", + "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]", + + "B%C", armb, armfbranch, "%b", + "BL%C", armb, armfbranch, "%b", + + "CDP%C", armco, 0, "", + "CDP%C", armco, 0, "", + "MCR%C", armco, 0, "", + "MRC%C", armco, 0, "", + + "UNK", armunk, 0, "", +}; + +static void +gaddr(Instr *i) +{ + *i->curr++ = '$'; + i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY); +} + +static char *mode[] = { 0, "IA", "DB", "IB" }; +static char *pw[] = { "P", "PW", 0, "W" }; +static char *sw[] = { 0, "W", "S", "SW" }; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + int j, k, m, n; + int g; + char *fmt; + + if(mnemonic) + format(0, i, mnemonic); + if(f == 0) + return; + if(mnemonic) + if(i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if(*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 'C': /* .CONDITION */ + if(cond[i->cond]) + bprint(i, ".%s", cond[i->cond]); + break; + + case 'S': /* .STORE */ + if(i->store) + bprint(i, ".S"); + break; + + case 'P': /* P & U bits for block move */ + n = (i->w >>23) & 0x3; + if (mode[n]) + bprint(i, ".%s", mode[n]); + break; + + case 'p': /* P & W bits for single data xfer*/ + if (pw[i->store]) + bprint(i, ".%s", pw[i->store]); + break; + + case 'a': /* S & W bits for single data xfer*/ + if (sw[i->store]) + bprint(i, ".%s", sw[i->store]); + break; + + case 's': + bprint(i, "%d", i->rs & 0xf); + break; + + case 'M': + bprint(i, "%d", (i->w>>8) & 0xf); + break; + + case 'm': + bprint(i, "%d", (i->w>>7) & 0x1f); + break; + + case 'h': + bprint(i, shtype[(i->w>>5) & 0x3]); + break; + + case 'u': /* Signed/unsigned Byte/Halfword */ + bprint(i, hb[(i->w>>5) & 0x3]); + break; + + case 'I': + if (i->rn == 13) { + if (plocal(i)) + break; + } + g = 0; + fmt = "#%lx(R%d)"; + if (i->rn == 15) { + /* convert load of offset(PC) to a load immediate */ + uint32 x; + if (get4(i->map, i->addr+i->imm+8, &x) > 0) + { + i->imm = (int32)x; + g = 1; + fmt = ""; + } + } + if (mach->sb) + { + if (i->rd == 11) { + uint32 nxti; + + if (get4(i->map, i->addr+4, &nxti) > 0) { + if ((nxti & 0x0e0f0fff) == 0x060c000b) { + i->imm += mach->sb; + g = 1; + fmt = "-SB"; + } + } + } + if (i->rn == 12) + { + i->imm += mach->sb; + g = 1; + fmt = "-SB(SB)"; + } + } + if (g) + { + gaddr(i); + bprint(i, fmt, i->rn); + } + else + bprint(i, fmt, i->imm, i->rn); + break; + case 'U': /* Add/subtract from base */ + bprint(i, addsub[(i->w >> 23) & 1]); + break; + + case 'n': + bprint(i, "%d", i->rn); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'i': + bprint(i, "%lux", i->imm); + break; + + case 'b': + i->curr += symoff(i->curr, i->end-i->curr, + i->imm, CTEXT); + break; + + case 'g': + i->curr += gsymoff(i->curr, i->end-i->curr, + i->imm, CANY); + break; + + case 'r': + n = i->imm&0xffff; + j = 0; + k = 0; + while(n) { + m = j; + while(n&0x1) { + j++; + n >>= 1; + } + if(j != m) { + if(k) + bprint(i, ","); + if(j == m+1) + bprint(i, "R%d", m); + else + bprint(i, "R%d-R%d", m, j-1); + k = 1; + } + j++; + n >>= 1; + } + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n-1; + if(decode(map, pc, &i) < 0) + return -1; + + (*opcodes[i.op].fmt)(&opcodes[i.op], &i); + return 4; +} + +static int +arminst(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + USED(modifier); + return printins(map, pc, buf, n); +} + +static int +armdas(Map *map, uvlong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + if(i.end-i.curr > 8) + i.curr = _hexify(buf, i.w, 7); + *i.curr = 0; + return 4; +} + +static int +arminstlen(Map *map, uvlong pc) +{ + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + return 4; +} + +static int +armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) +{ + ulong d; + Instr i; + + if(decode(map, pc, &i) < 0) + return -1; + + if(opcodes[i.op].foll) { + d = (*opcodes[i.op].foll)(map, rget, &i, pc); + if(d == -1) + return -1; + } else + d = pc+4; + + foll[0] = d; + return 1; +} diff --git a/src/libmach/Makefile b/src/libmach/Makefile index b0031486ab..cde2cdf66c 100644 --- a/src/libmach/Makefile +++ b/src/libmach/Makefile @@ -39,8 +39,10 @@ OFILES=\ access.$O\ machdata.$O\ setmach.$O\ + 5.$O\ 6.$O\ 8.$O\ + 5db.$O\ 8db.$O\ 5obj.$O\ 6obj.$O\ diff --git a/src/libmach/executable.c b/src/libmach/executable.c index 075738e9c8..6bde5b5a44 100644 --- a/src/libmach/executable.c +++ b/src/libmach/executable.c @@ -108,7 +108,6 @@ Mach mmips2be; Mach msparc; Mach msparc64; Mach m68020; -Mach marm; Mach mpower; Mach mpower64; Mach malpha; diff --git a/src/libmach/setmach.c b/src/libmach/setmach.c index b887781867..0fa4d31920 100644 --- a/src/libmach/setmach.c +++ b/src/libmach/setmach.c @@ -1,11 +1,11 @@ // Inferno libmach/setmach.c // http://code.google.com/p/inferno-os/source/browse/utils/libmach/setmach.c // -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. +// Copyright © 1994-1999 Lucent Technologies Inc. +// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). +// Portions Copyright © 1997-1999 Vita Nuova Limited. +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). +// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. // Portions Copyright © 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -50,8 +50,8 @@ extern Mach mmips, msparc, m68020, mi386, mamd64, extern Machdata mipsmach, sparcmach, m68020mach, i386mach, armmach, mipsmach2le, powermach, alphamach, sparc64mach; */ -extern Mach mi386, mamd64; -extern Machdata i386mach; +extern Mach mi386, mamd64, marm; +extern Machdata i386mach, armmach; /* * machine selection table. machines with native disassemblers should @@ -72,6 +72,12 @@ Machtab machines[] = AAMD64, &mamd64, &i386mach, }, + { "arm", /*ARM*/ + FARM, + FARMB, + AARM, + &marm, + &armmach, }, #ifdef unused { "68020", /*68020*/ F68020, @@ -127,12 +133,6 @@ Machtab machines[] = AI8086, &mi386, &i386mach, }, - { "arm", /*ARM*/ - FARM, - FARMB, - AARM, - &marm, - &armmach, }, { "power", /*PowerPC*/ FPOWER, FPOWERB,