/* Chrysalide - Outil d'analyse de fichiers binaires * arm.c - désassemblage des instructions ARMv7 * * Copyright (C) 2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA 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. * * OpenIDA 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 Foobar. If not, see . */ #include "arm.h" #include #include "opcodes/opcodes.h" #include "../../../common/bconst.h" /* Désassemble une instruction ARMv7 de données ou autre. */ static GArchInstruction *process_armv7_data_processing_and_miscellaneous_instructions(uint32_t); /* Désassemble une instruction ARMv7 de données de registre. */ static GArchInstruction *process_armv7_data_processing_register(uint32_t); /* Désassemble une instruction ARMv7 de données de immédiate. */ static GArchInstruction *process_armv7_data_processing_immediate(uint32_t); /* Désassemble une instruction ARMv7 liées aux multiplications. */ static GArchInstruction *process_armv7_multiply_and_multiply_accumulate(uint32_t); /* Désassemble une instruction ARMv7 de données ou autre. */ static GArchInstruction *process_armv7_branch_branch_with_link_and_block_data_transfer(uint32_t); // process_armv7_instruction_set_encoding #define process_armv7_load_store_word_and_unsigned_byte(raw) NULL #define process_armv7_load_store_word_and_unsigned_byte(raw) NULL #define process_armv7_media_instructions(raw) NULL //#define process_armv7_branch_branch_with_link_and_block_data_transfer(raw) NULL #define process_armv7_coprocessor_instructions_and_Supervisor_call(raw) NULL #define process_armv7_unconditional_instructions(raw) NULL // process_armv7_data_processing_and_miscellaneous_instructions #define process_armv7_data_processing_register_shifted_register(raw) NULL #define process_armv7_extra_load_store_instructions(raw) NULL #define process_armv7_miscellaneous_instructions(raw) NULL #define process_armv7_halfword_multiply_and_multiply_accumulate(raw) NULL //#define process_armv7_multiply_and_multiply_accumulate(raw) NULL #define process_armv7_synchronization_primitives(raw) NULL #define process_armv7_extra_load_store_instructions_unprivileged(raw) NULL #define process_armv7_extra_load_store_instructions(raw) NULL //#define process_armv7_data_processing_immediate(raw) NULL #define armv7_read_instr_mov_immediate(raw) NULL #define armv7_read_instr_movt(raw) NULL #define process_armv7_msr_immediate_and_hints(raw) NULL // process_armv7_data_processing_register #define armv7_read_instr_and_register(raw) NULL #define armv7_read_instr_eor_register(raw) NULL #define armv7_read_instr_sub_register(raw) NULL #define armv7_read_instr_rsb_register(raw) NULL #define armv7_read_instr_add_register_arm(raw) NULL #define armv7_read_instr_adc_register(raw) NULL #define armv7_read_instr_sbc_register(raw) NULL #define armv7_read_instr_rsc_register(raw) NULL #define armv7_read_instr_tst_register(raw) NULL #define armv7_read_instr_teq_register(raw) NULL #define armv7_read_instr_cmp_register(raw) NULL #define armv7_read_instr_cmn_register(raw) NULL #define armv7_read_instr_orr_register(raw) NULL //#define armv7_read_instr_mov_register_arm(raw) NULL #define armv7_read_instr_lsl_immediate(raw) NULL #define armv7_read_instr_lsr_immediate(raw) NULL #define armv7_read_instr_asr_immediate(raw) NULL #define armv7_read_instr_rrx(raw) NULL #define armv7_read_instr_ror_immediate(raw) NULL #define armv7_read_instr_bic_register(raw) NULL #define armv7_read_instr_mvn_register(raw) NULL // process_armv7_branch_branch_with_link_and_block_data_transfer #define armv7_read_instr_stmda_stmed(raw) NULL #define armv7_read_instr_ldmda_ldmfa(raw) NULL #define armv7_read_instr_stm_stmia_stmea(raw) NULL #define armv7_read_instr_ldm_ldmia_ldmfd_arm(raw) NULL #define armv7_read_instr_ldm_ldmia_ldmfd_arm(raw) NULL #define armv7_read_instr_pop_arm(raw) NULL #define armv7_read_instr_stmdb_stmfd(raw) NULL #define armv7_read_instr_stmdb_stmfd(raw) NULL #define armv7_read_instr_push(raw) NULL #define armv7_read_instr_ldmdb_ldmea(raw) NULL #define armv7_read_instr_stmib_stmfa(raw) NULL #define armv7_read_instr_ldmib_ldmed(raw) NULL #define armv7_read_instr_stm_user_registers(raw) NULL #define armv7_read_instr_ldm_user_registers(raw) NULL #define armv7_read_instr_ldm_exception_return(raw) NULL #define armv7_read_instr_b(raw) NULL //#define armv7_read_instr_bl_blx_immediate(raw) NULL #define armv7_read_instr_adr(raw) NULL // ??? #define armv7_read_instr_yield(raw) NULL #define armv7_read_instr_bx(raw) NULL /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 classique. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *process_armv7_instruction_set_encoding(uint32_t raw) { GArchInstruction *result; /* Instruction à renvoyer */ uint32_t cond; /* Champ 'cond' à retrouver */ uint32_t op1; /* Champ 'op1' à retrouver */ uint32_t op; /* Champ 'op' à retrouver */ /** * Suit les directives de : * § A5.1 ARM instruction set encoding */ result = NULL; cond = (raw >> 28) & 0xf; op1 = (raw >> 25) & 0x7; op = (raw >> 4) & 0x1; if (cond != b1111) { if ((op1 & b110) == b000) result = process_armv7_data_processing_and_miscellaneous_instructions(raw); else if (op1 == b010) result = process_armv7_load_store_word_and_unsigned_byte(raw); else if (op1 == b011) { if (op == b0) result = process_armv7_load_store_word_and_unsigned_byte(raw); else result = process_armv7_media_instructions(raw); } else if ((op1 & b110) == b100) result = process_armv7_branch_branch_with_link_and_block_data_transfer(raw); else if ((op1 & b110) == b110) result = process_armv7_coprocessor_instructions_and_Supervisor_call(raw); } else /* if (cond == b1111) */ result = process_armv7_unconditional_instructions(raw); return result; } /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 de données ou autre. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GArchInstruction *process_armv7_data_processing_and_miscellaneous_instructions(uint32_t raw) { GArchInstruction *result; /* Instruction à retourner */ uint32_t op; /* Champ 'op' à retrouver */ uint32_t op1; /* Champ 'op1' à retrouver */ uint32_t op2; /* Champ 'op2' à retrouver */ /** * Suit les directives de : * § A5.2 Data-processing and miscellaneous instructions */ result = NULL; op = (raw >> 25) & 0x1; op1 = (raw >> 20) & 0x1f; op2 = (raw >> 4) & 0xf; if (op == b0) { if ((op1 & b11001) != b10000) { if ((op2 & b0001) == b0000) result = process_armv7_data_processing_register(raw); else if ((op2 & b1001) == b0001) result = process_armv7_data_processing_register_shifted_register(raw); if (result != NULL) goto padpami_found; } else /* if ((op1 & b11001) == b10000) */ { if ((op2 & b1000) == b0000) result = process_armv7_miscellaneous_instructions(raw); else if ((op2 & b1001) == b1000) result = process_armv7_halfword_multiply_and_multiply_accumulate(raw); if (result != NULL) goto padpami_found; } if ((op1 & b10000) == b00000) { if (op2 == b1001) result = process_armv7_multiply_and_multiply_accumulate(raw); if (result != NULL) goto padpami_found; } if ((op1 & b10000) == b10000) { if (op2 == b1001) result = process_armv7_synchronization_primitives(raw); if (result != NULL) goto padpami_found; } if ((op1 & b10010) != b00010) { if (op2 == b1011) result = process_armv7_extra_load_store_instructions(raw); else if ((op2 & b1101) == b1101) result = process_armv7_extra_load_store_instructions(raw); if (result != NULL) goto padpami_found; } else /* if ((op1 & b10010) != b00010) */ { if (op2 == b1011) result = process_armv7_extra_load_store_instructions_unprivileged(raw); else if ((op2 & b1101) == b1101) result = process_armv7_extra_load_store_instructions(raw); if (result != NULL) goto padpami_found; } } else { if ((op1 & b11001) != b10000) result = process_armv7_data_processing_immediate(raw); else if (op1 == b10000) result = armv7_read_instr_mov_immediate(raw); else if (op1 == b10100) result = armv7_read_instr_movt(raw); else if ((op1 & b11011) == b10010) result = process_armv7_msr_immediate_and_hints(raw); } padpami_found: return result; } /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 de données de registre. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GArchInstruction *process_armv7_data_processing_register(uint32_t raw) { GArchInstruction *result; /* Instruction à retourner */ uint32_t op; /* Champ 'op' à retrouver */ uint32_t imm5; /* Champ 'imm5' à retrouver */ uint32_t op2; /* Champ 'op2' à retrouver */ /** * Suit les directives de : * § A5.2.1 Data-processing (register) */ result = NULL; op = (raw >> 20) & 0x1f; imm5 = (raw >> 7) & 0x1f; op2 = (raw >> 5) & 0x3; if ((op & b11110) == b00000) result = armv7_read_instr_and_register(raw); else if ((op & b11110) == b00010) result = armv7_read_instr_eor_register(raw); else if ((op & b11110) == b00100) result = armv7_read_instr_sub_register(raw); else if ((op & b11110) == b00110) result = armv7_read_instr_rsb_register(raw); else if ((op & b11110) == b01000) result = armv7_read_instr_add_register_arm(raw); else if ((op & b11110) == b01010) result = armv7_read_instr_adc_register(raw); else if ((op & b11110) == b01100) result = armv7_read_instr_sbc_register(raw); else if ((op & b11110) == b01110) result = armv7_read_instr_rsc_register(raw); /* else if ((op & b11001) == b10000) result = process_armv7_data_processing_and_miscellaneous_instructions(raw); */ else if (op == b10001) result = armv7_read_instr_tst_register(raw); else if (op == b10011) result = armv7_read_instr_teq_register(raw); else if (op == b10101) result = armv7_read_instr_cmp_register(raw); else if (op == b10111) result = armv7_read_instr_cmn_register(raw); else if ((op & b11110) == b11000) result = armv7_read_instr_orr_register(raw); else if ((op & b11110) == b11010) { if (op2 == b00) { if (imm5 == b00000) result = armv7_read_instr_mov_register_arm(raw); else result = armv7_read_instr_lsl_immediate(raw); } else if (op2 == b01) result = armv7_read_instr_lsr_immediate(raw); else if (op2 == b10) result = armv7_read_instr_asr_immediate(raw); else if (op2 == b11) { if (imm5 == b00000) result = armv7_read_instr_rrx(raw); else result = armv7_read_instr_ror_immediate(raw); } } else if ((op & b11110) == b11100) result = armv7_read_instr_bic_register(raw); else if ((op & b11110) == b11110) result = armv7_read_instr_mvn_register(raw); return result; } /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 de données de immédiate. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GArchInstruction *process_armv7_data_processing_immediate(uint32_t raw) { GArchInstruction *result; /* Instruction à retourner */ uint32_t op; /* Champ 'op' à retrouver */ uint32_t rn; /* Champ 'rn' à retrouver */ /** * Suit les directives de : * § A5.2.3 Data-processing (immediate) */ result = NULL; op = (raw >> 20) & 0x1f; rn = (raw >> 16) & 0xf; if ((op & b11110) == b00000) result = armv7_read_instr_and_immediate(raw); else if ((op & b11110) == b00010) result = armv7_read_instr_eor_immediate(raw); else if ((op & b11110) == b00100) { if (rn == b1111) result = armv7_read_instr_adr(raw); else result = armv7_read_instr_sub_immediate_arm(raw); } else if ((op & b11110) == b00110) result = armv7_read_instr_rsb_immediate(raw); else if ((op & b11110) == b01000) { if (rn == b1111) result = armv7_read_instr_adr(raw); else result = armv7_read_instr_add_immediate_arm(raw); } else if ((op & b11110) == b01010) result = armv7_read_instr_adc_immediate(raw); else if ((op & b11110) == b01100) result = armv7_read_instr_sbc_immediate(raw); else if ((op & b11110) == b01110) result = armv7_read_instr_rsc_immediate(raw); /* else if ((op & b11110) == b10000) result = process_armv7_data_processing_and_miscellaneous_instructions(raw); */ else if (op == b10001) result = armv7_read_instr_tst_immediate(raw); else if (op == b10011) result = armv7_read_instr_teq_immediate(raw); else if (op == b10101) result = armv7_read_instr_cmp_immediate(raw); else if (op == b10111) result = armv7_read_instr_cmn_immediate(raw); else if ((op & b11110) == b11000) result = armv7_read_instr_orr_immediate(raw); else if ((op & b11110) == b11010) result = armv7_read_instr_mov_immediate(raw); else if ((op & b11110) == b11100) result = armv7_read_instr_bic_immediate(raw); else if ((op & b11110) == b11110) result = armv7_read_instr_mvn_immediate(raw); return result; } /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 liées aux multiplications. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GArchInstruction *process_armv7_multiply_and_multiply_accumulate(uint32_t raw) { GArchInstruction *result; /* Instruction à retourner */ uint32_t op; /* Champ 'op' à retrouver */ /** * Suit les directives de : * § A5.2.5 Multiply and multiply accumulate */ result = NULL; if ((raw & 0x0f0000f0) == 0x00000090) return NULL; op = (raw >> 20) & 0x1f; if ((op & b1110) == b0000) result = armv7_read_instr_mul(raw); else if ((op & b1110) == b0010) result = armv7_read_instr_mla(raw); else if (op == b0100) result = armv7_read_instr_umaal(raw); else if (op == b0101) result = NULL; /* Non défini */ else if (op == b0110) result = armv7_read_instr_mls(raw); else if (op == b0111) result = NULL; /* Non défini */ else if ((op & b1110) == b1000) result = armv7_read_instr_umull(raw); else if ((op & b1110) == b1010) result = armv7_read_instr_umlal(raw); else if ((op & b1110) == b1100) result = armv7_read_instr_smull(raw); else if ((op & b1110) == b1110) result = armv7_read_instr_smlal(raw); return result; } /****************************************************************************** * * * Paramètres : raw = donnée brute de 32 bits à désassembler. * * * * Description : Désassemble une instruction ARMv7 de données ou autre. * * * * Retour : Instruction mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GArchInstruction *process_armv7_branch_branch_with_link_and_block_data_transfer(uint32_t raw) { GArchInstruction *result; /* Instruction à retourner */ uint32_t op; /* Champ 'op' à retrouver */ uint32_t rn; /* Champ 'rn' à retrouver */ uint32_t r; /* Champ 'r' à retrouver */ /** * Suit les directives de : * § A5.5 Branch, branch with link, and block data transferr */ result = NULL; op = (raw >> 20) & 0x3f; rn = (raw >> 16) & 0xf; r = (raw >> 15) & 0x1; if ((op & b111101) == b000000) result = armv7_read_instr_stmda_stmed(raw); else if ((op & b111101) == b000001) result = armv7_read_instr_ldmda_ldmfa(raw); else if ((op & b111101) == b001000) result = armv7_read_instr_stm_stmia_stmea(raw); else if (op == b001001) result = armv7_read_instr_ldm_ldmia_ldmfd_arm(raw); else if (op == b001011) { if (rn != b1101) result = armv7_read_instr_ldm_ldmia_ldmfd_arm(raw); else /* if (rn == b1101) */ result = armv7_read_instr_pop_arm(raw); } else if (op == b010000) result = armv7_read_instr_stmdb_stmfd(raw); else if (op == b010010) { if (rn != b1101) result = armv7_read_instr_stmdb_stmfd(raw); else /* if (rn == b1101) */ result = armv7_read_instr_push(raw); } else if ((op & b111101) == b010001) result = armv7_read_instr_ldmdb_ldmea(raw); else if ((op & b111101) == b011000) result = armv7_read_instr_stmib_stmfa(raw); else if ((op & b111101) == b011001) result = armv7_read_instr_ldmib_ldmed(raw); else if ((op & b100101) == b000100) result = armv7_read_instr_stm_user_registers(raw); else if ((op & b100101) == b000101) { if (r == b0) result = armv7_read_instr_ldm_user_registers(raw); else /* if (r == b1) */ result = armv7_read_instr_ldm_exception_return(raw); } else if ((op & b110000) == b100000) result = armv7_read_instr_b(raw); else if ((op & b110000) == b110000) result = armv7_read_instr_bl_blx_immediate(raw); return result; }