diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 19:50:13 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 20:34:34 -0500 |
| commit | e093c21ed880ac3eb72119be15093ee04f8ce299 (patch) | |
| tree | 9f720ebdc0ae415734b1199ed341668c69710a94 /arch/powerpc/test_disasm.cpp | |
| parent | 0609276712622908254065546102381466033141 (diff) | |
Move architecture modules into the API repo
Diffstat (limited to 'arch/powerpc/test_disasm.cpp')
| -rw-r--r-- | arch/powerpc/test_disasm.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp new file mode 100644 index 00000000..b893d2ab --- /dev/null +++ b/arch/powerpc/test_disasm.cpp @@ -0,0 +1,201 @@ +/****************************************************************************** + +Tests just the disassembler part (NOT the architecture plugin). + +Provide command line arguments for different cool tests. +Like `./test repl` to get an interactive disassembler +Like `./test speed` to get a timed test of instruction decomposition + +g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp disassembler.cpp -o test_disasm -lcapstone + +******************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> + +#include "disassembler.h" + +int print_errors = 1; + +int disas_instr_word(uint32_t instr_word, char *buf) +{ + int rc = -1; + + struct decomp_result res; + struct cs_insn *insn = &(res.insn); + struct cs_detail *detail = &(res.detail); + struct cs_ppc *ppc = &(detail->ppc); + + if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, true, &res)) { + if(print_errors) printf("ERROR: powerpc_decompose()\n"); + goto cleanup; + } + + /* MEGA DETAILS, IF YOU WANT 'EM */ + if(0) { + /* LEVEL1: id, address, size, bytes, mnemonic, op_str */ + printf("instruction id: %d\n", res.insn.id); + + /* LEVEL2: regs_read, regs_write, groups */ + printf(" regs read:"); + for(int j=0; j<detail->regs_read_count; ++j) { + printf(" %s", cs_reg_name(res.handle, detail->regs_read[j])); + } + printf("\n"); + printf(" regs write:"); + for(int j=0; j<detail->regs_write_count; ++j) { + printf(" %s", cs_reg_name(res.handle, detail->regs_write[j])); + } + printf("\n"); + printf(" groups:"); + for(int j=0; j<detail->groups_count; ++j) { + int group = detail->groups[j]; + printf(" %d(%s)", group, cs_group_name(res.handle, group)); + } + printf("\n"); + + /* LEVEL3: branch code, branch hint, update_cr0, operands */ + if(1 /* branch instruction */) { + printf(" branch code: %d\n", ppc->bc); // PPC_BC_LT, PPC_BC_LE, etc. + printf(" branch hint: %d\n", ppc->bh); // PPC_BH_PLUS, PPC_BH_MINUS + } + + printf(" update_cr0: %d\n", ppc->update_cr0); + + for(int j=0; j<ppc->op_count; ++j) { + printf(" operand%d: ", j); + + // .op_count is number of operands + // .operands[] is array of cs_ppc_op + cs_ppc_op op = ppc->operands[j]; + + switch(op.type) { + case PPC_OP_INVALID: + printf("invalid\n"); + break; + case PPC_OP_REG: + printf("reg: %s\n", cs_reg_name(res.handle, op.reg)); + break; + case PPC_OP_IMM: + printf("imm: 0x%X\n", op.imm); + break; + case PPC_OP_MEM: + printf("mem (%s + %d)\n", cs_reg_name(res.handle, op.mem.base), + op.mem.disp); + break; + case PPC_OP_CRX: + printf("crx (scale:%d, reg:%s)\n", op.crx.scale, + cs_reg_name(res.handle, op.crx.reg)); + break; + default: + printf("unknown (%d)\n", op.type); + break; + } + } + } + + if(powerpc_disassemble(&res, buf, 128)) { + if(print_errors) printf("ERROR: powerpc_disassemble()\n"); + goto cleanup; + } + + rc = 0; + cleanup: + return rc; +} + +int main(int ac, char **av) +{ + int rc = -1; + char buf[256]; + + #define BATCH 10000000 + + powerpc_init(); + + if(ac <= 1) { + printf("send argument \"repl\" or \"speed\"\n"); + goto cleanup; + } + + if(!strcasecmp(av[1], "repl")) { + printf("REPL mode!\n"); + printf("example inputs (write the words as if after endian fetch):\n"); + printf("93e1fffc\n"); + printf("9421ffe0\n"); + printf("7c3fb380\n"); + printf("38a00000\n"); + while(1) { + printf("disassemble> "); + + /* get line */ + if(NULL == fgets(buf, sizeof(buf), stdin)) { + printf("ERROR: fgets()\n"); + continue; + } + + uint32_t instr_word = strtoul(buf, NULL, 16); + //printf("instruction word: %08X\n", instr_word); + + /* convert to string */ + if(disas_instr_word(instr_word, buf)) { + printf("ERROR: disas_instr_word()\n"); + continue; + } + + printf("%s\n", buf); + } + } + else if(!strcasecmp(av[1], "speed")) { + printf("SPEED TEST THAT COUNTS QUICK RETURNS FROM BAD INSTRUCTIONS AS DISASSEMBLED\n"); + print_errors = 0; + uint32_t instr_word = 0x780b3f7c; + + while(1) { + clock_t t0 = clock(); + + for(int i=0; i<BATCH; ++i) { + disas_instr_word(instr_word, buf); + //printf("%08X: %s\n", instr_word, buf); + instr_word++; + } + + clock_t t1 = clock(); + double ellapsed = ((double)t1 - t0) / CLOCKS_PER_SEC; + printf("current rate: %f instructions per second\n", (float)BATCH/ellapsed); + } + } + else if(!strcasecmp(av[1], "speed2")) { + printf("SPEED TEST THAT IS GIVEN NO CREDIT FOR QUICK RETURNS FROM BAD INSTRUCTIONS\n"); + print_errors = 0; + uint32_t instr_word = 0x780b3f7c; + + while(1) { + clock_t t0 = clock(); + int ndisasms = 0; + + for(int i=0; i<BATCH; ++i) { + if(disas_instr_word(instr_word, buf) == 0) { + ndisasms++; + } + //printf("%08X: %s\n", instr_word, buf); + instr_word += 27; + } + + clock_t t1 = clock(); + double ellapsed = ((double)t1 - t0) / CLOCKS_PER_SEC; + printf("current rate: %f instructions per second\n", (float)ndisasms/ellapsed); + } + } + else { + printf("ERROR: dunno what to do with \"%s\"\n", av[1]); + goto cleanup; + } + + rc = 0; + cleanup: + return rc; +} + |
