1 /* 2 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 21 #define unlikely(cond) (cond) 22 #include "insn/insn.h" 23 #include "insn/inat.c" 24 #include "insn/insn.c" 25 26 #include "../../elf.h" 27 #include "../../arch.h" 28 #include "../../warn.h" 29 30 static int is_x86_64(struct elf *elf) 31 { 32 switch (elf->ehdr.e_machine) { 33 case EM_X86_64: 34 return 1; 35 case EM_386: 36 return 0; 37 default: 38 WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); 39 return -1; 40 } 41 } 42 43 int arch_decode_instruction(struct elf *elf, struct section *sec, 44 unsigned long offset, unsigned int maxlen, 45 unsigned int *len, unsigned char *type, 46 unsigned long *immediate) 47 { 48 struct insn insn; 49 int x86_64; 50 unsigned char op1, op2, ext; 51 52 x86_64 = is_x86_64(elf); 53 if (x86_64 == -1) 54 return -1; 55 56 insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); 57 insn_get_length(&insn); 58 insn_get_opcode(&insn); 59 insn_get_modrm(&insn); 60 insn_get_immediate(&insn); 61 62 if (!insn_complete(&insn)) { 63 WARN_FUNC("can't decode instruction", sec, offset); 64 return -1; 65 } 66 67 *len = insn.length; 68 *type = INSN_OTHER; 69 70 if (insn.vex_prefix.nbytes) 71 return 0; 72 73 op1 = insn.opcode.bytes[0]; 74 op2 = insn.opcode.bytes[1]; 75 76 switch (op1) { 77 case 0x55: 78 if (!insn.rex_prefix.nbytes) 79 /* push rbp */ 80 *type = INSN_FP_SAVE; 81 break; 82 83 case 0x5d: 84 if (!insn.rex_prefix.nbytes) 85 /* pop rbp */ 86 *type = INSN_FP_RESTORE; 87 break; 88 89 case 0x70 ... 0x7f: 90 *type = INSN_JUMP_CONDITIONAL; 91 break; 92 93 case 0x89: 94 if (insn.rex_prefix.nbytes == 1 && 95 insn.rex_prefix.bytes[0] == 0x48 && 96 insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) 97 /* mov rsp, rbp */ 98 *type = INSN_FP_SETUP; 99 break; 100 101 case 0x90: 102 *type = INSN_NOP; 103 break; 104 105 case 0x0f: 106 if (op2 >= 0x80 && op2 <= 0x8f) 107 *type = INSN_JUMP_CONDITIONAL; 108 else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || 109 op2 == 0x35) 110 /* sysenter, sysret */ 111 *type = INSN_CONTEXT_SWITCH; 112 else if (op2 == 0x0b || op2 == 0xb9) 113 /* ud2 */ 114 *type = INSN_BUG; 115 else if (op2 == 0x0d || op2 == 0x1f) 116 /* nopl/nopw */ 117 *type = INSN_NOP; 118 else if (op2 == 0x01 && insn.modrm.nbytes && 119 (insn.modrm.bytes[0] == 0xc2 || 120 insn.modrm.bytes[0] == 0xd8)) 121 /* vmlaunch, vmrun */ 122 *type = INSN_CONTEXT_SWITCH; 123 124 break; 125 126 case 0xc9: /* leave */ 127 *type = INSN_FP_RESTORE; 128 break; 129 130 case 0xe3: /* jecxz/jrcxz */ 131 *type = INSN_JUMP_CONDITIONAL; 132 break; 133 134 case 0xe9: 135 case 0xeb: 136 *type = INSN_JUMP_UNCONDITIONAL; 137 break; 138 139 case 0xc2: 140 case 0xc3: 141 *type = INSN_RETURN; 142 break; 143 144 case 0xc5: /* iret */ 145 case 0xca: /* retf */ 146 case 0xcb: /* retf */ 147 *type = INSN_CONTEXT_SWITCH; 148 break; 149 150 case 0xe8: 151 *type = INSN_CALL; 152 break; 153 154 case 0xff: 155 ext = X86_MODRM_REG(insn.modrm.bytes[0]); 156 if (ext == 2 || ext == 3) 157 *type = INSN_CALL_DYNAMIC; 158 else if (ext == 4) 159 *type = INSN_JUMP_DYNAMIC; 160 else if (ext == 5) /*jmpf */ 161 *type = INSN_CONTEXT_SWITCH; 162 163 break; 164 165 default: 166 break; 167 } 168 169 *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; 170 171 return 0; 172 } 173