Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ppcdis.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      ppcdis.cc
00004  *
00005  *      Copyright (C) 1999-2002 Sebastian Biallas (sb@web-productions.de)
00006  *      Copyright 1994 Free Software Foundation, Inc.
00007  *      Written by Ian Lance Taylor, Cygnus Support
00008  *
00009  *      This program is free software; you can redistribute it and/or modify
00010  *      it under the terms of the GNU General Public License version 2 as
00011  *      published by the Free Software Foundation.
00012  *
00013  *      This program is distributed in the hope that it will be useful,
00014  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *      GNU General Public License for more details.
00017  *
00018  *      You should have received a copy of the GNU General Public License
00019  *      along with this program; if not, write to the Free Software
00020  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021  */
00022 
00023 #include "htendian.h"
00024 #include "ppcdis.h"
00025 #include "ppcopc.h"
00026 #include "tools.h"
00027 
00028 PPCDisassembler::PPCDisassembler()
00029 {
00030 }
00031 
00032 dis_insn *PPCDisassembler::decode(byte *code, int maxlen, CPU_ADDR addr)
00033 {
00034         const struct powerpc_opcode *opcode;
00035         const struct powerpc_opcode *opcode_end;
00036         uint32 op;
00037         int dialect = -1;
00038 
00039         insn.data = create_host_int(code, 4, big_endian);
00040         
00041         if (maxlen<4) {
00042                 insn.valid = false;
00043                 insn.size = maxlen;
00044                 return &insn;
00045         }
00046 
00047         insn.size = 4;
00048 
00049         /* Get the major opcode of the instruction.  */
00050         op = PPC_OP(insn.data);
00051 
00052         /* Find the first match in the opcode table.  We could speed this up
00053            a bit by doing a binary search on the major opcode.  */
00054         opcode_end = powerpc_opcodes + powerpc_num_opcodes;
00055         
00056         for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) {
00057                 uint32 table_op;
00058                 const byte *opindex;
00059                 const struct powerpc_operand *operand;
00060                 bool invalid;
00061                 bool need_comma;
00062                 bool need_paren;
00063 
00064                 table_op = PPC_OP (opcode->opcode);
00065                 if (op < table_op) break;
00066                 if (op > table_op) continue;
00067 
00068                 if ((insn.data & opcode->mask) != opcode->opcode || (opcode->flags & dialect) == 0) {
00069                         continue;
00070                 }
00071 
00072                 /* Make two passes over the operands.  First see if any of them
00073                    have extraction functions, and, if they do, make sure the
00074                    instruction is valid.  */
00075                 invalid = false;
00076                 for (opindex = opcode->operands; *opindex != 0; opindex++) {
00077                         operand = powerpc_operands + *opindex;
00078                         if (operand->extract) (*operand->extract)(insn.data, &invalid);
00079                 }
00080                 if (invalid) continue;
00081 
00082                 /* The instruction is valid.  */
00083 //              fprintf(out, "%s", opcode->name);
00084                 insn.name = opcode->name;
00085 //              if (opcode->operands[0] != 0) fprintf(out, "\t");
00086 
00087                 /* Now extract and print the operands.  */
00088                 need_comma = false;
00089                 need_paren = false;
00090                 int opidx = 0;
00091                 for (opindex = opcode->operands; *opindex != 0; opindex++) {
00092                         uint32 value;
00093 
00094                         operand = powerpc_operands + *opindex;
00095 
00096                         /* Operands that are marked FAKE are simply ignored.  We
00097                            already made sure that the extract function considered
00098                   the instruction to be valid.  */
00099                         if ((operand->flags & PPC_OPERAND_FAKE) != 0) continue;
00100 
00101                         insn.op[opidx].op = operand;
00102                         insn.op[opidx].flags = operand->flags;
00103                         /* Extract the value from the instruction.  */
00104                         if (operand->extract) {
00105                                 value = (*operand->extract)(insn.data, NULL);
00106                         } else {
00107                                 value = (insn.data >> operand->shift) & ((1 << operand->bits) - 1);
00108                                 if ((operand->flags & PPC_OPERAND_SIGNED) != 0 && (value & (1 << (operand->bits - 1))) != 0) {
00109                                         value -= 1 << operand->bits;
00110                                 }
00111                }
00112 
00113                         /* If the operand is optional, and the value is zero, don't
00114                            print anything.  */
00115                         if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 && (operand->flags & PPC_OPERAND_NEXT) == 0 && value == 0) {
00116                                 insn.op[opidx++].imm = 0;
00117                                 continue;
00118                         }
00119 
00120                         if (need_comma) {
00121 //                              fprintf(out, ", ");
00122                                 need_comma = false;
00123                         }
00124 
00125                         /* Print the operand as directed by the flags.  */
00126                         if ((operand->flags & PPC_OPERAND_GPR) != 0) {
00127                                 insn.op[opidx++].reg = value;
00128                         } else if ((operand->flags & PPC_OPERAND_FPR) != 0) {
00129                                 insn.op[opidx++].freg = value;
00130                         } else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) {
00131                                 insn.op[opidx++].rel.mem = addr.addr32.offset + value;
00132                         } else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) {
00133                                 insn.op[opidx++].abs.mem = value;
00134                         } else if ((operand->flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
00135                                 insn.op[opidx++].imm = value;
00136                         } else {
00137                                 insn.op[opidx++].creg = value;
00138                                 if (operand->bits == 3) {
00139 //                                      fprintf(out, "cr%d", value);
00140                                 } else {
00141 
00142 //                                      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
00143                                         int cr;
00144                                         int cc;
00145                                         cr = value >> 2;
00146 //                                      if (cr != 0) fprintf(out, "4*cr%d", cr);
00147                                         cc = value & 3;
00148                                         if (cc != 0) {
00149 //                                              if (cr != 0) fprintf(out, "+");
00150 //                                              fprintf(out, "%s", cbnames[cc]);
00151                                         }
00152                                 }
00153                         }
00154 
00155                         if (need_paren) {
00156 //                              fprintf(out, ")");
00157                                 need_paren = false;
00158                         }
00159 
00160                         if ((operand->flags & PPC_OPERAND_PARENS) == 0) {
00161                                 need_comma = true;
00162                         } else {
00163 //                              fprintf(out, "(");
00164                                 need_paren = true;
00165                         }
00166                 }
00167                 insn.ops = opidx;
00168 
00169                 /* We have found and printed an instruction; return.  */
00170                 insn.valid = true;
00171                 return &insn;
00172         }
00173 
00174         insn.valid = false;
00175         return &insn;
00176 }
00177 
00178 dis_insn *PPCDisassembler::duplicateInsn(dis_insn *disasm_insn)
00179 {
00180         ppcdis_insn *insn = (ppcdis_insn *)malloc(sizeof (ppcdis_insn));
00181         *insn = *(ppcdis_insn *)disasm_insn;
00182         return insn;
00183 }
00184 
00185 void PPCDisassembler::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align)
00186 {
00187         min_length = max_length = min_look_ahead = avg_look_ahead = addr_align = 4;
00188 }
00189 
00190 byte PPCDisassembler::getSize(dis_insn *disasm_insn)
00191 {
00192         return ((ppcdis_insn*)disasm_insn)->size;
00193 }
00194 
00195 char *PPCDisassembler::getName()
00196 {
00197         return "PPC/Disassembler";
00198 }
00199 
00200 char *PPCDisassembler::str(dis_insn *disasm_insn, int style)
00201 {
00202         return strf(disasm_insn, style, "");
00203 }
00204 
00205 char *PPCDisassembler::strf(dis_insn *disasm_insn, int style, char *format)
00206 {
00207         if (style & DIS_STYLE_HIGHLIGHT) enable_highlighting();
00208         
00209         const char *cs_default = get_cs(e_cs_default);
00210         const char *cs_number = get_cs(e_cs_number);
00211         const char *cs_symbol = get_cs(e_cs_symbol);
00212 
00213         ppcdis_insn *ppc_insn = (ppcdis_insn *) disasm_insn;
00214         if (!ppc_insn->valid) {
00215                 switch (ppc_insn->size) {
00216                         case 1:
00217                                 strcpy(insnstr, "db         ?");
00218                                 break;
00219                         case 2:
00220                                 strcpy(insnstr, "dw         ?");
00221                                 break;
00222                         case 3:
00223                                 strcpy(insnstr, "db         ? * 3");
00224                                 break;
00225                         case 4:
00226                                 sprintf(insnstr, "dd        %s0x%08x", cs_number, ppc_insn->data);
00227                                 break;
00228                         default: { /* braces for empty assert */
00229                                 strcpy(insnstr, "?");
00230 //                              assert(0);
00231                         }
00232                 }
00233         } else {
00234                 char *is = insnstr+sprintf(insnstr, "%-10s", ppc_insn->name);
00235                 int dialect=-1;
00236 
00237                 bool need_comma = false;
00238                 bool need_paren = false;
00239                 for (int opidx = 0; opidx < ppc_insn->ops; opidx++) {
00240                         int flags = ppc_insn->op[opidx].flags;
00241 /*                      if ((flags & PPC_OPERAND_OPTIONAL) != 0 && (flags & PPC_OPERAND_NEXT) == 0 && ppc_insn->op[opidx].imm == 0) {
00242                                 continue;
00243                         }*/
00244                         if (need_comma) {
00245                                 is += sprintf(is, "%s, ", cs_symbol);
00246                                 need_comma = false;
00247                         }
00248                         if ((flags & PPC_OPERAND_GPR) != 0) {
00249                                 is += sprintf(is, "%sr%d", cs_default, ppc_insn->op[opidx].reg);
00250                         } else if ((flags & PPC_OPERAND_FPR) != 0) {
00251                                 is += sprintf(is, "%sf%d", cs_default, ppc_insn->op[opidx].freg);
00252                         } else if ((flags & PPC_OPERAND_RELATIVE) != 0) {
00253                                 CPU_ADDR caddr;
00254                                 caddr.addr32.offset = (dword)ppc_insn->op[opidx].mem.disp;
00255                                 int slen;
00256                                 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
00257                                 if (s) {
00258                                         is += sprintf(is, "%s", cs_default);
00259                                         memmove(is, s, slen);
00260                                         is[slen] = 0;
00261                                         is += slen;
00262                                 } else {
00263                                         is += sprintf(is, "%s0x%x", cs_number, ppc_insn->op[opidx].rel.mem);
00264                                 }
00265                         } else if ((flags & PPC_OPERAND_ABSOLUTE) != 0) {
00266                                 is += sprintf(is, "%s0x%x", cs_number, ppc_insn->op[opidx].abs.mem);
00267                         } else if ((flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
00268                                 is += sprintf(is, "%s%d", cs_number, ppc_insn->op[opidx].imm);
00269                         } else if (ppc_insn->op[opidx].op->bits == 3) {
00270                                 is += sprintf(is, "%scr%d", cs_default, ppc_insn->op[opidx].creg);
00271                         } else {
00272                                 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
00273                                 int cr;
00274                                 int cc;
00275                                 cr = ppc_insn->op[opidx].creg >> 2;
00276                                 if (cr != 0) is += sprintf(is, "%s4%s*%scr%d", cs_number, cs_symbol, cs_default, cr);
00277                                 cc = ppc_insn->op[opidx].creg & 3;
00278                                 if (cc != 0) {
00279                                         if (cr != 0) is += sprintf(is, "%s+", cs_symbol);
00280                                         is += sprintf(is, "%s%s", cs_default, cbnames[cc]);
00281                                 }
00282                         }
00283                 
00284                         if (need_paren) {
00285                                 is += sprintf(is, "%s)", cs_symbol);
00286                                 need_paren = false;
00287                         }
00288 
00289                         if ((flags & PPC_OPERAND_PARENS) == 0) {
00290                                 need_comma = true;
00291                         } else {
00292                                 is += sprintf(is, "%s(", cs_symbol);
00293                                 need_paren = true;
00294                         }
00295                 }
00296         }
00297         disable_highlighting();
00298         return insnstr;     
00299 }
00300 
00301 OBJECT_ID PPCDisassembler::object_id() const
00302 {
00303         return ATOM_DISASM_PPC;
00304 }
00305 
00306 bool PPCDisassembler::validInsn(dis_insn *disasm_insn)
00307 {
00308         return ((ppcdis_insn*)disasm_insn)->valid;
00309 }
00310 
00311 

Generated on Fri May 7 21:15:42 2004 by doxygen 1.3.5