?? cris-dis.c
字號(hào):
/* Return the number of bits in the argument. */static intnumber_of_bits (unsigned int val){ int bits; for (bits = 0; val != 0; val &= val - 1) bits++; return bits;}/* Get an entry in the opcode-table. */static const struct cris_opcode *get_opcode_entry (unsigned int insn, unsigned int prefix_insn, struct cris_disasm_data *disdata){ /* For non-prefixed insns, we keep a table of pointers, indexed by the insn code. Each entry is initialized when found to be NULL. */ static const struct cris_opcode **opc_table = NULL; const struct cris_opcode *max_matchedp = NULL; const struct cris_opcode **prefix_opc_table = NULL; /* We hold a table for each prefix that need to be handled differently. */ static const struct cris_opcode **dip_prefixes = NULL; static const struct cris_opcode **bdapq_m1_prefixes = NULL; static const struct cris_opcode **bdapq_m2_prefixes = NULL; static const struct cris_opcode **bdapq_m4_prefixes = NULL; static const struct cris_opcode **rest_prefixes = NULL; /* Allocate and clear the opcode-table. */ if (opc_table == NULL) { opc_table = malloc (65536 * sizeof (opc_table[0])); if (opc_table == NULL) return NULL; memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *)); dip_prefixes = malloc (65536 * sizeof (const struct cris_opcode **)); if (dip_prefixes == NULL) return NULL; memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0])); bdapq_m1_prefixes = malloc (65536 * sizeof (const struct cris_opcode **)); if (bdapq_m1_prefixes == NULL) return NULL; memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0])); bdapq_m2_prefixes = malloc (65536 * sizeof (const struct cris_opcode **)); if (bdapq_m2_prefixes == NULL) return NULL; memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0])); bdapq_m4_prefixes = malloc (65536 * sizeof (const struct cris_opcode **)); if (bdapq_m4_prefixes == NULL) return NULL; memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0])); rest_prefixes = malloc (65536 * sizeof (const struct cris_opcode **)); if (rest_prefixes == NULL) return NULL; memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0])); } /* Get the right table if this is a prefix. This code is connected to cris_constraints in that it knows what prefixes play a role in recognition of patterns; the necessary state is reflected by which table is used. If constraints involving match or non-match of prefix insns are changed, then this probably needs changing too. */ if (prefix_insn != NO_CRIS_PREFIX) { const struct cris_opcode *popcodep = (opc_table[prefix_insn] != NULL ? opc_table[prefix_insn] : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata)); if (popcodep == NULL) return NULL; if (popcodep->match == BDAP_QUICK_OPCODE) { /* Since some offsets are recognized with "push" macros, we have to have different tables for them. */ int offset = (prefix_insn & 255); if (offset > 127) offset -= 256; switch (offset) { case -4: prefix_opc_table = bdapq_m4_prefixes; break; case -2: prefix_opc_table = bdapq_m2_prefixes; break; case -1: prefix_opc_table = bdapq_m1_prefixes; break; default: prefix_opc_table = rest_prefixes; break; } } else if (popcodep->match == DIP_OPCODE) /* We don't allow postincrement when the prefix is DIP, so use a different table for DIP. */ prefix_opc_table = dip_prefixes; else prefix_opc_table = rest_prefixes; } if (prefix_insn != NO_CRIS_PREFIX && prefix_opc_table[insn] != NULL) max_matchedp = prefix_opc_table[insn]; else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) max_matchedp = opc_table[insn]; else { const struct cris_opcode *opcodep; int max_level_of_match = -1; for (opcodep = cris_opcodes; opcodep->name != NULL; opcodep++) { int level_of_match; if (disdata->distype == cris_dis_v32) { switch (opcodep->applicable_version) { case cris_ver_version_all: break; case cris_ver_v0_3: case cris_ver_v0_10: case cris_ver_v3_10: case cris_ver_sim_v0_10: case cris_ver_v8_10: case cris_ver_v10: case cris_ver_warning: continue; case cris_ver_v3p: case cris_ver_v8p: case cris_ver_v10p: case cris_ver_v32p: break; case cris_ver_v8: abort (); default: abort (); } } else { switch (opcodep->applicable_version) { case cris_ver_version_all: case cris_ver_v0_3: case cris_ver_v3p: case cris_ver_v0_10: case cris_ver_v8p: case cris_ver_v8_10: case cris_ver_v10: case cris_ver_sim_v0_10: case cris_ver_v10p: case cris_ver_warning: break; case cris_ver_v32p: continue; case cris_ver_v8: abort (); default: abort (); } } /* We give a double lead for bits matching the template in cris_opcodes. Not even, because then "move p8,r10" would be given 2 bits lead over "clear.d r10". When there's a tie, the first entry in the table wins. This is deliberate, to avoid a more complicated recognition formula. */ if ((opcodep->match & insn) == opcodep->match && (opcodep->lose & insn) == 0 && ((level_of_match = cris_constraint (opcodep->args, insn, prefix_insn, disdata)) >= 0) && ((level_of_match += 2 * number_of_bits (opcodep->match | opcodep->lose)) > max_level_of_match)) { max_matchedp = opcodep; max_level_of_match = level_of_match; /* If there was a full match, never mind looking further. */ if (level_of_match >= 2 * 16) break; } } /* Fill in the new entry. If there are changes to the opcode-table involving prefixes, and disassembly then does not work correctly, try removing the else-clause below that fills in the prefix-table. If that helps, you need to change the prefix_opc_table setting above, or something related. */ if (prefix_insn == NO_CRIS_PREFIX) opc_table[insn] = max_matchedp; else prefix_opc_table[insn] = max_matchedp; } return max_matchedp;}/* Return -1 if the constraints of a bitwise-matched instruction say that there is no match. Otherwise return a nonnegative number indicating the confidence in the match (higher is better). */static intcris_constraint (const char *cs, unsigned int insn, unsigned int prefix_insn, struct cris_disasm_data *disdata){ int retval = 0; int tmp; int prefix_ok = 0; const char *s; for (s = cs; *s; s++) switch (*s) { case '!': /* Do not recognize "pop" if there's a prefix and then only for v0..v10. */ if (prefix_insn != NO_CRIS_PREFIX || disdata->distype != cris_dis_v0_v10) return -1; break; case 'U': /* Not recognized at disassembly. */ return -1; case 'M': /* Size modifier for "clear", i.e. special register 0, 4 or 8. Check that it is one of them. Only special register 12 could be mismatched, but checking for matches is more logical than checking for mismatches when there are only a few cases. */ tmp = ((insn >> 12) & 0xf); if (tmp != 0 && tmp != 4 && tmp != 8) return -1; break; case 'm': if ((insn & 0x30) == 0x30) return -1; break; case 'S': /* A prefix operand without side-effect. */ if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) { prefix_ok = 1; break; } else return -1; case 's': case 'y': case 'Y': /* If this is a prefixed insn with postincrement (side-effect), the prefix must not be DIP. */ if (prefix_insn != NO_CRIS_PREFIX) { if (insn & 0x400) { const struct cris_opcode *prefix_opcodep = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); if (prefix_opcodep->match == DIP_OPCODE) return -1; } prefix_ok = 1; } break; case 'B': /* If we don't fall through, then the prefix is ok. */ prefix_ok = 1; /* A "push" prefix. Check for valid "push" size. In case of special register, it may be != 4. */ if (prefix_insn != NO_CRIS_PREFIX) { /* Match the prefix insn to BDAPQ. */ const struct cris_opcode *prefix_opcodep = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); if (prefix_opcodep->match == BDAP_QUICK_OPCODE) { int pushsize = (prefix_insn & 255); if (pushsize > 127) pushsize -= 256; if (s[1] == 'P') { unsigned int spec_reg = (insn >> 12) & 15; const struct cris_spec_reg *sregp = spec_reg_info (spec_reg, disdata->distype); /* For a special-register, the "prefix size" must match the size of the register. */ if (sregp && sregp->reg_size == (unsigned int) -pushsize) break; } else if (s[1] == 'R') { if ((insn & 0x30) == 0x20 && pushsize == -4) break; } /* FIXME: Should abort here; next constraint letter *must* be 'P' or 'R'. */ } } return -1; case 'D': retval = (((insn >> 12) & 15) == (insn & 15)); if (!retval) return -1; else retval += 4; break; case 'P': { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15, disdata->distype); /* Since we match four bits, we will give a value of 4-1 = 3 in a match. If there is a corresponding exact match of a special register in another pattern, it will get a value of 4, which will be higher. This should be correct in that an exact pattern would match better than a general pattern. Note that there is a reason for not returning zero; the pattern for "clear" is partly matched in the bit-pattern (the two lower bits must be zero), while the bit-pattern for a move from a special register is matched in the register constraint. */ if (sregp != NULL) { retval += 3; break; } else return -1; } } if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) return -1; return retval;}/* Format number as hex with a leading "0x" into outbuffer. */static char *format_hex (unsigned long number, char *outbuffer, struct cris_disasm_data *disdata){ /* Truncate negative numbers on >32-bit hosts. */ number &= 0xffffffff; sprintf (outbuffer, "0x%lx", number); /* Save this value for the "case" support. */ if (TRACE_CASE) last_immediate = number; return outbuffer + strlen (outbuffer);}/* Format number as decimal into outbuffer. Parameter signedp says whether the number should be formatted as signed (!= 0) or unsigned (== 0). */static char *format_dec (long number, char *outbuffer, int signedp){ last_immediate = number; sprintf (outbuffer, signedp ? "%ld" : "%lu", number); return outbuffer + strlen (outbuffer);}/* Format the name of the general register regno into outbuffer. */static char *format_reg (struct cris_disasm_data *disdata, int regno, char *outbuffer_start, bfd_boolean with_reg_prefix){ char *outbuffer = outbuffer_start; if (with_reg_prefix) *outbuffer++ = REGISTER_PREFIX_CHAR; switch (regno) { case 15: /* For v32, there is no context in which we output PC. */ if (disdata->distype == cris_dis_v32) strcpy (outbuffer, "acr"); else
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -