YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | |
Nguyen Anh Quynh | 2897a80 | 2016-10-21 17:03:27 +0800 | [diff] [blame] | 4 | #include <capstone/capstone.h> |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 5 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 6 | void print_string_hex(char *comment, unsigned char *str, size_t len); |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 7 | |
| 8 | void print_insn_detail_arm(csh handle, cs_insn *ins) |
| 9 | { |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 10 | cs_arm *arm; |
| 11 | int i; |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 12 | cs_regs regs_read, regs_write; |
| 13 | uint8_t regs_read_count, regs_write_count; |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 14 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 15 | // detail can be NULL on "data" instruction if SKIPDATA option is turned ON |
| 16 | if (ins->detail == NULL) |
| 17 | return; |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 18 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 19 | arm = &(ins->detail->arm); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 20 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 21 | if (arm->op_count) |
| 22 | printf("\top_count: %u\n", arm->op_count); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 23 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 24 | for (i = 0; i < arm->op_count; i++) { |
| 25 | cs_arm_op *op = &(arm->operands[i]); |
| 26 | switch((int)op->type) { |
| 27 | default: |
| 28 | break; |
| 29 | case ARM_OP_REG: |
| 30 | printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); |
| 31 | break; |
| 32 | case ARM_OP_IMM: |
| 33 | printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); |
| 34 | break; |
| 35 | case ARM_OP_FP: |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 36 | #if defined(_KERNEL_MODE) |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 37 | // Issue #681: Windows kernel does not support formatting float point |
| 38 | printf("\t\toperands[%u].type: FP = <float_point_unsupported>\n", i); |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 39 | #else |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 40 | printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 41 | #endif |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 42 | break; |
| 43 | case ARM_OP_MEM: |
| 44 | printf("\t\toperands[%u].type: MEM\n", i); |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 45 | if (op->mem.base != ARM_REG_INVALID) |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 46 | printf("\t\t\toperands[%u].mem.base: REG = %s\n", |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 47 | i, cs_reg_name(handle, op->mem.base)); |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 48 | if (op->mem.index != ARM_REG_INVALID) |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 49 | printf("\t\t\toperands[%u].mem.index: REG = %s\n", |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 50 | i, cs_reg_name(handle, op->mem.index)); |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 51 | if (op->mem.scale != 1) |
| 52 | printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale); |
| 53 | if (op->mem.disp != 0) |
| 54 | printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 55 | if (op->mem.lshift != 0) |
| 56 | printf("\t\t\toperands[%u].mem.lshift: 0x%x\n", i, op->mem.lshift); |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 57 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 58 | break; |
| 59 | case ARM_OP_PIMM: |
| 60 | printf("\t\toperands[%u].type: P-IMM = %u\n", i, op->imm); |
| 61 | break; |
| 62 | case ARM_OP_CIMM: |
| 63 | printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm); |
| 64 | break; |
| 65 | case ARM_OP_SETEND: |
| 66 | printf("\t\toperands[%u].type: SETEND = %s\n", i, op->setend == ARM_SETEND_BE? "be" : "le"); |
| 67 | break; |
| 68 | case ARM_OP_SYSREG: |
| 69 | printf("\t\toperands[%u].type: SYSREG = %u\n", i, op->reg); |
| 70 | break; |
| 71 | } |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 72 | |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 73 | if (op->neon_lane != -1) { |
| 74 | printf("\t\toperands[%u].neon_lane = %u\n", i, op->neon_lane); |
| 75 | } |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 76 | |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 77 | switch(op->access) { |
| 78 | default: |
| 79 | break; |
| 80 | case CS_AC_READ: |
| 81 | printf("\t\toperands[%u].access: READ\n", i); |
| 82 | break; |
| 83 | case CS_AC_WRITE: |
| 84 | printf("\t\toperands[%u].access: WRITE\n", i); |
| 85 | break; |
| 86 | case CS_AC_READ | CS_AC_WRITE: |
| 87 | printf("\t\toperands[%u].access: READ | WRITE\n", i); |
| 88 | break; |
| 89 | } |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 90 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 91 | if (op->shift.type != ARM_SFT_INVALID && op->shift.value) { |
| 92 | if (op->shift.type < ARM_SFT_ASR_REG) |
| 93 | // shift with constant value |
| 94 | printf("\t\t\tShift: %u = %u\n", op->shift.type, op->shift.value); |
| 95 | else |
| 96 | // shift with register |
| 97 | printf("\t\t\tShift: %u = %s\n", op->shift.type, |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 98 | cs_reg_name(handle, op->shift.value)); |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 99 | } |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 100 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 101 | if (op->vector_index != -1) { |
| 102 | printf("\t\toperands[%u].vector_index = %u\n", i, op->vector_index); |
| 103 | } |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 104 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 105 | if (op->subtracted) |
| 106 | printf("\t\tSubtracted: True\n"); |
| 107 | } |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 108 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 109 | if (arm->cc != ARM_CC_AL && arm->cc != ARM_CC_INVALID) |
| 110 | printf("\tCode condition: %u\n", arm->cc); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 111 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 112 | if (arm->update_flags) |
| 113 | printf("\tUpdate-flags: True\n"); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 114 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 115 | if (arm->writeback) |
| 116 | printf("\tWrite-back: True\n"); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 117 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 118 | if (arm->cps_mode) |
| 119 | printf("\tCPSI-mode: %u\n", arm->cps_mode); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 120 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 121 | if (arm->cps_flag) |
| 122 | printf("\tCPSI-flag: %u\n", arm->cps_flag); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 123 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 124 | if (arm->vector_data) |
| 125 | printf("\tVector-data: %u\n", arm->vector_data); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 126 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 127 | if (arm->vector_size) |
| 128 | printf("\tVector-size: %u\n", arm->vector_size); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 129 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 130 | if (arm->usermode) |
| 131 | printf("\tUser-mode: True\n"); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 132 | |
Nguyen Anh Quynh | 32238dc | 2016-10-21 16:42:47 +0800 | [diff] [blame] | 133 | if (arm->mem_barrier) |
| 134 | printf("\tMemory-barrier: %u\n", arm->mem_barrier); |
YUHANG TANG | 9bc14c1 | 2016-10-28 15:32:50 +0800 | [diff] [blame] | 135 | |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 136 | // Print out all registers accessed by this instruction (either implicit or explicit) |
| 137 | if (!cs_regs_access(handle, ins, |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 138 | regs_read, ®s_read_count, |
| 139 | regs_write, ®s_write_count)) { |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 140 | if (regs_read_count) { |
| 141 | printf("\tRegisters read:"); |
| 142 | for(i = 0; i < regs_read_count; i++) { |
| 143 | printf(" %s", cs_reg_name(handle, regs_read[i])); |
| 144 | } |
| 145 | printf("\n"); |
| 146 | } |
Nguyen Anh Quynh | df6f9cc | 2016-10-28 16:12:05 +0800 | [diff] [blame] | 147 | |
YUHANG TANG | be3f867 | 2016-10-27 12:12:59 +0800 | [diff] [blame] | 148 | if (regs_write_count) { |
| 149 | printf("\tRegisters modified:"); |
| 150 | for(i = 0; i < regs_write_count; i++) { |
| 151 | printf(" %s", cs_reg_name(handle, regs_write[i])); |
| 152 | } |
| 153 | printf("\n"); |
| 154 | } |
| 155 | } |
YUHANG TANG | 08da0c0 | 2016-10-14 20:47:29 +0800 | [diff] [blame] | 156 | } |