cris-dis.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,405 行 · 第 1/3 页
C
1,405 行
number = prefix_buffer[2]; if (number > 127) number -= 256; break; case 2: number = prefix_buffer[2] + prefix_buffer[3] * 256; if (number > 32767) number -= 65536; break; case 4: number = prefix_buffer[2] + prefix_buffer[3] * 256 + prefix_buffer[4] * 65536 + prefix_buffer[5] * 0x1000000; break; default: strcpy (tp, "bug"); tp += 3; number = 42; } info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; info->target2 = (bfd_vma) number; /* If the size is dword, then assume it's an address. */ if (nbytes == 4) { /* Finish off and output previous formatted bytes. */ *tp++ = '+'; *tp = 0; tp = temp; (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) number, info); } else { if (number >= 0) *tp++ = '+'; tp = format_dec (number, tp, 1); } } else { /* Output "r+[R].m" or "r+[R+].m". */ *tp++ = '+'; *tp++ = '['; tp = format_reg (prefix_insn & 15, tp, with_reg_prefix); if (prefix_insn & 0x400) *tp++ = '+'; *tp++ = ']'; *tp++ = '.'; *tp++ = mode_char[(prefix_insn >> 4) & 3]; info->flags |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG | CRIS_DIS_FLAG_MEM_TARGET2_MEM | CRIS_DIS_FLAG_MEM_TARGET_IS_REG | (((prefix_insn >> 4) == 2) ? 0 : (((prefix_insn >> 4) & 3) == 1 ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE))); } break; default: (*info->fprintf_func) (info->stream, "?prefix-bug"); } /* To mark that the prefix is used, reset it. */ prefix_opcodep = NULL; } else { tp = format_reg (insn & 15, tp, with_reg_prefix); info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; info->target = insn & 15; if (insn & 0x400) *tp++ = '+'; } *tp++ = ']'; } break; case 'x': tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix); *tp++ = '.'; *tp++ = mode_char[(insn >> 4) & 3]; break; case 'I': tp = format_dec (insn & 63, tp, 0); break; case 'b': { int where = buffer[2] + buffer[3] * 256; if (where > 32767) where -= 65536; where += addr + 4; if (insn == BA_PC_INCR_OPCODE) info->insn_type = dis_branch; else info->insn_type = dis_condbranch; info->target = (bfd_vma) where; *tp = 0; tp = temp; (*info->fprintf_func) (info->stream, "%s%s ", temp, cris_cc_strings[insn >> 12]); (*info->print_address_func) ((bfd_vma) where, info); } break; case 'c': tp = format_dec (insn & 31, tp, 0); break; case 'C': tp = format_dec (insn & 15, tp, 0); break; case 'o': { long offset = insn & 0xfe; if (insn & 1) offset |= ~0xff; if (opcodep->match == BA_QUICK_OPCODE) info->insn_type = dis_branch; else info->insn_type = dis_condbranch; info->target = (bfd_vma) (addr + 2 + offset); *tp = 0; tp = temp; (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) (addr + 2 + offset), info); } break; case 'O': { long number = buffer[0]; if (number > 127) number = number - 256; tp = format_dec (number, tp, 1); *tp++ = ','; tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix); } break; case 'f': tp = print_flags (insn, tp); break; case 'i': tp = format_dec ((insn & 32) ? (insn & 31) | ~31 : insn & 31, tp, 1); break; case 'P': { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15); if (sregp->name == NULL) /* Should have been caught as a non-match eariler. */ *tp++ = '?'; else { if (with_reg_prefix) *tp++ = REGISTER_PREFIX_CHAR; strcpy (tp, sregp->name); tp += strlen (tp); } } break; default: strcpy (tp, "???"); tp += 3; } } *tp = 0; if (prefix_opcodep) (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")", prefix_opcodep->name, prefix_opcodep->args); (*info->fprintf_func) (info->stream, "%s", temp); /* Get info for matching case-tables, if we don't have any active. We assume that the last constant seen is used; either in the insn itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */ if (TRACE_CASE && case_offset_counter == 0) { if (strncmp (opcodep->name, "sub", 3) == 0) case_offset = last_immediate; /* It could also be an "add", if there are negative case-values. */ else if (strncmp (opcodep->name, "add", 3) == 0) { /* The first case is the negated operand to the add. */ case_offset = -last_immediate; } /* A bound insn will tell us the number of cases. */ else if (strncmp (opcodep->name, "bound", 5) == 0) { no_of_case_offsets = last_immediate + 1; } /* A jump or jsr or branch breaks the chain of insns for a case-table, so assume default first-case again. */ else if (info->insn_type == dis_jsr || info->insn_type == dis_branch || info->insn_type == dis_condbranch) case_offset = 0; }}/* Print the CRIS instruction at address memaddr on stream. Returns length of the instruction, in bytes. Prefix register names with `$' if WITH_REG_PREFIX. */static intprint_insn_cris_generic (memaddr, info, with_reg_prefix) bfd_vma memaddr; disassemble_info *info; boolean with_reg_prefix;{ int nbytes; unsigned int insn; const struct cris_opcode *matchedp; int advance = 0; /* No instruction will be disassembled as longer than this number of bytes; stacked prefixes will not be expanded. */ unsigned char buffer[MAX_BYTES_PER_CRIS_INSN]; unsigned char *bufp; int status; bfd_vma addr; /* There will be an "out of range" error after the last instruction. Reading pairs of bytes in decreasing number, we hope that we will get at least the amount that we will consume. If we can't get any data, or we do not get enough data, we print the error message. */ for (nbytes = MAX_BYTES_PER_CRIS_INSN; nbytes > 0; nbytes -= 2) { status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); if (status == 0) break; } /* If we did not get all we asked for, then clear the rest. Hopefully this makes a reproducible result in case of errors. */ if (nbytes != MAX_BYTES_PER_CRIS_INSN) memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes); addr = memaddr; bufp = buffer; /* Set some defaults for the insn info. */ info->insn_info_valid = 1; info->branch_delay_insns = 0; info->data_size = 0; info->insn_type = dis_nonbranch; info->flags = 0; info->target = 0; info->target2 = 0; /* If we got any data, disassemble it. */ if (nbytes != 0) { matchedp = NULL; insn = bufp[0] + bufp[1] * 256; /* If we're in a case-table, don't disassemble the offsets. */ if (TRACE_CASE && case_offset_counter != 0) { info->insn_type = dis_noninsn; advance += 2; /* If to print data as offsets, then shortcut here. */ (*info->fprintf_func) (info->stream, "case %d%s: -> ", case_offset + no_of_case_offsets - case_offset_counter, case_offset_counter == 1 ? "/default" : ""); (*info->print_address_func) ((bfd_vma) ((short) (insn) + (long) (addr - (no_of_case_offsets - case_offset_counter) * 2)), info); case_offset_counter--; /* The default case start (without a "sub" or "add") must be zero. */ if (case_offset_counter == 0) case_offset = 0; } else if (insn == 0) { /* We're often called to disassemble zeroes. While this is a valid "bcc .+2" insn, it is also useless enough and enough of a nuiscance that we will just output "bcc .+2" for it and signal it as a noninsn. */ (*info->fprintf_func) (info->stream, "bcc .+2"); info->insn_type = dis_noninsn; advance += 2; } else { const struct cris_opcode *prefix_opcodep = NULL; unsigned char *prefix_buffer = bufp; unsigned int prefix_insn = insn; int prefix_size = 0; matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX); /* Check if we're supposed to write out prefixes as address modes and if this was a prefix. */ if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p') { /* If it's a prefix, put it into the prefix vars and get the main insn. */ prefix_size = bytes_to_skip (prefix_insn, matchedp); prefix_opcodep = matchedp; insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256; matchedp = get_opcode_entry (insn, prefix_insn); if (matchedp != NULL) { addr += prefix_size; bufp += prefix_size; advance += prefix_size; } else { /* The "main" insn wasn't valid, at least not when prefixed. Put back things enough to output the prefix insn only, as a normal insn. */ matchedp = prefix_opcodep; insn = prefix_insn; prefix_opcodep = NULL; } } if (matchedp == NULL) { (*info->fprintf_func) (info->stream, "??0x%lx", insn); advance += 2; info->insn_type = dis_noninsn; } else { advance += bytes_to_skip (insn, matchedp); /* The info_type and assorted fields will be set according to the operands. */ print_with_operands (matchedp, insn, bufp, addr, info, prefix_opcodep, prefix_insn, prefix_buffer, with_reg_prefix); } } } else info->insn_type = dis_noninsn; /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error status when reading that much, and the insn decoding indicated a length exceeding what we read, there is an error. */ if (status != 0 && (nbytes == 0 || advance > nbytes)) { (*info->memory_error_func) (status, memaddr, info); return -1; } /* Max supported insn size with one folded prefix insn. */ info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN; /* I would like to set this to a fixed value larger than the actual number of bytes to print in order to avoid spaces between bytes, but objdump.c (2.9.1) does not like that, so we print 16-bit chunks, which is the next choice. */ info->bytes_per_chunk = 2; /* Printing bytes in order of increasing addresses makes sense, especially on a little-endian target. This is completely the opposite of what you think; setting this to BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N we want. */ info->display_endian = BFD_ENDIAN_BIG; return advance;}/* Disassemble, prefixing register names with `$'. */static intprint_insn_cris_with_register_prefix (vma, info) bfd_vma vma; disassemble_info *info;{ return print_insn_cris_generic (vma, info, true);}/* Disassemble, no prefixes on register names. */static intprint_insn_cris_without_register_prefix (vma, info) bfd_vma vma; disassemble_info *info;{ return print_insn_cris_generic (vma, info, false);}/* Return a disassembler-function that prints registers with a `$' prefix, or one that prints registers without a prefix. */disassembler_ftypecris_get_disassembler (abfd) bfd *abfd;{ /* If there's no bfd in sight, we return what is valid as input in all contexts if fed back to the assembler: disassembly *with* register prefix. */ if (abfd == NULL || bfd_get_symbol_leading_char (abfd) == 0) return print_insn_cris_with_register_prefix; return print_insn_cris_without_register_prefix;}/* * Local variables: * eval: (c-set-style "gnu") * indent-tabs-mode: t * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?