decode.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. #include <stdio.h>
  18. #include <stdlib.h>
  19. #define unlikely(cond) (cond)
  20. #include "insn/insn.h"
  21. #include "insn/inat.c"
  22. #include "insn/insn.c"
  23. #include "../../elf.h"
  24. #include "../../arch.h"
  25. #include "../../warn.h"
  26. static int is_x86_64(struct elf *elf)
  27. {
  28. switch (elf->ehdr.e_machine) {
  29. case EM_X86_64:
  30. return 1;
  31. case EM_386:
  32. return 0;
  33. default:
  34. WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
  35. return -1;
  36. }
  37. }
  38. int arch_decode_instruction(struct elf *elf, struct section *sec,
  39. unsigned long offset, unsigned int maxlen,
  40. unsigned int *len, unsigned char *type,
  41. unsigned long *immediate)
  42. {
  43. struct insn insn;
  44. int x86_64;
  45. unsigned char op1, op2, ext;
  46. x86_64 = is_x86_64(elf);
  47. if (x86_64 == -1)
  48. return -1;
  49. insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64);
  50. insn_get_length(&insn);
  51. insn_get_opcode(&insn);
  52. insn_get_modrm(&insn);
  53. insn_get_immediate(&insn);
  54. if (!insn_complete(&insn)) {
  55. WARN_FUNC("can't decode instruction", sec, offset);
  56. return -1;
  57. }
  58. *len = insn.length;
  59. *type = INSN_OTHER;
  60. if (insn.vex_prefix.nbytes)
  61. return 0;
  62. op1 = insn.opcode.bytes[0];
  63. op2 = insn.opcode.bytes[1];
  64. switch (op1) {
  65. case 0x55:
  66. if (!insn.rex_prefix.nbytes)
  67. /* push rbp */
  68. *type = INSN_FP_SAVE;
  69. break;
  70. case 0x5d:
  71. if (!insn.rex_prefix.nbytes)
  72. /* pop rbp */
  73. *type = INSN_FP_RESTORE;
  74. break;
  75. case 0x70 ... 0x7f:
  76. *type = INSN_JUMP_CONDITIONAL;
  77. break;
  78. case 0x89:
  79. if (insn.rex_prefix.nbytes == 1 &&
  80. insn.rex_prefix.bytes[0] == 0x48 &&
  81. insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5)
  82. /* mov rsp, rbp */
  83. *type = INSN_FP_SETUP;
  84. break;
  85. case 0x8d:
  86. if (insn.rex_prefix.nbytes &&
  87. insn.rex_prefix.bytes[0] == 0x48 &&
  88. insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c &&
  89. insn.sib.nbytes && insn.sib.bytes[0] == 0x24)
  90. /* lea %(rsp), %rbp */
  91. *type = INSN_FP_SETUP;
  92. break;
  93. case 0x90:
  94. *type = INSN_NOP;
  95. break;
  96. case 0x0f:
  97. if (op2 >= 0x80 && op2 <= 0x8f)
  98. *type = INSN_JUMP_CONDITIONAL;
  99. else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
  100. op2 == 0x35)
  101. /* sysenter, sysret */
  102. *type = INSN_CONTEXT_SWITCH;
  103. else if (op2 == 0x0b || op2 == 0xb9)
  104. /* ud2 */
  105. *type = INSN_BUG;
  106. else if (op2 == 0x0d || op2 == 0x1f)
  107. /* nopl/nopw */
  108. *type = INSN_NOP;
  109. else if (op2 == 0x01 && insn.modrm.nbytes &&
  110. (insn.modrm.bytes[0] == 0xc2 ||
  111. insn.modrm.bytes[0] == 0xd8))
  112. /* vmlaunch, vmrun */
  113. *type = INSN_CONTEXT_SWITCH;
  114. break;
  115. case 0xc9: /* leave */
  116. *type = INSN_FP_RESTORE;
  117. break;
  118. case 0xe3: /* jecxz/jrcxz */
  119. *type = INSN_JUMP_CONDITIONAL;
  120. break;
  121. case 0xe9:
  122. case 0xeb:
  123. *type = INSN_JUMP_UNCONDITIONAL;
  124. break;
  125. case 0xc2:
  126. case 0xc3:
  127. *type = INSN_RETURN;
  128. break;
  129. case 0xca: /* retf */
  130. case 0xcb: /* retf */
  131. case 0xcf: /* iret */
  132. *type = INSN_CONTEXT_SWITCH;
  133. break;
  134. case 0xe8:
  135. *type = INSN_CALL;
  136. break;
  137. case 0xff:
  138. ext = X86_MODRM_REG(insn.modrm.bytes[0]);
  139. if (ext == 2 || ext == 3)
  140. *type = INSN_CALL_DYNAMIC;
  141. else if (ext == 4)
  142. *type = INSN_JUMP_DYNAMIC;
  143. else if (ext == 5) /*jmpf */
  144. *type = INSN_CONTEXT_SWITCH;
  145. break;
  146. default:
  147. break;
  148. }
  149. *immediate = insn.immediate.nbytes ? insn.immediate.value : 0;
  150. return 0;
  151. }