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 0x8d: 102 if (insn.rex_prefix.nbytes && 103 insn.rex_prefix.bytes[0] == 0x48 && 104 insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && 105 insn.sib.nbytes && insn.sib.bytes[0] == 0x24) 106 /* lea %(rsp), %rbp */ 107 *type = INSN_FP_SETUP; 108 break; 109 110 case 0x90: 111 *type = INSN_NOP; 112 break; 113 114 case 0x0f: 115 if (op2 >= 0x80 && op2 <= 0x8f) 116 *type = INSN_JUMP_CONDITIONAL; 117 else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || 118 op2 == 0x35) 119 /* sysenter, sysret */ 120 *type = INSN_CONTEXT_SWITCH; 121 else if (op2 == 0x0d || op2 == 0x1f) 122 /* nopl/nopw */ 123 *type = INSN_NOP; 124 else if (op2 == 0x01 && insn.modrm.nbytes && 125 (insn.modrm.bytes[0] == 0xc2 || 126 insn.modrm.bytes[0] == 0xd8)) 127 /* vmlaunch, vmrun */ 128 *type = INSN_CONTEXT_SWITCH; 129 130 break; 131 132 case 0xc9: /* leave */ 133 *type = INSN_FP_RESTORE; 134 break; 135 136 case 0xe3: /* jecxz/jrcxz */ 137 *type = INSN_JUMP_CONDITIONAL; 138 break; 139 140 case 0xe9: 141 case 0xeb: 142 *type = INSN_JUMP_UNCONDITIONAL; 143 break; 144 145 case 0xc2: 146 case 0xc3: 147 *type = INSN_RETURN; 148 break; 149 150 case 0xca: /* retf */ 151 case 0xcb: /* retf */ 152 case 0xcf: /* iret */ 153 *type = INSN_CONTEXT_SWITCH; 154 break; 155 156 case 0xe8: 157 *type = INSN_CALL; 158 break; 159 160 case 0xff: 161 ext = X86_MODRM_REG(insn.modrm.bytes[0]); 162 if (ext == 2 || ext == 3) 163 *type = INSN_CALL_DYNAMIC; 164 else if (ext == 4) 165 *type = INSN_JUMP_DYNAMIC; 166 else if (ext == 5) /*jmpf */ 167 *type = INSN_CONTEXT_SWITCH; 168 169 break; 170 171 default: 172 break; 173 } 174 175 *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; 176 177 return 0; 178 } 179