blob: eeb6217ba583f34cf16521d92cc794e06e638089 [file] [log] [blame]
echotyh51c8c502016-10-10 15:16:56 +08001/* Tang Yuhang <1648200150@qq.com> 2016 */
2#include <stdio.h>
3#include <inttypes.h>
4#include <string.h>
5#include <ctype.h>
6#include <errno.h>
7
Nguyen Anh Quynh56649982016-10-11 00:04:46 +08008#include <capstone/capstone.h>
echotyh51c8c502016-10-10 15:16:56 +08009
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080010#define VERSION "1.0"
echotyh51c8c502016-10-10 15:16:56 +080011
YUHANG TANG9354e5e2016-10-14 17:29:56 +080012void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
YUHANG TANG08da0c02016-10-14 20:47:29 +080013void print_insn_detail_arm(csh handle, cs_insn *ins);
14void print_insn_detail_arm64(csh handle, cs_insn *ins);
15void print_insn_detail_mips(csh handle, cs_insn *ins);
16void print_insn_detail_ppc(csh handle, cs_insn *ins);
17void print_insn_detail_sparc(csh handle, cs_insn *ins);
18void print_insn_detail_sysz(csh handle, cs_insn *ins);
19void print_insn_detail_xcore(csh handle, cs_insn *ins);
YUHANG TANG9354e5e2016-10-14 17:29:56 +080020
echotyh51c8c502016-10-10 15:16:56 +080021// convert hexchar to hexnum
22static uint8_t char_to_hexnum(char c)
23{
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080024 if (c >= '0' && c <= '9') {
25 return (uint8_t)(c - '0');
26 }
27
28 if (c >= 'a' && c <= 'f') {
29 return (uint8_t)(10 + c - 'a');
30 }
31
32 // c >= 'A' && c <= 'F'
33 return (uint8_t)(10 + c - 'A');
echotyh51c8c502016-10-10 15:16:56 +080034}
35
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080036// convert user input (char[]) to uint8_t[], each element of which is
37// valid hexadecimal, and return actual length of uint8_t[] in @size.
echotyh51c8c502016-10-10 15:16:56 +080038static uint8_t *preprocess(char *code, size_t *size)
39{
Nguyen Anh Quynh74154672016-10-11 16:56:20 +080040 size_t i = 0, j = 0;
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080041 uint8_t high, low;
42 uint8_t *result;
echotyh51c8c502016-10-10 15:16:56 +080043
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080044 result = (uint8_t *)malloc(strlen(code));
45 if (result != NULL) {
46 while (code[i] != '\0') {
47 if (isxdigit(code[i]) && isxdigit(code[i+1])) {
48 high = 16 * char_to_hexnum(code[i]);
49 low = char_to_hexnum(code[i+1]);
50 result[j] = high + low;
51 i++;
52 j++;
53 }
54 i++;
55 }
56 *size = j;
57 }
58
59 return result;
echotyh51c8c502016-10-10 15:16:56 +080060}
61
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080062static void usage(char *prog)
echotyh51c8c502016-10-10 15:16:56 +080063{
Nguyen Anh Quynh130eb7e2016-10-11 23:21:12 +080064 printf("Cstool v%s for Capstone Disassembler Engine (www.capstone-engine.org)\n\n", VERSION);
YUHANG TANG9354e5e2016-10-14 17:29:56 +080065 printf("Syntax: %s [-d:print all debug information] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +080066 printf("\nThe following <arch+mode> options are supported:\n");
67
68 if (cs_support(CS_ARCH_X86)) {
69 printf(" x16: 16-bit mode (X86)\n");
70 printf(" x32: 32-bit mode (X86)\n");
71 printf(" x64: 64-bit mode (X86)\n");
72 printf(" x16att: 16-bit mode (X86) syntax-att\n");
73 printf(" x32att: 32-bit mode (X86) syntax-att\n");
74 printf(" x64att: 64-bit mode (X86) syntax-att\n");
75 }
76
77 if (cs_support(CS_ARCH_ARM)) {
78 printf(" arm: arm\n");
79 printf(" armb: arm + big endian\n");
80 printf(" arml: arm + little endian\n");
81 printf(" thumb: thumb mode\n");
82 printf(" thumbbe: thumb + big endian\n");
83 printf(" thumble: thumb + billtle endian\n");
84 }
85
86 if (cs_support(CS_ARCH_ARM64)) {
87 printf(" arm64: aarch64 mode\n");
88 }
89
90 if (cs_support(CS_ARCH_MIPS)) {
91 printf(" mips: mips32 + little endian\n");
92 printf(" mipsbe: mips32 + big endian\n");
93 printf(" mips64: mips64 + little endian\n");
94 printf(" mips64be: mips64 + big endian\n");
95 }
96
97 if (cs_support(CS_ARCH_PPC)) {
98 printf(" ppc64: ppc64 + little endian\n");
99 printf(" ppc64be: ppc64 + big endian\n");
100 }
101
102 if (cs_support(CS_ARCH_SPARC)) {
103 printf(" sparc: sparc\n");
104 }
105
106 if (cs_support(CS_ARCH_SYSZ)) {
107 printf(" systemz: systemz (s390x)\n");
108 }
109
110 if (cs_support(CS_ARCH_XCORE)) {
111 printf(" xcore: xcore\n");
112 }
113
114 printf("\n");
echotyh51c8c502016-10-10 15:16:56 +0800115}
116
117int main(int argc, char **argv)
118{
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800119 csh handle;
120 char *mode;
121 uint8_t *assembly;
122 size_t count, size;
123 uint64_t address = 0;
124 cs_insn *insn;
125 cs_err err;
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800126 cs_mode md;
YUHANG TANG08da0c02016-10-14 20:47:29 +0800127 char *arch;
128 bool debug_flag = false;
echotyh51c8c502016-10-10 15:16:56 +0800129
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800130 if (argc != 3 && argc != 4 && argc != 5) {
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800131 usage(argv[0]);
132 return -1;
133 }
echotyh51c8c502016-10-10 15:16:56 +0800134
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800135 if (!strcmp(argv[1], "-d")) {
136 if (argc == 3) {
137 usage(argv[0]);
138 return -1;
139 }
140 debug_flag = true;
141 mode = argv[2];
142 assembly = preprocess(argv[3], &size);
143 if (argc == 5) {
144 char *temp;
145 address = strtoull(argv[4], &temp, 16);
146 if (temp == argv[4] || *temp != '\0' || errno == ERANGE) {
147 printf("ERROR: invalid address argument, quit!\n");
148 return -2;
149 }
150 }
151 } else {
152 if (argc == 5) {
153 usage(argv[0]);
154 return -1;
155 }
156
157 mode = argv[1];
158 assembly = preprocess(argv[2], &size);
159 if (assembly == NULL) {
160 printf("ERROR: invalid assembler-string argument, quit!\n");
161 return -3;
162 }
163
164 if (argc == 4) {
165 // cstool <arch> <assembly> <address>
166 char *temp;
167 address = strtoull(argv[3], &temp, 16);
168 if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
169 printf("ERROR: invalid address argument, quit!\n");
170 return -2;
171 }
172 }
173 }
174
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800175 if (!strcmp(mode, "arm")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800176 arch = "arm";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800177 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle);
178 }
179
180 if (!strcmp(mode, "armb")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800181 arch = "arm";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800182 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_BIG_ENDIAN, &handle);
183 }
184
185 if (!strcmp(mode, "arml")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800186 arch = "arm";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800187 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
188 }
189
190 if (!strcmp(mode, "thumb")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800191 arch = "arm";
192 err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN, &handle);
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800193 }
194
195 if (!strcmp(mode, "thumbbe")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800196 arch = "arm";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800197 err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_BIG_ENDIAN, &handle);
198 }
199
200 if (!strcmp(mode, "thumble")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800201 arch = "arm";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800202 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
203 }
204
205 if (!strcmp(mode, "arm64")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800206 arch = "arm64";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800207 err = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle);
208 }
209
210 if (!strcmp(mode, "mips")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800211 arch = "mips";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800212 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN, &handle);
213 }
214
215 if (!strcmp(mode, "mipsbe")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800216 arch = "mips";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800217 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN, &handle);
218 }
219
220 if (!strcmp(mode, "mips64")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800221 arch = "mips";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800222 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
223 }
224
225 if (!strcmp(mode, "mips64be")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800226 arch = "mips";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800227 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
228 }
229
230 if (!strcmp(mode, "x16")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800231 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800232 err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
233 }
234
235 if (!strcmp(mode, "x32")) {
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800236 md = CS_MODE_32;
YUHANG TANG08da0c02016-10-14 20:47:29 +0800237 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800238 err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
239 }
240
241 if (!strcmp(mode, "x64")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800242 md = CS_MODE_64;
243 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800244 err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
245 }
246
247 if (!strcmp(mode, "x16att")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800248 md = CS_MODE_16;
249 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800250 err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
251 if (!err) {
252 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
253 }
254 }
255
256 if (!strcmp(mode,"x32att")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800257 md = CS_MODE_32;
258 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800259 err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
260 if (!err) {
261 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
262 }
263 }
264
265 if (!strcmp(mode,"x64att")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800266 md = CS_MODE_64;
267 arch = "x86";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800268 err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
269 if (!err) {
270 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
271 }
272 }
273
274 if (!strcmp(mode,"ppc64")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800275 arch = "ppc";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800276 err = cs_open(CS_ARCH_PPC, CS_MODE_64+CS_MODE_LITTLE_ENDIAN, &handle);
277 }
278
279 if (!strcmp(mode,"ppc64be")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800280 arch = "ppc";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800281 err = cs_open(CS_ARCH_PPC,CS_MODE_64+CS_MODE_BIG_ENDIAN, &handle);
282 }
283
284 if (!strcmp(mode,"sparc")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800285 arch = "sparc";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800286 err = cs_open(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, &handle);
287 }
288
289 if (!strcmp(mode, "systemz") || !strcmp(mode, "sysz") || !strcmp(mode, "s390x")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800290 arch = "sysz";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800291 err = cs_open(CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN, &handle);
292 }
293
294 if (!strcmp(mode,"xcore")) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800295 arch = "xcore";
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800296 err = cs_open(CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN, &handle);
297 }
298
299 if (err) {
300 printf("ERROR: Failed on cs_open(), quit!\n");
301 usage(argv[0]);
302 return -1;
303 }
304
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800305 if (debug_flag) {
306 cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
307 }
308
309 count = cs_disasm(handle, assembly, size, address, 0, &insn);
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800310 if (count > 0) {
Nguyen Anh Quynhbab2a932016-10-11 16:19:27 +0800311 size_t i;
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800312
Nguyen Anh Quynhbab2a932016-10-11 16:19:27 +0800313 for (i = 0; i < count; i++) {
314 int j;
315 printf("%"PRIx64" ", insn[i].address);
316 for (j = 0; j < insn[i].size; j++) {
317 printf("%02x", insn[i].bytes[j]);
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800318 }
Nguyen Anh Quynhbab2a932016-10-11 16:19:27 +0800319 // X86 instruction size is variable.
320 // align assembly instruction after the opcode
YUHANG TANG08da0c02016-10-14 20:47:29 +0800321 if (!strcmp(arch, "x86")) {
Nguyen Anh Quynhbab2a932016-10-11 16:19:27 +0800322 for (; j < 16; j++) {
323 printf(" ");
324 }
325 }
326 printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
YUHANG TANGad257422016-10-16 16:56:55 +0800327 if (debug_flag) {
YUHANG TANG08da0c02016-10-14 20:47:29 +0800328 if (!strcmp(arch, "x86")) {
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800329 print_insn_detail_x86(handle, md, &insn[i]);
330 }
YUHANG TANG08da0c02016-10-14 20:47:29 +0800331
332 if (!strcmp(arch, "arm")) {
333 print_insn_detail_arm(handle, &insn[i]);
334 }
335
336 if (!strcmp(arch,"arm64")) {
337 print_insn_detail_arm64(handle,&insn[i]);
338 }
339
340 if (!strcmp(arch, "mips")) {
341 print_insn_detail_mips(handle, &insn[i]);
342 }
343
344 if (!strcmp(arch, "ppc")) {
345 print_insn_detail_ppc(handle, &insn[i]);
346 }
347
348 if (!strcmp(arch, "sparc")) {
349 print_insn_detail_sparc(handle, &insn[i]);
350 }
351
352 if (!strcmp(arch, "sysz")) {
353 print_insn_detail_sysz(handle, &insn[i]);
354 }
355
356 if (!strcmp(arch, "xcore")) {
357 print_insn_detail_xcore(handle, &insn[i]);
358 }
YUHANG TANG9354e5e2016-10-14 17:29:56 +0800359 }
Nguyen Anh Quynh815b94a2016-10-10 23:20:29 +0800360 }
361 cs_free(insn, count);
362 } else {
363 printf("ERROR: invalid assembly code\n");
364 return(-4);
365 }
366
367 cs_close(&handle);
368
369 return 0;
echotyh51c8c502016-10-10 15:16:56 +0800370}
371
372