00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00050 op = PPC_OP(insn.data);
00051
00052
00053
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
00073
00074
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
00083
00084 insn.name = opcode->name;
00085
00086
00087
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
00097
00098
00099 if ((operand->flags & PPC_OPERAND_FAKE) != 0) continue;
00100
00101 insn.op[opidx].op = operand;
00102 insn.op[opidx].flags = operand->flags;
00103
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
00114
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
00122 need_comma = false;
00123 }
00124
00125
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
00140 } else {
00141
00142
00143 int cr;
00144 int cc;
00145 cr = value >> 2;
00146
00147 cc = value & 3;
00148 if (cc != 0) {
00149
00150
00151 }
00152 }
00153 }
00154
00155 if (need_paren) {
00156
00157 need_paren = false;
00158 }
00159
00160 if ((operand->flags & PPC_OPERAND_PARENS) == 0) {
00161 need_comma = true;
00162 } else {
00163
00164 need_paren = true;
00165 }
00166 }
00167 insn.ops = opidx;
00168
00169
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: {
00229 strcpy(insnstr, "?");
00230
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
00242
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