summaryrefslogtreecommitdiff
path: root/arch/powerpc/disassembler.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/disassembler.cpp
parent0609276712622908254065546102381466033141 (diff)
Move architecture modules into the API repo
Diffstat (limited to 'arch/powerpc/disassembler.cpp')
-rw-r--r--arch/powerpc/disassembler.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp
new file mode 100644
index 00000000..66a8b36d
--- /dev/null
+++ b/arch/powerpc/disassembler.cpp
@@ -0,0 +1,185 @@
+/******************************************************************************
+
+See disassembler.h for more information about how this fits into the PPC
+architecture plugin picture.
+
+******************************************************************************/
+
+#include <string.h> // strcpy, etc.
+
+#define MYLOG(...) while(0);
+//#include <binaryninjaapi.h>
+//#define MYLOG BinaryNinja::LogDebug
+
+#include "disassembler.h"
+
+/* have to do this... while options can be toggled after initialization (thru
+ cs_option(), the modes cannot, and endianness is considered a mode) */
+thread_local csh handle_lil = 0;
+thread_local csh handle_big = 0;
+
+extern "C" int
+powerpc_init(void)
+{
+ int rc = -1;
+
+ MYLOG("powerpc_init()\n");
+
+ if(handle_lil || handle_big) {
+ MYLOG("ERROR: already initialized!\n");
+ goto cleanup;
+ }
+
+ /* initialize capstone handle */
+ if(cs_open(CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, &handle_big) != CS_ERR_OK) {
+ MYLOG("ERROR: cs_open()\n");
+ goto cleanup;
+ }
+
+ if(cs_open(CS_ARCH_PPC, CS_MODE_LITTLE_ENDIAN, &handle_lil) != CS_ERR_OK) {
+ MYLOG("ERROR: cs_open()\n");
+ goto cleanup;
+ }
+
+ cs_option(handle_big, CS_OPT_DETAIL, CS_OPT_ON);
+ cs_option(handle_lil, CS_OPT_DETAIL, CS_OPT_ON);
+
+ rc = 0;
+ cleanup:
+ if(rc) {
+ powerpc_release();
+ }
+
+ return rc;
+}
+
+extern "C" void
+powerpc_release(void)
+{
+ if(handle_lil) {
+ cs_close(&handle_lil);
+ handle_lil = 0;
+ }
+
+ if(handle_big) {
+ cs_close(&handle_big);
+ handle_big = 0;
+ }
+}
+
+extern "C" int
+powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end,
+ struct decomp_result *res)
+{
+ int rc = -1;
+ res->status = STATUS_ERROR_UNSPEC;
+
+ if(!handle_lil) {
+ powerpc_init();
+ }
+
+ //typedef struct cs_insn {
+ // unsigned int id; /* see capstone/ppc.h for PPC_INS_ADD, etc. */
+ // uint64_t address;
+ // uint16_t size;
+ // uint8_t bytes[16];
+ // char mnemonic[32]; /* string */
+ // char op_str[160]; /* string */
+ // cs_detail *detail; /* need CS_OP_DETAIL ON and CS_OP_SKIPDATA is OFF */
+ //} cs_insn;
+
+ // where cs_detail is some details + architecture specific part
+ // typedef struct cs_detail {
+ // uint8_t regs_read[12];
+ // uint8_t regs_read_count;
+ // uint8_t regs_write;
+ // uint8_t regs_write_count;
+ // uint8_t groups[8];
+ // uint8_t groups_count;
+ // cs_ppc *ppc;
+ // }
+
+ // and finally ppc is:
+ // typedef struct cs_ppc {
+ // ppc_bc bc; /* branch code, see capstone/ppc.h for PPC_BC_LT, etc. */
+ // ppc_bh bh; /* branch hint, see capstone/ppc.h for PPC_BH_PLUS, etc. */
+ // bool update_cr0;
+ // uint8_t op_count;
+ // cs_ppc_op operands[8];
+ // } cs_ppc;
+
+ // and each operand is:
+ // typedef struct cs_ppc_op {
+ // ppc_op_type type; /* see capstone/ppc.h for PPC_OP_REG, etc. */
+ // union {
+ // unsigned int reg; // register value for REG operand
+ // int32_t imm; // immediate value for IMM operand
+ // ppc_op_mem mem; // struct ppc_op_mem { uint base; int disp }
+ // ppc_op_crx crx; // struct ppc_op_crx { uint scale, uint reg }
+ // };
+ // } cs_ppc_op;
+
+ csh handle;
+ cs_insn *insn = 0; /* instruction information
+ cs_disasm() will allocate array of cs_insn here */
+
+ /* which handle to use?
+ BIG end or LITTLE end? */
+ handle = handle_big;
+ if(lil_end) handle = handle_lil;
+ res->handle = handle;
+
+ /* call */
+ size_t n = cs_disasm(handle, data, size, addr, 1, &insn);
+ if(n != 1) {
+ MYLOG("ERROR: cs_disasm() returned %" PRIdPTR " (cs_errno:%d)\n", n, cs_errno(handle));
+ goto cleanup;
+ }
+
+ /* set the status */
+ res->status = STATUS_SUCCESS;
+
+ /* copy the instruction struct, and detail sub struct to result */
+ memcpy(&(res->insn), insn, sizeof(cs_insn));
+ memcpy(&(res->detail), insn->detail, sizeof(cs_detail));
+
+ rc = 0;
+ cleanup:
+ if(insn) {
+ cs_free(insn, 1);
+ insn = 0;
+ }
+ return rc;
+}
+
+extern "C" int
+powerpc_disassemble(struct decomp_result *res, char *buf, size_t len)
+{
+ /* ideally the "heavy" string disassemble result is derived from light data
+ in the decomposition result, but capstone doesn't make this distinction */
+ int rc = -1;
+
+ if(len < strlen(res->insn.mnemonic)+strlen(res->insn.op_str) + 2) {
+ MYLOG("ERROR: insufficient room\n");
+ goto cleanup;
+ }
+
+ strcpy(buf, res->insn.mnemonic);
+ strcat(buf, " ");
+ strcat(buf, res->insn.op_str);
+
+ rc = 0;
+ cleanup:
+ return rc;
+}
+
+extern "C" const char *
+powerpc_reg_to_str(uint32_t rid)
+{
+ if(!handle_lil) {
+ powerpc_init();
+ }
+
+ return cs_reg_name(handle_lil, rid);
+}
+