summaryrefslogtreecommitdiff
path: root/arch/powerpc/test_disasm.cpp
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-03-05 19:50:13 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2024-03-05 20:34:34 -0500
commite093c21ed880ac3eb72119be15093ee04f8ce299 (patch)
tree9f720ebdc0ae415734b1199ed341668c69710a94 /arch/powerpc/test_disasm.cpp
parent0609276712622908254065546102381466033141 (diff)
Move architecture modules into the API repo
Diffstat (limited to 'arch/powerpc/test_disasm.cpp')
-rw-r--r--arch/powerpc/test_disasm.cpp201
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;
+}
+