/* vm/jit/alpha/disass.c - primitive disassembler for alpha machine code Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Institut f. Computersprachen, TU Wien R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, J. Wenninger This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Contact: cacao@complang.tuwien.ac.at Authors: Andreas Krall Reinhard Grafl $Id: disass.c 1624 2004-11-30 14:49:45Z twisti $ */ #include #include "vm/jit/alpha/disass.h" /* The disassembler uses two tables for decoding the instructions. The first table (ops) is used to classify the instructions based on the op code and contains the instruction names for instructions which don't used the function codes. This table is indexed by the op code (6 bit, 64 entries). The second table (op3s) contains instructions which contain both an op code and a function code. This table is an unsorted list of instructions which is terminated by op code and function code zero. This list is searched linearly for a matching pair of opcode and function code. */ #define ITYPE_UNDEF 0 /* undefined instructions (illegal opcode) */ #define ITYPE_JMP 1 /* jump instructions */ #define ITYPE_MEM 2 /* memory instructions */ #define ITYPE_FMEM 3 /* floating point memory instructions */ #define ITYPE_BRA 4 /* branch instructions */ #define ITYPE_OP 5 /* integer instructions */ #define ITYPE_FOP 6 /* floating point instructions */ /* instruction decode table for 6 bit op codes */ static struct {char *name; int itype;} ops[] = { /* 0x00 */ {"", ITYPE_UNDEF}, /* 0x01 */ {"", ITYPE_UNDEF}, /* 0x02 */ {"", ITYPE_UNDEF}, /* 0x03 */ {"", ITYPE_UNDEF}, /* 0x04 */ {"", ITYPE_UNDEF}, /* 0x05 */ {"", ITYPE_UNDEF}, /* 0x06 */ {"", ITYPE_UNDEF}, /* 0x07 */ {"", ITYPE_UNDEF}, /* 0x08 */ {"lda ", ITYPE_MEM}, /* 0x09 */ {"ldah ", ITYPE_MEM}, /* 0x0a */ {"ldb ", ITYPE_MEM}, /* 0x0b */ {"ldq_u ", ITYPE_MEM}, /* 0x0c */ {"ldw ", ITYPE_MEM}, /* 0x0d */ {"stw ", ITYPE_MEM}, /* 0x0e */ {"stb ", ITYPE_MEM}, /* 0x0f */ {"stq_u ", ITYPE_MEM}, /* 0x10 */ {"op ", ITYPE_OP}, /* 0x11 */ {"op ", ITYPE_OP}, /* 0x12 */ {"op ", ITYPE_OP}, /* 0x13 */ {"op ", ITYPE_OP}, /* 0x14 */ {"", ITYPE_UNDEF}, /* 0x15 */ {"", ITYPE_UNDEF}, /* 0x16 */ {"fop ", ITYPE_FOP}, /* 0x17 */ {"fop ", ITYPE_FOP}, /* 0x18 */ {"memfmt ", ITYPE_MEM}, /* 0x19 */ {"", ITYPE_UNDEF}, /* 0x1a */ {"jmp ", ITYPE_JMP}, /* 0x1b */ {"", ITYPE_UNDEF}, /* 0x1c */ {"op ", ITYPE_OP}, /* 0x1d */ {"", ITYPE_UNDEF}, /* 0x1e */ {"", ITYPE_UNDEF}, /* 0x1f */ {"", ITYPE_UNDEF}, /* 0x20 */ {"ldf ", ITYPE_FMEM}, /* 0x21 */ {"ldg ", ITYPE_FMEM}, /* 0x22 */ {"lds ", ITYPE_FMEM}, /* 0x23 */ {"ldt ", ITYPE_FMEM}, /* 0x24 */ {"stf ", ITYPE_FMEM}, /* 0x25 */ {"stg ", ITYPE_FMEM}, /* 0x26 */ {"sts ", ITYPE_FMEM}, /* 0x27 */ {"stt ", ITYPE_FMEM}, /* 0x28 */ {"ldl ", ITYPE_MEM}, /* 0x29 */ {"ldq ", ITYPE_MEM}, /* 0x2a */ {"ldl_l ", ITYPE_MEM}, /* 0x2b */ {"ldq_l ", ITYPE_MEM}, /* 0x2c */ {"stl ", ITYPE_MEM}, /* 0x2d */ {"stq ", ITYPE_MEM}, /* 0x2e */ {"stl_c ", ITYPE_MEM}, /* 0x2f */ {"stq_c ", ITYPE_MEM}, /* 0x30 */ {"br ", ITYPE_BRA}, /* 0x31 */ {"fbeq ", ITYPE_BRA}, /* 0x32 */ {"fblt ", ITYPE_BRA}, /* 0x33 */ {"fble ", ITYPE_BRA}, /* 0x34 */ {"bsr ", ITYPE_BRA}, /* 0x35 */ {"fbne ", ITYPE_BRA}, /* 0x36 */ {"fbge ", ITYPE_BRA}, /* 0x37 */ {"fbgt ", ITYPE_BRA}, /* 0x38 */ {"blbc ", ITYPE_BRA}, /* 0x39 */ {"beq ", ITYPE_BRA}, /* 0x3a */ {"blt ", ITYPE_BRA}, /* 0x3b */ {"ble ", ITYPE_BRA}, /* 0x3c */ {"blbs ", ITYPE_BRA}, /* 0x3d */ {"bne ", ITYPE_BRA}, /* 0x3e */ {"bge ", ITYPE_BRA}, /* 0x3f */ {"bgt ", ITYPE_BRA} }; /* instruction decode list for 6 bit op codes and 9 bit function codes */ static struct { u2 op, fun; char *name; } op3s[] = { { 0x10, 0x00, "addl " }, { 0x10, 0x40, "addl/v " }, { 0x10, 0x20, "addq " }, { 0x10, 0x60, "addq/v " }, { 0x10, 0x09, "subl " }, { 0x10, 0x49, "subl/v " }, { 0x10, 0x29, "subq " }, { 0x10, 0x69, "subq/v " }, { 0x10, 0x2D, "cmpeq " }, { 0x10, 0x4D, "cmplt " }, { 0x10, 0x6D, "cmple " }, { 0x10, 0x1D, "cmpult " }, { 0x10, 0x3D, "cmpule " }, { 0x10, 0x0F, "cmpbge " }, { 0x10, 0x02, "s4addl " }, { 0x10, 0x0b, "s4subl " }, { 0x10, 0x22, "s4addq " }, { 0x10, 0x2b, "s4subq " }, { 0x10, 0x12, "s8addl " }, { 0x10, 0x1b, "s8subl " }, { 0x10, 0x32, "s8addq " }, { 0x10, 0x3b, "s8subq " }, { 0x11, 0x00, "and " }, { 0x11, 0x20, "or " }, { 0x11, 0x40, "xor " }, { 0x11, 0x08, "andnot " }, { 0x11, 0x28, "ornot " }, { 0x11, 0x48, "xornot " }, { 0x11, 0x24, "cmoveq " }, { 0x11, 0x44, "cmovlt " }, { 0x11, 0x64, "cmovle " }, { 0x11, 0x26, "cmovne " }, { 0x11, 0x46, "cmovge " }, { 0x11, 0x66, "cmovgt " }, { 0x11, 0x14, "cmovlbs" }, { 0x11, 0x16, "cmovlbc" }, { 0x12, 0x39, "sll " }, { 0x12, 0x3C, "sra " }, { 0x12, 0x34, "srl " }, { 0x12, 0x30, "zap " }, { 0x12, 0x31, "zapnot " }, { 0x12, 0x06, "extbl " }, { 0x12, 0x16, "extwl " }, { 0x12, 0x26, "extll " }, { 0x12, 0x36, "extql " }, { 0x12, 0x5a, "extwh " }, { 0x12, 0x6a, "extlh " }, { 0x12, 0x7a, "extqh " }, { 0x12, 0x0b, "insbl " }, { 0x12, 0x1b, "inswl " }, { 0x12, 0x2b, "insll " }, { 0x12, 0x3b, "insql " }, { 0x12, 0x57, "inswh " }, { 0x12, 0x67, "inslh " }, { 0x12, 0x77, "insqh " }, { 0x12, 0x02, "mskbl " }, { 0x12, 0x12, "mskwl " }, { 0x12, 0x22, "mskll " }, { 0x12, 0x32, "mskql " }, { 0x12, 0x52, "mskwh " }, { 0x12, 0x62, "msklh " }, { 0x12, 0x72, "mskqh " }, { 0x13, 0x00, "mull " }, { 0x13, 0x20, "mulq " }, { 0x13, 0x40, "mull/v " }, { 0x13, 0x60, "mulq/v " }, { 0x13, 0x30, "umulh " }, { 0x16, 0x080, "fadd " }, { 0x16, 0x0a0, "dadd " }, { 0x16, 0x081, "fsub " }, { 0x16, 0x0a1, "dsub " }, { 0x16, 0x082, "fmul " }, { 0x16, 0x0a2, "dmul " }, { 0x16, 0x083, "fdiv " }, { 0x16, 0x0a3, "ddiv " }, { 0x16, 0x580, "fadds " }, { 0x16, 0x5a0, "dadds " }, { 0x16, 0x581, "fsubs " }, { 0x16, 0x5a1, "dsubs " }, { 0x16, 0x582, "fmuls " }, { 0x16, 0x5a2, "dmuls " }, { 0x16, 0x583, "fdivs " }, { 0x16, 0x5a3, "ddivs " }, { 0x16, 0x0ac, "cvtdf " }, { 0x16, 0x0bc, "cvtlf " }, { 0x16, 0x0be, "cvtld " }, { 0x16, 0x0af, "cvtdl " }, { 0x16, 0x02f, "cvtdlc " }, { 0x17, 0x030, "cvtli " }, { 0x16, 0x1af, "cvtdlv " }, { 0x16, 0x12f, "cvtdlcv" }, { 0x17, 0x130, "cvtliv " }, { 0x16, 0x5ac, "cvtdfs " }, { 0x16, 0x5af, "cvtdls " }, { 0x16, 0x52f, "cvtdlcs" }, { 0x16, 0x0a4, "fcmpun " }, { 0x16, 0x0a5, "fcmpeq " }, { 0x16, 0x0a6, "fcmplt " }, { 0x16, 0x0a7, "fcmple " }, { 0x16, 0x5a4, "fcmpuns" }, { 0x16, 0x5a5, "fcmpeqs" }, { 0x16, 0x5a6, "fcmplts" }, { 0x16, 0x5a7, "fcmples" }, { 0x17, 0x020, "fmov " }, { 0x17, 0x021, "fmovn " }, { 0x1c, 0x0, "bsext " }, { 0x1c, 0x1, "wsext " }, { 0x00, 0x00, NULL } }; /* name table for 32 integer registers */ char *regs[] = { /* 0x00 */ "v0", /* "$0", */ /* 0x01 */ "t0", /* "$1", */ /* 0x02 */ "t1", /* "$2", */ /* 0x03 */ "t2", /* "$3", */ /* 0x04 */ "t3", /* "$4", */ /* 0x05 */ "t4", /* "$5", */ /* 0x06 */ "t5", /* "$6", */ /* 0x07 */ "t6", /* "$7", */ /* 0x08 */ "t7", /* "$8", */ /* 0x09 */ "s0", /* "$9", */ /* 0x0a */ "s1", /* "$10", */ /* 0x0b */ "s2", /* "$11", */ /* 0x0c */ "s3", /* "$12", */ /* 0x0d */ "s4", /* "$13", */ /* 0x0e */ "s5", /* "$14", */ /* 0x0f */ "s6", /* "$15", */ /* 0x10 */ "a0", /* "$16", */ /* 0x11 */ "a1", /* "$17", */ /* 0x12 */ "a2", /* "$18", */ /* 0x13 */ "a3", /* "$19", */ /* 0x14 */ "a4", /* "$20", */ /* 0x15 */ "a5", /* "$21", */ /* 0x16 */ "t8", /* "$22", */ /* 0x17 */ "t9", /* "$23", */ /* 0x18 */ "t10", /* "$24", */ /* 0x19 */ "t11", /* "$25", */ /* 0x1a */ "ra", /* "$26", */ /* 0x1b */ "pv", /* "$27", */ /* 0x1c */ "at", /* "$28", */ /* 0x1d */ "gp", /* "$29", */ /* 0x1e */ "sp", /* "$30", */ /* 0x1f */ "zero" /* "$31" */ }; /* function disassinstr ******************************************************** outputs a disassembler listing of one machine code instruction on 'stdout' c: instructions machine code pos: instructions address relative to method start *******************************************************************************/ void disassinstr(s4 *code, int pos) { int op; /* 6 bit op code */ int opfun; /* 7 bit function code */ int ra, rb, rc; /* 6 bit register specifiers */ int lit; /* 8 bit unsigned literal */ int i; /* loop counter */ s4 c = *code; op = (c >> 26) & 0x3f; /* 6 bit op code */ opfun = (c >> 5) & 0x7f; /* 7 bit function code */ ra = (c >> 21) & 0x1f; /* 6 bit source register specifier */ rb = (c >> 16) & 0x1f; /* 6 bit source register specifier */ rc = (c >> 0) & 0x1f; /* 6 bit destination register specifiers */ lit = (c >> 13) & 0xff; /* 8 bit unsigned literal */ printf("0x%016lx: %08x ", (u8) code, c); switch (ops[op].itype) { case ITYPE_JMP: switch ((c >> 14) & 3) { /* branch hint */ case 0: if (ra == 31) { printf ("jmp (%s)\n", regs[rb]); return; } printf ("jmp "); break; case 1: if (ra == 26) { printf ("jsr (%s)\n", regs[rb]); return; } printf ("jsr "); break; case 2: if (ra == 31 && rb == 26) { printf ("ret\n"); return; } if (ra == 31) { printf ("ret (%s)\n", regs[rb]); return; } printf ("ret "); break; case 3: printf ("jsr_co "); break; } printf ("%s,(%s)\n", regs[ra], regs[rb]); break; case ITYPE_MEM: { int disp = (c << 16) >> 16; /* 16 bit signed displacement */ if (op == 0x18 && ra == 0 && ra == 0 && disp == 0) printf ("trapb\n"); else printf ("%s %s,%d(%s)\n", ops[op].name, regs[ra], disp, regs[rb]); break; } case ITYPE_FMEM: printf ("%s $f%d,%d(%s)\n", ops[op].name, ra, (c << 16) >> 16, regs[rb]); break; case ITYPE_BRA: /* 21 bit signed branch offset */ if (op == 0x30 && ra == 31) printf("br 0x%016lx\n", (u8) code + 4 + ((c << 11) >> 9)); else if (op == 0x34 && ra == 26) printf("brs 0x%016lx\n", (u8) code + 4 + ((c << 11) >> 9)); else printf("%s %s,0x%016lx\n", ops[op].name, regs[ra], (u8) code + 4 + ((c << 11) >> 9)); break; case ITYPE_FOP: { int fopfun = (c >> 5) & 0x7ff; /* 11 bit fp function code */ if (op == 0x17 && fopfun == 0x020 && ra == rb) { if (ra == 31 && rc == 31) printf("fnop\n"); else printf("fmov $f%d,$f%d\n", ra, rc); return; } for (i = 0; op3s[i].name; i++) if (op3s[i].op == op && op3s[i].fun == fopfun) { printf("%s $f%d,$f%d,$f%d\n", op3s[i].name, ra, rb, rc); return; } printf("%s%x $f%d,$f%d,$f%d\n", ops[op].name, fopfun, ra, rb, rc); break; } case ITYPE_OP: if (op == 0x11 && opfun == 0x20 && ra == rb && ~(c&0x1000)) { if (ra == 31 && rc == 31) printf("nop\n"); else if (ra == 31) printf("clr %s\n", regs[rc]); else printf("mov %s,%s\n", regs[ra], regs[rc]); return; } for (i = 0; op3s[i].name; i++) { if (op3s[i].op == op && op3s[i].fun == opfun) { if (c & 0x1000) /* immediate instruction */ printf("%s %s,%d,%s\n", op3s[i].name, regs[ra], lit, regs[rc]); else printf("%s %s,%s,%s\n", op3s[i].name, regs[ra], regs[rb], regs[rc]); return; } } /* fall through */ default: if (c & 0x1000) /* immediate instruction */ printf("UNDEF %x(%x) $%d,%d,$%d\n", op, opfun, ra, lit, rc); else printf("UNDEF %x(%x) $%d,$%d,$%d\n", op, opfun, ra, rb, rc); } } /* function disassemble ******************************************************** outputs a disassembler listing of some machine code on 'stdout' code: pointer to first instruction len: code size (number of instructions * 4) *******************************************************************************/ void disassemble(s4 *code, int len) { int p; printf (" --- disassembler listing ---\n"); for (p = 0; p < len; p += 4, code++) disassinstr(code, p); } /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: */