/* tilepro-dis.c. Disassembly routines for the TILEPro architecture. Copyright (C) 2011-2014 Free Software Foundation, Inc. This file is part of the GNU opcodes library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sysdep.h" #include #include #include "bfd.h" #include "elf/tilepro.h" #include "elf-bfd.h" #include "dis-asm.h" #include "opcode/tilepro.h" #define TREG_ZERO 63 static int contains_insn (tilepro_mnemonic expected_mnemonic, int expected_first_operand, int expected_second_operand, bfd_vma memaddr, int *last_operand_ret, disassemble_info *info) { struct tilepro_decoded_instruction decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]; bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES]; int i, num_instructions; if ((*info->read_memory_func) (memaddr, opbuf, TILEPRO_BUNDLE_SIZE_IN_BYTES, info) != 0) /* If we cannot even read the memory, it obviously does not have the instruction for which we are looking. */ return 0; /* Parse the instructions in the bundle. */ num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded); for (i = 0; i < num_instructions; i++) { const struct tilepro_opcode *opcode = decoded[i].opcode; if (opcode->mnemonic != expected_mnemonic) continue; if (expected_first_operand != -1 && decoded[i].operand_values[0] != expected_first_operand) continue; if (expected_second_operand != -1 && decoded[i].operand_values[1] != expected_second_operand) continue; *last_operand_ret = decoded[i].operand_values[opcode->num_operands - 1]; return 1; } /* No match. */ return 0; } int print_insn_tilepro (bfd_vma memaddr, disassemble_info *info) { struct tilepro_decoded_instruction decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]; bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES]; int status, i, num_instructions, num_printed; tilepro_mnemonic padding_mnemonic; status = (*info->read_memory_func) (memaddr, opbuf, TILEPRO_BUNDLE_SIZE_IN_BYTES, info); if (status != 0) { (*info->memory_error_func) (status, memaddr, info); return -1; } info->bytes_per_line = TILEPRO_BUNDLE_SIZE_IN_BYTES; info->bytes_per_chunk = TILEPRO_BUNDLE_SIZE_IN_BYTES; info->octets_per_byte = 1; info->display_endian = BFD_ENDIAN_LITTLE; /* Parse the instructions in the bundle. */ num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded); /* Print the instructions in the bundle. */ info->fprintf_func (info->stream, "{ "); num_printed = 0; /* Determine which nop opcode is used for padding and should be skipped. */ padding_mnemonic = TILEPRO_OPC_FNOP; for (i = 0; i < num_instructions; i++) { if (!decoded[i].opcode->can_bundle) { /* Instructions that cannot be bundled are padded out with nops, rather than fnops. Displaying them is always clutter. */ padding_mnemonic = TILEPRO_OPC_NOP; break; } } for (i = 0; i < num_instructions; i++) { const struct tilepro_opcode *opcode = decoded[i].opcode; const char *name; int j; /* Do not print out fnops, unless everything is an fnop, in which case we will print out just the last one. */ if (opcode->mnemonic == padding_mnemonic && (num_printed > 0 || i + 1 < num_instructions)) continue; if (num_printed > 0) info->fprintf_func (info->stream, " ; "); ++num_printed; name = opcode->name; if (name == NULL) name = ""; info->fprintf_func (info->stream, "%s", name); for (j = 0; j < opcode->num_operands; j++) { int num; const struct tilepro_operand *op; const char *spr_name; if (j > 0) info->fprintf_func (info->stream, ","); info->fprintf_func (info->stream, " "); num = decoded[i].operand_values[j]; op = decoded[i].operands[j]; switch (op->type) { case TILEPRO_OP_TYPE_REGISTER: info->fprintf_func (info->stream, "%s", tilepro_register_names[num]); break; case TILEPRO_OP_TYPE_SPR: spr_name = get_tilepro_spr_name(num); if (spr_name != NULL) info->fprintf_func (info->stream, "%s", spr_name); else info->fprintf_func (info->stream, "%d", num); break; case TILEPRO_OP_TYPE_IMMEDIATE: { bfd_vma addr = 0; int found_addr = 0; int addr_piece; switch (opcode->mnemonic) { case TILEPRO_OPC_ADDLI: if (contains_insn (TILEPRO_OPC_AULI, decoded[i].operand_values[1], TREG_ZERO, memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES, &addr_piece, info)) { addr = num + (addr_piece << 16); found_addr = 1; } break; case TILEPRO_OPC_AULI: if (contains_insn (TILEPRO_OPC_MOVELI, decoded[i].operand_values[1], -1, memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES, &addr_piece, info)) { addr = (num << 16) + addr_piece; found_addr = 1; } break; default: /* Operand does not look like a constructed address. */ break; } info->fprintf_func (info->stream, "%d", num); if (found_addr) { info->fprintf_func (info->stream, " /* "); info->print_address_func (addr, info); info->fprintf_func (info->stream, " */"); } } break; case TILEPRO_OP_TYPE_ADDRESS: info->print_address_func ((bfd_vma)(unsigned int) num, info); break; default: abort (); } } } info->fprintf_func (info->stream, " }"); return TILEPRO_BUNDLE_SIZE_IN_BYTES; }