arm-dis.c
来自「qemu性能直逼VMware的仿真器QEMU 的模擬速度約為實機的 25%;約為」· C语言 代码 · 共 1,681 行 · 第 1/4 页
C
1,681 行
func (stream, "blx\t"); offset &= 0xfffffffc; } else func (stream, "bl\t"); info->print_address_func (offset, info); return 4; } else { info->bytes_per_chunk = 2; info->bytes_per_line = 4; given &= 0xffff; for (; *c; c++) { if (*c == '%') { int domaskpc = 0; int domasklr = 0; switch (*++c) { case '%': func (stream, "%%"); break; case 'S': { long reg; reg = (given >> 3) & 0x7; if (given & (1 << 6)) reg += 8; func (stream, "%s", arm_regnames[reg]); } break; case 'D': { long reg; reg = given & 0x7; if (given & (1 << 7)) reg += 8; func (stream, "%s", arm_regnames[reg]); } break; case 'T': func (stream, "%s", arm_conditional [(given >> 8) & 0xf]); break; case 'N': if (given & (1 << 8)) domasklr = 1; /* Fall through. */ case 'O': if (*c == 'O' && (given & (1 << 8))) domaskpc = 1; /* Fall through. */ case 'M': { int started = 0; int reg; func (stream, "{"); /* It would be nice if we could spot ranges, and generate the rS-rE format: */ for (reg = 0; (reg < 8); reg++) if ((given & (1 << reg)) != 0) { if (started) func (stream, ", "); started = 1; func (stream, "%s", arm_regnames[reg]); } if (domasklr) { if (started) func (stream, ", "); started = 1; func (stream, arm_regnames[14] /* "lr" */); } if (domaskpc) { if (started) func (stream, ", "); func (stream, arm_regnames[15] /* "pc" */); } func (stream, "}"); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int bitstart = *c++ - '0'; int bitend = 0; while (*c >= '0' && *c <= '9') bitstart = (bitstart * 10) + *c++ - '0'; switch (*c) { case '-': { long reg; c++; while (*c >= '0' && *c <= '9') bitend = (bitend * 10) + *c++ - '0'; if (!bitend) abort (); reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; switch (*c) { case 'r': func (stream, "%s", arm_regnames[reg]); break; case 'd': func (stream, "%d", reg); break; case 'H': func (stream, "%d", reg << 1); break; case 'W': func (stream, "%d", reg << 2); break; case 'a': /* PC-relative address -- the bottom two bits of the address are dropped before the calculation. */ info->print_address_func (((pc + 4) & ~3) + (reg << 2), info); break; case 'x': func (stream, "0x%04x", reg); break; case 'I': reg = ((reg ^ (1 << bitend)) - (1 << bitend)); func (stream, "%d", reg); break; case 'B': reg = ((reg ^ (1 << bitend)) - (1 << bitend)); (*info->print_address_func) (reg * 2 + pc + 4, info); break; default: abort (); } } break; case '\'': c++; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c); break; case '?': ++c; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c++); else func (stream, "%c", *++c); break; default: abort (); } } break; default: abort (); } } else func (stream, "%c", *c); } } return 2; } } /* No match. */ abort ();}/* Parse an individual disassembler option. */voidparse_arm_disassembler_option (option) char * option;{ if (option == NULL) return; if (strneq (option, "reg-names-", 10)) { int i; option += 10; for (i = NUM_ARM_REGNAMES; i--;) if (streq (option, regnames[i].name)) { regname_selected = i; break; } if (i < 0) fprintf (stderr, _("Unrecognised register name set: %s\n"), option); } else if (streq (option, "force-thumb")) force_thumb = 1; else if (streq (option, "no-force-thumb")) force_thumb = 0; else fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); return;}/* Parse the string of disassembler options, spliting it at whitespaces. */static voidparse_disassembler_options (options) char * options;{ char * space; if (options == NULL) return; do { space = strchr (options, ' '); if (space) { * space = '\0'; parse_arm_disassembler_option (options); * space = ' '; options = space + 1; } else parse_arm_disassembler_option (options); } while (space);}/* NOTE: There are no checks in these routines that the relevant number of data bytes exist. */intprint_insn_arm (pc, info) bfd_vma pc; struct disassemble_info * info;{ unsigned char b[4]; long given; int status; int is_thumb; int little; if (info->disassembler_options) { parse_disassembler_options (info->disassembler_options); /* To avoid repeated parsing of these options, we remove them here. */ info->disassembler_options = NULL; } is_thumb = force_thumb; if (pc & 1) { is_thumb = 1; pc &= ~(bfd_vma) 1; } #if 0 if (!is_thumb && info->symbols != NULL) { if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) { coff_symbol_type * cs; cs = coffsymbol (*info->symbols); is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT || cs->native->u.syment.n_sclass == C_THUMBSTAT || cs->native->u.syment.n_sclass == C_THUMBLABEL || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC); } else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour) { elf_symbol_type * es; unsigned int type; es = *(elf_symbol_type **)(info->symbols); type = ELF_ST_TYPE (es->internal_elf_sym.st_info); is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); } }#endif little = (info->endian == BFD_ENDIAN_LITTLE); info->bytes_per_chunk = 4; info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; if (little) { status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info); if (status != 0 && is_thumb) { info->bytes_per_chunk = 2; status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); b[3] = b[2] = 0; } if (status != 0) { info->memory_error_func (status, pc, info); return -1; } given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); } else { status = info->read_memory_func (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info); if (status != 0) { info->memory_error_func (status, pc, info); return -1; } if (is_thumb) { if (pc & 0x2) { given = (b[2] << 8) | b[3]; status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info); if (status != 0) { info->memory_error_func (status, pc + 4, info); return -1; } given |= (b[0] << 24) | (b[1] << 16); } else given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16); } else given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); } if (info->flags & INSN_HAS_RELOC) /* If the instruction has a reloc associated with it, then the offset field in the instruction will actually be the addend for the reloc. (We are using REL type relocs). In such cases, we can ignore the pc when computing addresses, since the addend is not currently pc-relative. */ pc = 0; if (is_thumb) status = print_insn_thumb (pc, info, given); else status = print_insn_arm1 (pc, info, given); return status;}voidprint_arm_disassembler_options (FILE * stream){ int i; fprintf (stream, _("\n\The following ARM specific disassembler options are supported for use with\n\the -M switch:\n")); for (i = NUM_ARM_REGNAMES; i--;) fprintf (stream, " reg-names-%s %*c%s\n", regnames[i].name, (int)(14 - strlen (regnames[i].name)), ' ', regnames[i].description); fprintf (stream, " force-thumb Assume all insns are Thumb insns\n"); fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?