#include <lib9.h>#include <bio.h>#include "mach.h" static int debug = 0; typedef struct Instr Instr;struct Instr{ Map *map; ulong w; ulong addr; uchar op; /* super opcode */ uchar rd; uchar rn; uchar rs; long imm; /* 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*); uvlong (*foll)(Map*, Rgetter, Instr*, uvlong); char* a;}; static void format(char*, Instr*, char*);static char FRAMENAME[] = ".frame"; /* * Thumb-specific debugger interface */ static char *thumbexcep(Map*, Rgetter);static int thumbfoll(Map*, uvlong, Rgetter, uvlong*);static int thumbinst(Map*, uvlong, char, char*, int);static int thumbdas(Map*, uvlong, char*, int);static int thumbinstlen(Map*, uvlong); /* * Debugger interface */Machdata thumbmach ={ {0x0, 0xE8}, /* break point */ 2, /* 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 */ thumbexcep, /* print exception */ 0, /* breakpoint fixup */ 0, /* single precision float printer */ 0, /* double precision float printer */ thumbfoll, /* following addresses */ thumbinst, /* print instruction */ thumbdas, /* dissembler */ thumbinstlen, /* instruction size */}; static void thumbrrh(Opcode *, Instr *);static void thumbbcc(Opcode *, Instr *);static void thumbb(Opcode *, Instr *);static void thumbbl(Opcode *, Instr *); static char*thumbexcep(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"; }} staticchar* cond[16] ={ "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "\0", "NV"}; #define B(h, l) bits(ins, h, l) static intbits(int i, int h, int l){ if(h < l) print("h < l in bits"); return (i&(((1<<(h-l+1))-1)<<l))>>l;} intthumbclass(long w){ int o; int ins = w; if(ins&0xffff0000) return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; o = B(15, 13); switch(o){ case 0: o = B(12, 11); switch(o){ case 0: case 1: case 2: return B(12, 11); case 3: if(B(10, 10) == 0) return 3+B(9, 9); else return 3+2+B(9, 9); } case 1: return 3+2+2+B(12, 11); case 2: o = B(12, 10); if(o == 0) return 3+2+2+4+B(9, 6); if(o == 1){ o = B(9, 8); if(o == 3) return 3+2+2+4+16+B(9, 8); return 3+2+2+4+16+B(9, 8); } if(o == 2 || o == 3) return 3+2+2+4+16+4; return 3+2+2+4+16+4+1+B(11, 9); case 3: return 3+2+2+4+16+4+1+8+B(12, 11); case 4: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+4+B(11, 11); return 3+2+2+4+16+4+1+8+6+B(11, 11); case 5: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+6+2+B(11, 11); if(B(11, 8) == 0) return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7); return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11); case 6: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11); if(B(11, 8) == 0xf) return 3+2+2+4+16+4+1+8+6+2+2+2+4; return 3+2+2+4+16+4+1+8+6+2+2+2+4+1; case 7: o = B(12, 11); switch(o){ case 0: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1; case 1: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; case 2: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1; case 3: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1; } } return 0;} static intdecode(Map *map, uvlong pc, Instr *i){ ushort w; if(get2(map, pc, &w) < 0) { werrstr("can't read instruction: %r"); return -1; } i->w = w; i->addr = pc; i->op = thumbclass(w); i->map = map; return 1;} static voidbprint(Instr *i, char *fmt, ...){ va_list arg; va_start(arg, fmt); i->curr = vseprint(i->curr, i->end, fmt, arg); va_end(arg);} static intplocal(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] */static intgsymoff(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+%llux", s.name, v-s.value); else return snprint(buf, n, "#%lux", v);} static intthumbcondpass(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 uvlongthumbfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc){ char buf[8]; if(i->op == 30){ // BX thumbrrh(nil, i); sprint(buf, "R%ud", i->rn); return rget(map, buf)&~1; // clear T bit } if(i->op == 57){ // Bcc thumbbcc(nil, i); if(thumbcondpass(map, rget, (i->w >> 8) & 0xf)) return i->imm; return pc+2; } if(i->op == 58){ // B thumbb(nil, i); return i->imm; } if(i->op == 60){ // BL thumbbl(nil, i); return i->imm; } print("bad thumbfbranch call"); return 0;} static uvlongthumbfmov(Map *map, Rgetter rget, Instr *i, uvlong pc){ char buf[8]; ulong rd; thumbrrh(nil, i); rd = i->rd; if(rd != 15) return pc+2; sprint(buf, "R%ud", i->rn); return rget(map, buf);} static uvlongthumbfadd(Map *map, Rgetter rget, Instr *i, uvlong pc){ char buf[8]; ulong rd, v; thumbrrh(nil, i); rd = i->rd; if(rd != 15) return pc+2; sprint(buf, "R%ud", i->rn); v = rget(map, buf); sprint(buf, "R15"); return rget(map, buf) + v;} static voidthumbshift(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(10, 6); format(o->o, i, o->a);} static voidthumbrrr(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->rs = B(8, 6); format(o->o, i, o->a);} static voidthumbirr(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(8, 6); format(o->o, i, o->a);} static voidthumbir(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(10, 8); i->imm = B(7, 0); format(o->o, i, o->a);} static voidthumbrr(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); format(o->o, i, o->a);} static voidthumbrrh(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); if(B(6, 6)) i->rn += 8; if(B(7, 7)) i->rd += 8; if(o != nil){ if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr format("RET", i, ""); else format(o->o, i, o->a); }} static voidthumbpcrel(Opcode *o, Instr *i){ int ins = i->w; i->rn = 15; i->rd = B(10, 8); i->imm = 4*(B(7, 0)+1); if(i->addr & 3) i->imm -= 2; format(o->o, i, o->a);} static voidthumbmovirr(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(10, 6); if(strcmp(o->o, "MOVW") == 0) i->imm *= 4; else if(strncmp(o->o, "MOVH", 4) == 0) i->imm *= 2; format(o->o, i, o->a);} static voidthumbmovsp(Opcode *o, Instr *i){ int ins = i->w; i->rn = 13; i->rd = B(10, 8); i->imm = 4*B(7, 0); format(o->o, i, o->a);} static voidthumbaddsppc(Opcode *o, Instr *i){ int ins = i->w; i->rd = B(10, 8); i->imm = 4*B(7, 0); if(i->op == 48) i->imm += 4; format(o->o, i, o->a);}Lines 1–500 of 839. Load more
#include <lib9.h> #include <bio.h> #include "mach.h" static int debug = 0; typedef struct Instr Instr; struct Instr { Map *map; ulong w; ulong addr; uchar op; /* super opcode */ uchar rd; uchar rn; uchar rs; long imm; /* 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*); uvlong (*foll)(Map*, Rgetter, Instr*, uvlong); char* a; }; static void format(char*, Instr*, char*); static char FRAMENAME[] = ".frame"; /* * Thumb-specific debugger interface */ static char *thumbexcep(Map*, Rgetter); static int thumbfoll(Map*, uvlong, Rgetter, uvlong*); static int thumbinst(Map*, uvlong, char, char*, int); static int thumbdas(Map*, uvlong, char*, int); static int thumbinstlen(Map*, uvlong); /* * Debugger interface */ Machdata thumbmach = { {0x0, 0xE8}, /* break point */ 2, /* 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 */ thumbexcep, /* print exception */ 0, /* breakpoint fixup */ 0, /* single precision float printer */ 0, /* double precision float printer */ thumbfoll, /* following addresses */ thumbinst, /* print instruction */ thumbdas, /* dissembler */ thumbinstlen, /* instruction size */ }; static void thumbrrh(Opcode *, Instr *); static void thumbbcc(Opcode *, Instr *); static void thumbb(Opcode *, Instr *); static void thumbbl(Opcode *, Instr *); static char* thumbexcep(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" }; #define B(h, l) bits(ins, h, l) static int bits(int i, int h, int l) { if(h < l) print("h < l in bits"); return (i&(((1<<(h-l+1))-1)<<l))>>l; } int thumbclass(long w) { int o; int ins = w; if(ins&0xffff0000) return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; o = B(15, 13); switch(o){ case 0: o = B(12, 11); switch(o){ case 0: case 1: case 2: return B(12, 11); case 3: if(B(10, 10) == 0) return 3+B(9, 9); else return 3+2+B(9, 9); } case 1: return 3+2+2+B(12, 11); case 2: o = B(12, 10); if(o == 0) return 3+2+2+4+B(9, 6); if(o == 1){ o = B(9, 8); if(o == 3) return 3+2+2+4+16+B(9, 8); return 3+2+2+4+16+B(9, 8); } if(o == 2 || o == 3) return 3+2+2+4+16+4; return 3+2+2+4+16+4+1+B(11, 9); case 3: return 3+2+2+4+16+4+1+8+B(12, 11); case 4: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+4+B(11, 11); return 3+2+2+4+16+4+1+8+6+B(11, 11); case 5: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+6+2+B(11, 11); if(B(11, 8) == 0) return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7); return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11); case 6: if(B(12, 12) == 0) return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11); if(B(11, 8) == 0xf) return 3+2+2+4+16+4+1+8+6+2+2+2+4; return 3+2+2+4+16+4+1+8+6+2+2+2+4+1; case 7: o = B(12, 11); switch(o){ case 0: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1; case 1: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; case 2: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1; case 3: return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1; } } return 0; } static int decode(Map *map, uvlong pc, Instr *i) { ushort w; if(get2(map, pc, &w) < 0) { werrstr("can't read instruction: %r"); return -1; } i->w = w; i->addr = pc; i->op = thumbclass(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] */ static 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+%llux", s.name, v-s.value); else return snprint(buf, n, "#%lux", v); } static int thumbcondpass(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 uvlong thumbfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc) { char buf[8]; if(i->op == 30){ // BX thumbrrh(nil, i); sprint(buf, "R%ud", i->rn); return rget(map, buf)&~1; // clear T bit } if(i->op == 57){ // Bcc thumbbcc(nil, i); if(thumbcondpass(map, rget, (i->w >> 8) & 0xf)) return i->imm; return pc+2; } if(i->op == 58){ // B thumbb(nil, i); return i->imm; } if(i->op == 60){ // BL thumbbl(nil, i); return i->imm; } print("bad thumbfbranch call"); return 0; } static uvlong thumbfmov(Map *map, Rgetter rget, Instr *i, uvlong pc) { char buf[8]; ulong rd; thumbrrh(nil, i); rd = i->rd; if(rd != 15) return pc+2; sprint(buf, "R%ud", i->rn); return rget(map, buf); } static uvlong thumbfadd(Map *map, Rgetter rget, Instr *i, uvlong pc) { char buf[8]; ulong rd, v; thumbrrh(nil, i); rd = i->rd; if(rd != 15) return pc+2; sprint(buf, "R%ud", i->rn); v = rget(map, buf); sprint(buf, "R15"); return rget(map, buf) + v; } static void thumbshift(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(10, 6); format(o->o, i, o->a); } static void thumbrrr(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->rs = B(8, 6); format(o->o, i, o->a); } static void thumbirr(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(8, 6); format(o->o, i, o->a); } static void thumbir(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(10, 8); i->imm = B(7, 0); format(o->o, i, o->a); } static void thumbrr(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); format(o->o, i, o->a); } static void thumbrrh(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); if(B(6, 6)) i->rn += 8; if(B(7, 7)) i->rd += 8; if(o != nil){ if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr format("RET", i, ""); else format(o->o, i, o->a); } } static void thumbpcrel(Opcode *o, Instr *i) { int ins = i->w; i->rn = 15; i->rd = B(10, 8); i->imm = 4*(B(7, 0)+1); if(i->addr & 3) i->imm -= 2; format(o->o, i, o->a); } static void thumbmovirr(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(2, 0); i->rn = B(5, 3); i->imm = B(10, 6); if(strcmp(o->o, "MOVW") == 0) i->imm *= 4; else if(strncmp(o->o, "MOVH", 4) == 0) i->imm *= 2; format(o->o, i, o->a); } static void thumbmovsp(Opcode *o, Instr *i) { int ins = i->w; i->rn = 13; i->rd = B(10, 8); i->imm = 4*B(7, 0); format(o->o, i, o->a); } static void thumbaddsppc(Opcode *o, Instr *i) { int ins = i->w; i->rd = B(10, 8); i->imm = 4*B(7, 0); if(i->op == 48) i->imm += 4; format(o->o, i, o->a); }