📄 cris-dis.c.svn-base
字号:
strcpy (outbuffer, "pc"); break; case 14: strcpy (outbuffer, "sp"); break; default: sprintf (outbuffer, "r%d", regno); break; } return outbuffer_start + strlen (outbuffer_start);}/* Format the name of a support register into outbuffer. */static char *format_sup_reg (unsigned int regno, char *outbuffer_start, bfd_boolean with_reg_prefix){ char *outbuffer = outbuffer_start; int i; if (with_reg_prefix) *outbuffer++ = REGISTER_PREFIX_CHAR; for (i = 0; cris_support_regs[i].name != NULL; i++) if (cris_support_regs[i].number == regno) { sprintf (outbuffer, "%s", cris_support_regs[i].name); return outbuffer_start + strlen (outbuffer_start); } /* There's supposed to be register names covering all numbers, though some may be generic names. */ sprintf (outbuffer, "format_sup_reg-BUG"); return outbuffer_start + strlen (outbuffer_start);}/* Return the length of an instruction. */static unsignedbytes_to_skip (unsigned int insn, const struct cris_opcode *matchedp, enum cris_disass_family distype, const struct cris_opcode *prefix_matchedp){ /* Each insn is a word plus "immediate" operands. */ unsigned to_skip = 2; const char *template = matchedp->args; const char *s; for (s = template; *s; s++) if ((*s == 's' || *s == 'N' || *s == 'Y') && (insn & 0x400) && (insn & 15) == 15 && prefix_matchedp == NULL) { /* Immediate via [pc+], so we have to check the size of the operand. */ int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); if (matchedp->imm_oprnd_size == SIZE_FIX_32) to_skip += 4; else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15, distype); /* FIXME: Improve error handling; should have been caught earlier. */ if (sregp == NULL) return 2; /* PC is incremented by two, not one, for a byte. Except on CRISv32, where constants are always DWORD-size for special registers. */ to_skip += distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; } else to_skip += (mode_size + 1) & ~1; } else if (*s == 'n') to_skip += 4; else if (*s == 'b') to_skip += 2; return to_skip;}/* Print condition code flags. */static char *print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp){ /* Use the v8 (Etrax 100) flag definitions for disassembly. The differences with v0 (Etrax 1..4) vs. Svinto are: v0 'd' <=> v8 'm' v0 'e' <=> v8 'b'. FIXME: Emit v0..v3 flag names somehow. */ static const char v8_fnames[] = "cvznxibm"; static const char v32_fnames[] = "cvznxiup"; const char *fnames = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames; unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); int i; for (i = 0; i < 8; i++) if (flagbits & (1 << i)) *cp++ = fnames[i]; return cp;}/* Print out an insn with its operands, and update the info->insn_type fields. The prefix_opcodep and the rest hold a prefix insn that is supposed to be output as an address mode. */static voidprint_with_operands (const struct cris_opcode *opcodep, unsigned int insn, unsigned char *buffer, bfd_vma addr, disassemble_info *info, /* If a prefix insn was before this insn (and is supposed to be output as an address), here is a description of it. */ const struct cris_opcode *prefix_opcodep, unsigned int prefix_insn, unsigned char *prefix_buffer, bfd_boolean with_reg_prefix){ /* Get a buffer of somewhat reasonable size where we store intermediate parts of the insn. */ char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; char *tp = temp; static const char mode_char[] = "bwd?"; const char *s; const char *cs; struct cris_disasm_data *disdata = (struct cris_disasm_data *) info->private_data; /* Print out the name first thing we do. */ (*info->fprintf_func) (info->stream, "%s", opcodep->name); cs = opcodep->args; s = cs; /* Ignore any prefix indicator. */ if (*s == 'p') s++; if (*s == 'm' || *s == 'M' || *s == 'z') { *tp++ = '.'; /* Get the size-letter. */ *tp++ = *s == 'M' ? (insn & 0x8000 ? 'd' : insn & 0x4000 ? 'w' : 'b') : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; /* Ignore the size and the space character that follows. */ s += 2; } /* Add a space if this isn't a long-branch, because for those will add the condition part of the name later. */ if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) *tp++ = ' '; /* Fill in the insn-type if deducible from the name (and there's no better way). */ if (opcodep->name[0] == 'j') { if (CONST_STRNEQ (opcodep->name, "jsr")) /* It's "jsr" or "jsrc". */ info->insn_type = dis_jsr; else /* Any other jump-type insn is considered a branch. */ info->insn_type = dis_branch; } /* We might know some more fields right now. */ info->branch_delay_insns = opcodep->delayed; /* Handle operands. */ for (; *s; s++) { switch (*s) { case 'T': tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix); break; case 'A': if (with_reg_prefix) *tp++ = REGISTER_PREFIX_CHAR; *tp++ = 'a'; *tp++ = 'c'; *tp++ = 'r'; break; case '[': case ']': case ',': *tp++ = *s; break; case '!': /* Ignore at this point; used at earlier stages to avoid recognition if there's a prefix at something that in other ways looks like a "pop". */ break; case 'd': /* Ignore. This is an optional ".d " on the large one of relaxable insns. */ break; case 'B': /* This was the prefix that made this a "push". We've already handled it by recognizing it, so signal that the prefix is handled by setting it to NULL. */ prefix_opcodep = NULL; break; case 'D': case 'r': tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); break; case 'R': tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); break; case 'n': { /* Like N but pc-relative to the start of the insn. */ unsigned long number = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + buffer[5] * 0x1000000 + addr); /* Finish off and output previous formatted bytes. */ *tp = 0; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); tp = temp; (*info->print_address_func) ((bfd_vma) number, info); } break; case 'u': { /* Like n but the offset is bits <3:0> in the instruction. */ unsigned long number = (buffer[0] & 0xf) * 2 + addr; /* Finish off and output previous formatted bytes. */ *tp = 0; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); tp = temp; (*info->print_address_func) ((bfd_vma) number, info); } break; case 'N': case 'y': case 'Y': case 'S': case 's': /* Any "normal" memory operand. */ if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL) { /* We're looking at [pc+], i.e. we need to output an immediate number, where the size can depend on different things. */ long number; int signedp = ((*cs == 'z' && (insn & 0x20)) || opcodep->match == BDAP_QUICK_OPCODE); int nbytes; if (opcodep->imm_oprnd_size == SIZE_FIX_32) nbytes = 4; else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15, disdata->distype); /* A NULL return should have been as a non-match earlier, so catch it as an internal error in the error-case below. */ if (sregp == NULL) /* Whatever non-valid size. */ nbytes = 42; else /* PC is always incremented by a multiple of two. For CRISv32, immediates are always 4 bytes for special registers. */ nbytes = disdata->distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; } else { int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); if (mode_size == 1) nbytes = 2; else nbytes = mode_size; } switch (nbytes) { case 1: number = buffer[2]; if (signedp && number > 127) number -= 256; break; case 2: number = buffer[2] + buffer[3] * 256; if (signedp && number > 32767) number -= 65536; break; case 4: number = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + buffer[5] * 0x1000000; break; default: strcpy (tp, "bug"); tp += 3; number = 42; } if ((*cs == 'z' && (insn & 0x20)) || (opcodep->match == BDAP_QUICK_OPCODE && (nbytes <= 2 || buffer[1 + nbytes] == 0))) tp = format_dec (number, tp, signedp); else { unsigned int highbyte = (number >> 24) & 0xff; /* Either output this as an address or as a number. If it's a dword with the same high-byte as the address of the insn, assume it's an address, and also if it's a non-zero non-0xff high-byte. If this is a jsr or a jump, then it's definitely an address. */ if (nbytes == 4 && (highbyte == ((addr >> 24) & 0xff) || (highbyte != 0 && highbyte != 0xff) || info->insn_type == dis_branch || info->insn_type == dis_jsr)) { /* Finish off and output previous formatted bytes. */ *tp = 0; tp = temp; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) number, info); info->target = number; } else tp = format_hex (number, tp, disdata); } } else { /* Not an immediate number. Then this is a (possibly prefixed) memory operand. */ if (info->insn_type != dis_nonbranch) { int mode_size = 1 << ((insn >> 4) & (opcodep->args[0] == 'z' ? 1 : 3)); int size; info->insn_type = dis_dref; info->flags |= CRIS_DIS_FLAG_MEMREF; if (opcodep->imm_oprnd_size == SIZE_FIX_32) size = 4; else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15, disdata->distype); /* FIXME: Improve error handling; should have been caught earlier. */ if (sregp == NULL) size = 4; else size = sregp->reg_size; } else size = mode_size; info->data_size = size; } *tp++ = '['; if (prefix_opcodep /* We don't match dip with a postincremented field as a side-effect address mode. */ && ((insn & 0x400) == 0 || prefix_opcodep->match != DIP_OPCODE)) { if (insn & 0x400) { tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); *tp++ = '='; } /* We mainly ignore the prefix format string when the address-mode syntax is output. */ switch (prefix_opcodep->match) { case DIP_OPCODE: /* It's [r], [r+] or [pc+]. */ if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) { /* It's [pc+]. This cannot possibly be anything but an address. */ unsigned long number = prefix_buffer[2] + prefix_buffer[3] * 256 + prefix_buffer[4] * 65536 + prefix_buffer[5] * 0x1000000; info->target = (bfd_vma) number; /* Finish off and output previous formatted data. */ *tp = 0; tp = temp; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) number, info); } else { /* For a memref in an address, we use target2. In this case, targ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -