From 3c6cdd1fae2dcc4870326b8e288ebe46f48efb08 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Tue, 12 Mar 2024 13:18:38 -0400 Subject: [PATCH 01/14] added all the old stuff, need to decide on getopt for windows stuff --- arch/powerpc/CMakeLists.txt | 32 ++++++++++++++++++- arch/powerpc/arch_ppc.cpp | 48 ++++++++++++++++++++++++++--- arch/powerpc/disassembler.cpp | 18 ++++++----- arch/powerpc/disassembler.h | 7 +++-- arch/powerpc/test_asm.cpp | 4 +++ arch/powerpc/test_disasm.cpp | 58 +++++++++++++++++++++++++++++------ 6 files changed, 142 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index 57a68f6ee..fe168576c 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -2,8 +2,14 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(arch_ppc) +if((NOT BN_API_PATH) AND (NOT BN_INTERNAL_BUILD)) + set(BN_API_PATH $ENV{BN_API_PATH}) + if(NOT BN_API_PATH) + message(FATAL_ERROR "Provide path to Binary Ninja API source in BN_API_PATH") + endif() +endif() if(NOT BN_INTERNAL_BUILD) - add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api) + add_subdirectory(${BN_API_PATH} ${PROJECT_BINARY_DIR}/api) endif() file(GLOB SOURCES @@ -47,3 +53,27 @@ if(BN_INTERNAL_BUILD) LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR} RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) endif() + +if (DEFINED FORCE_TEST) + set(TEST_INLCUDE_LIST ) + set(TEST_LINK_DIRECTORIES ) + set(TEST_LINK_LIBRARIES capstone) + + if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + find_package(getopt_for_windows) + list(APPEND TEST_INCLUDE_LIST ${getopt_for_windows_INCLUDE_DIR}) + list(APPEND TEST_LINK_DIRECTORIES ${getopt_for_windows_LIB_DIR}) + list(APPEND TEST_LINK_LIBRARIES getopt_for_windows_static) + endif() + + add_executable(test_disasm test_disasm.cpp disassembler.cpp) + add_executable(test_asm test_asm.cpp assembler.cpp) + + target_include_directories(test_disasm PRIVATE ${TEST_INCLUDE_LIST}) + target_link_directories(test_disasm PRIVATE ${TEST_LINK_DIRECTORIES}) + target_link_libraries(test_disasm PRIVATE ${TEST_LINK_LIBRARIES}) + + target_include_directories(test_asm PRIVATE ${TEST_INCLUDE_LIST}) + target_link_directories(test_asm PRIVATE ${TEST_LINK_DIRECTORIES}) + target_link_libraries(test_asm PRIVATE ${TEST_LINK_LIBRARIES}) +endif() diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp index 6366db168..4791a49d7 100644 --- a/arch/powerpc/arch_ppc.cpp +++ b/arch/powerpc/arch_ppc.cpp @@ -281,6 +281,7 @@ class PowerpcArchitecture: public Architecture { private: BNEndianness endian; + int cs_mode_local; /* this can maybe be moved to the API later */ BNRegisterInfo RegisterInfo(uint32_t fullWidthReg, size_t offset, size_t size, bool zeroExtend = false) @@ -299,6 +300,14 @@ class PowerpcArchitecture: public Architecture PowerpcArchitecture(const char* name, BNEndianness endian_): Architecture(name) { endian = endian_; + cs_mode_local = 0; + } + + /* initialization list */ + PowerpcArchitecture(const char* name, BNEndianness endian_, int CS_MODE_): Architecture(name) + { + endian = endian_; + cs_mode_local = CS_MODE_; } /*************************************************************************/ @@ -360,7 +369,7 @@ class PowerpcArchitecture: public Architecture } /* decompose the instruction to get branch info */ - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res)) { + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); return false; } @@ -622,7 +631,7 @@ class PowerpcArchitecture: public Architecture if (DoesQualifyForLocalDisassembly(data)) return PerformLocalDisassembly(data, addr, len, result); - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res)) { + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); goto cleanup; } @@ -748,7 +757,7 @@ class PowerpcArchitecture: public Architecture goto cleanup; } - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res)) { + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); il.AddInstruction(il.Undefined()); goto cleanup; @@ -922,7 +931,7 @@ class PowerpcArchitecture: public Architecture virtual string GetRegisterName(uint32_t regId) override { - const char *result = powerpc_reg_to_str(regId); + const char *result = powerpc_reg_to_str(regId, cs_mode_local); if(result == NULL) result = ""; @@ -2471,6 +2480,15 @@ extern "C" Architecture* ppc = new PowerpcArchitecture("ppc", BigEndian); Architecture::Register(ppc); + Architecture* ppc_qpx = new PowerpcArchitecture("ppc_qpx", BigEndian, CS_MODE_QPX); + Architecture::Register(ppc_qpx); + + Architecture* ppc_spe = new PowerpcArchitecture("ppc_spe", BigEndian, CS_MODE_SPE); + Architecture::Register(ppc_spe); + + Architecture* ppc_ps = new PowerpcArchitecture("ppc_ps", BigEndian, CS_MODE_PS); + Architecture::Register(ppc_ps); + Architecture* ppc64 = new PowerpcArchitecture("ppc64", BigEndian); Architecture::Register(ppc64); @@ -2485,10 +2503,19 @@ extern "C" conv = new PpcSvr4CallingConvention(ppc); ppc->RegisterCallingConvention(conv); ppc->SetDefaultCallingConvention(conv); + ppc_qpx->RegisterCallingConvention(conv); + ppc_qpx->SetDefaultCallingConvention(conv); + ppc_spe->RegisterCallingConvention(conv); + ppc_spe->SetDefaultCallingConvention(conv); + ppc_ps->RegisterCallingConvention(conv); + ppc_ps->SetDefaultCallingConvention(conv); ppc64->RegisterCallingConvention(conv); ppc64->SetDefaultCallingConvention(conv); conv = new PpcLinuxSyscallCallingConvention(ppc); ppc->RegisterCallingConvention(conv); + ppc_qpx->RegisterCallingConvention(conv); + ppc_spe->RegisterCallingConvention(conv); + ppc_ps->RegisterCallingConvention(conv); ppc64->RegisterCallingConvention(conv); conv = new PpcSvr4CallingConvention(ppc_le); @@ -2502,9 +2529,15 @@ extern "C" /* function recognizer */ ppc->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); + ppc_qpx->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); + ppc_spe->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); + ppc_ps->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); ppc_le->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); ppc->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); + ppc_qpx->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); + ppc_spe->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); + ppc_ps->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); ppc_le->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); ppc_le->RegisterRelocationHandler("Mach-O", new PpcMachoRelocationHandler()); /* call the STATIC RegisterArchitecture with "Mach-O" @@ -2538,6 +2571,13 @@ extern "C" ppc /* the architecture */ ); + BinaryViewType::RegisterArchitecture( + "ELF", /* name of the binary view type */ + EM_PPC, /* id (key in m_arch map) */ + BigEndian, + ppc_ps /* the architecture */ + ); + BinaryViewType::RegisterArchitecture( "ELF", /* name of the binary view type */ EM_PPC64, /* id (key in m_arch map) */ diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp index 66a8b36dd..24545fe05 100644 --- a/arch/powerpc/disassembler.cpp +++ b/arch/powerpc/disassembler.cpp @@ -19,7 +19,7 @@ thread_local csh handle_lil = 0; thread_local csh handle_big = 0; extern "C" int -powerpc_init(void) +powerpc_init(int cs_mode_arg) { int rc = -1; @@ -31,12 +31,12 @@ powerpc_init(void) } /* initialize capstone handle */ - if(cs_open(CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, &handle_big) != CS_ERR_OK) { + if(cs_open(CS_ARCH_PPC, (cs_mode)((int)CS_MODE_BIG_ENDIAN | cs_mode_arg), &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) { + if(cs_open(CS_ARCH_PPC, (cs_mode)((int)CS_MODE_LITTLE_ENDIAN | cs_mode_arg), &handle_lil) != CS_ERR_OK) { MYLOG("ERROR: cs_open()\n"); goto cleanup; } @@ -69,13 +69,13 @@ powerpc_release(void) extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, - struct decomp_result *res) + struct decomp_result *res, int cs_mode_arg) { int rc = -1; res->status = STATUS_ERROR_UNSPEC; if(!handle_lil) { - powerpc_init(); + powerpc_init(cs_mode_arg); } //typedef struct cs_insn { @@ -120,6 +120,7 @@ powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, // } cs_ppc_op; csh handle; + struct cs_struct *hand_tmp = 0; cs_insn *insn = 0; /* instruction information cs_disasm() will allocate array of cs_insn here */ @@ -129,6 +130,9 @@ powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, if(lil_end) handle = handle_lil; res->handle = handle; + hand_tmp = (struct cs_struct *)handle; + hand_tmp->mode = (cs_mode)((int)hand_tmp->mode | cs_mode_arg); + /* call */ size_t n = cs_disasm(handle, data, size, addr, 1, &insn); if(n != 1) { @@ -174,10 +178,10 @@ powerpc_disassemble(struct decomp_result *res, char *buf, size_t len) } extern "C" const char * -powerpc_reg_to_str(uint32_t rid) +powerpc_reg_to_str(uint32_t rid, int cs_mode_arg) { if(!handle_lil) { - powerpc_init(); + powerpc_init(cs_mode_arg); } return cs_reg_name(handle_lil, rid); diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h index e1701687c..e08924416 100644 --- a/arch/powerpc/disassembler.h +++ b/arch/powerpc/disassembler.h @@ -23,6 +23,7 @@ Then some helpers if you need them: /* capstone stuff /usr/local/include/capstone */ #include "capstone/capstone.h" +#include "capstone/cs_priv.h" #include "capstone/ppc.h" //***************************************************************************** @@ -59,11 +60,11 @@ struct decomp_result //***************************************************************************** // function prototypes //***************************************************************************** -extern "C" int powerpc_init(void); +extern "C" int powerpc_init(int); extern "C" void powerpc_release(void); extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr, - bool lil_end, struct decomp_result *result); + bool lil_end, struct decomp_result *result, int); extern "C" int powerpc_disassemble(struct decomp_result *, char *buf, size_t len); -extern "C" const char *powerpc_reg_to_str(uint32_t rid); +extern "C" const char *powerpc_reg_to_str(uint32_t rid, int); diff --git a/arch/powerpc/test_asm.cpp b/arch/powerpc/test_asm.cpp index 7f3917927..253b74864 100644 --- a/arch/powerpc/test_asm.cpp +++ b/arch/powerpc/test_asm.cpp @@ -23,7 +23,11 @@ using namespace std; #include #include +#if defined(_WIN32) +#include +#else #include +#endif #include "assembler.h" diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index b893d2ab9..9c651ef18 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -15,9 +15,16 @@ g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp dis #include #include +#if defined(_WIN32) +#include +#else +#include +#endif + #include "disassembler.h" int print_errors = 1; +int cs_mode_local = 0; int disas_instr_word(uint32_t instr_word, char *buf) { @@ -28,7 +35,7 @@ int disas_instr_word(uint32_t instr_word, char *buf) 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(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, true, &res, cs_mode_local)) { if(print_errors) printf("ERROR: powerpc_decompose()\n"); goto cleanup; } @@ -106,21 +113,52 @@ int disas_instr_word(uint32_t instr_word, char *buf) return rc; } +void usage() +{ + printf("send argument \"repl\" or \"speed\"\n"); +} + int main(int ac, char **av) { int rc = -1; char buf[256]; + int index; + char* disasm_cmd = 0; + int c; + +#define BATCH 10000000 + opterr = 0; + + while ((c = getopt(ac, av, "qsp")) != -1) + { + switch (c) + { + case 'q': + cs_mode_local = CS_MODE_QPX; + break; + case 's': + cs_mode_local = CS_MODE_SPE; + break; + case 'p': + cs_mode_local = CS_MODE_PS; + break; + default: + usage(); + goto cleanup; + } + } - #define BATCH 10000000 - - powerpc_init(); - - if(ac <= 1) { - printf("send argument \"repl\" or \"speed\"\n"); + if (optind >= ac) + { + usage(); goto cleanup; } - if(!strcasecmp(av[1], "repl")) { + disasm_cmd = av[optind]; + + powerpc_init(cs_mode_local); + + if(!strcasecmp(disasm_cmd, "repl")) { printf("REPL mode!\n"); printf("example inputs (write the words as if after endian fetch):\n"); printf("93e1fffc\n"); @@ -148,7 +186,7 @@ int main(int ac, char **av) printf("%s\n", buf); } } - else if(!strcasecmp(av[1], "speed")) { + else if(!strcasecmp(disasm_cmd, "speed")) { printf("SPEED TEST THAT COUNTS QUICK RETURNS FROM BAD INSTRUCTIONS AS DISASSEMBLED\n"); print_errors = 0; uint32_t instr_word = 0x780b3f7c; @@ -167,7 +205,7 @@ int main(int ac, char **av) printf("current rate: %f instructions per second\n", (float)BATCH/ellapsed); } } - else if(!strcasecmp(av[1], "speed2")) { + else if(!strcasecmp(disasm_cmd, "speed2")) { printf("SPEED TEST THAT IS GIVEN NO CREDIT FOR QUICK RETURNS FROM BAD INSTRUCTIONS\n"); print_errors = 0; uint32_t instr_word = 0x780b3f7c; From 767860f6ca31bc4768ff05492d9d6020932aa0b0 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Tue, 12 Mar 2024 13:26:47 -0400 Subject: [PATCH 02/14] forgot the unsubmodule changes --- arch/powerpc/CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index fe168576c..5f9045317 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -2,14 +2,8 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(arch_ppc) -if((NOT BN_API_PATH) AND (NOT BN_INTERNAL_BUILD)) - set(BN_API_PATH $ENV{BN_API_PATH}) - if(NOT BN_API_PATH) - message(FATAL_ERROR "Provide path to Binary Ninja API source in BN_API_PATH") - endif() -endif() if(NOT BN_INTERNAL_BUILD) - add_subdirectory(${BN_API_PATH} ${PROJECT_BINARY_DIR}/api) + add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api) endif() file(GLOB SOURCES From 8541410568fd41448ed3b72efb5afce017bc29fa Mon Sep 17 00:00:00 2001 From: David Riusech Date: Tue, 12 Mar 2024 13:41:27 -0400 Subject: [PATCH 03/14] removed windows compat stuff --- arch/powerpc/CMakeLists.txt | 27 +++++++++++---------------- arch/powerpc/test_asm.cpp | 4 ---- arch/powerpc/test_disasm.cpp | 4 ---- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index 5f9045317..95b19df98 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -53,21 +53,16 @@ if (DEFINED FORCE_TEST) set(TEST_LINK_DIRECTORIES ) set(TEST_LINK_LIBRARIES capstone) - if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - find_package(getopt_for_windows) - list(APPEND TEST_INCLUDE_LIST ${getopt_for_windows_INCLUDE_DIR}) - list(APPEND TEST_LINK_DIRECTORIES ${getopt_for_windows_LIB_DIR}) - list(APPEND TEST_LINK_LIBRARIES getopt_for_windows_static) - endif() - - add_executable(test_disasm test_disasm.cpp disassembler.cpp) - add_executable(test_asm test_asm.cpp assembler.cpp) - - target_include_directories(test_disasm PRIVATE ${TEST_INCLUDE_LIST}) - target_link_directories(test_disasm PRIVATE ${TEST_LINK_DIRECTORIES}) - target_link_libraries(test_disasm PRIVATE ${TEST_LINK_LIBRARIES}) + if (${CMAKE_SYSTEM_NAME} NOT MATCHES "Windows") + add_executable(test_disasm test_disasm.cpp disassembler.cpp) + add_executable(test_asm test_asm.cpp assembler.cpp) + + target_include_directories(test_disasm PRIVATE ${TEST_INCLUDE_LIST}) + target_link_directories(test_disasm PRIVATE ${TEST_LINK_DIRECTORIES}) + target_link_libraries(test_disasm PRIVATE ${TEST_LINK_LIBRARIES}) - target_include_directories(test_asm PRIVATE ${TEST_INCLUDE_LIST}) - target_link_directories(test_asm PRIVATE ${TEST_LINK_DIRECTORIES}) - target_link_libraries(test_asm PRIVATE ${TEST_LINK_LIBRARIES}) + target_include_directories(test_asm PRIVATE ${TEST_INCLUDE_LIST}) + target_link_directories(test_asm PRIVATE ${TEST_LINK_DIRECTORIES}) + target_link_libraries(test_asm PRIVATE ${TEST_LINK_LIBRARIES}) + endif() endif() diff --git a/arch/powerpc/test_asm.cpp b/arch/powerpc/test_asm.cpp index 253b74864..7f3917927 100644 --- a/arch/powerpc/test_asm.cpp +++ b/arch/powerpc/test_asm.cpp @@ -23,11 +23,7 @@ using namespace std; #include #include -#if defined(_WIN32) -#include -#else #include -#endif #include "assembler.h" diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index 9c651ef18..6f1615a18 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -15,11 +15,7 @@ g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp dis #include #include -#if defined(_WIN32) -#include -#else #include -#endif #include "disassembler.h" From 8207badb88d7bdb37f10a10713fb15830147725f Mon Sep 17 00:00:00 2001 From: David Riusech Date: Mon, 18 Mar 2024 10:04:04 -0400 Subject: [PATCH 04/14] early lifting, missing fcmpo --- arch/powerpc/il.cpp | 51 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/il.cpp b/arch/powerpc/il.cpp index 1de2c5c09..c5aee3064 100644 --- a/arch/powerpc/il.cpp +++ b/arch/powerpc/il.cpp @@ -1574,6 +1574,53 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, il.AddInstruction(il.Trap(0)); break; + case PPC_INS_STFS: + REQUIRE2OPS + ei0 = il.Store(4, + operToIL(il, oper1), + operToIL(il, oper0) + ); + il.AddInstruction(ei0); + + break; + + case PPC_INS_STFD: + REQUIRE2OPS + ei0 = il.Store(8, + operToIL(il, oper1), + operToIL(il, oper0) + ); + il.AddInstruction(ei0); + + break; + + case PPC_INS_LFS: + REQUIRE2OPS + ei0 = operToIL(il, oper1); // d(rA) or 0 + ei0 = il.Load(4, ei0); // [d(rA)] + ei0 = il.SetRegister(4, oper0->reg, ei0); // rD = [d(rA)] + il.AddInstruction(ei0); + + break; + + case PPC_INS_LFD: + REQUIRE2OPS + ei0 = operToIL(il, oper1); // d(rA) or 0 + ei0 = il.Load(8, ei0); // [d(rA)] + ei0 = il.SetRegister(8, oper0->reg, ei0); // rD = [d(rA)] + il.AddInstruction(ei0); + + break; + + // case PPC_INS_FCMPO: /* compare (signed) word(32-bit) */ + // REQUIRE2OPS + // ei0 = operToIL(il, oper2 ? oper1 : oper0); + // ei1 = operToIL(il, oper2 ? oper2 : oper1); + // ei2 = il.Sub(4, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0)); + // il.AddInstruction(ei2); + // break; + + case PPC_INS_BCL: case PPC_INS_BCLR: case PPC_INS_BCLRL: @@ -1821,13 +1868,11 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_LDU: case PPC_INS_LDUX: case PPC_INS_LDX: - case PPC_INS_LFD: case PPC_INS_LFDU: case PPC_INS_LFDUX: case PPC_INS_LFDX: case PPC_INS_LFIWAX: case PPC_INS_LFIWZX: - case PPC_INS_LFS: case PPC_INS_LFSU: case PPC_INS_LFSUX: case PPC_INS_LFSX: @@ -1899,12 +1944,10 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_STDU: case PPC_INS_STDUX: case PPC_INS_STDX: - case PPC_INS_STFD: case PPC_INS_STFDU: case PPC_INS_STFDUX: case PPC_INS_STFDX: case PPC_INS_STFIWX: - case PPC_INS_STFS: case PPC_INS_STFSU: case PPC_INS_STFSUX: case PPC_INS_STFSX: From e6754f72668fd69eb531493c85fde5dc78ba07b5 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Fri, 29 Mar 2024 08:27:55 -0400 Subject: [PATCH 05/14] mac support, needed threadlocal for the disassembler.cpp --- arch/powerpc/CMakeLists.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index 95b19df98..3b3b890cd 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -53,9 +53,23 @@ if (DEFINED FORCE_TEST) set(TEST_LINK_DIRECTORIES ) set(TEST_LINK_LIBRARIES capstone) - if (${CMAKE_SYSTEM_NAME} NOT MATCHES "Windows") + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_executable(test_disasm test_disasm.cpp disassembler.cpp) add_executable(test_asm test_asm.cpp assembler.cpp) + + set_target_properties(test_disasm PROPERTIES + CXX_STANDARD 17 + CXX_VISIBILITY_PRESET hidden + CXX_STANDARD_REQUIRED ON + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) + + set_target_properties(test_asm PROPERTIES + CXX_STANDARD 17 + CXX_VISIBILITY_PRESET hidden + CXX_STANDARD_REQUIRED ON + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) target_include_directories(test_disasm PRIVATE ${TEST_INCLUDE_LIST}) target_link_directories(test_disasm PRIVATE ${TEST_LINK_DIRECTORIES}) From f2950ea028c89a136e80294ca53893f378c52662 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Fri, 29 Mar 2024 16:39:05 -0400 Subject: [PATCH 06/14] moved around the external routines, and added them to the il --- arch/powerpc/CMakeLists.txt | 9 +- arch/powerpc/arch_ppc.cpp | 175 ++++++++-------------------------- arch/powerpc/disassembler.cpp | 78 +++++++++++++++ arch/powerpc/disassembler.h | 16 ++++ arch/powerpc/il.cpp | 35 +++++-- arch/powerpc/test_disasm.cpp | 3 +- 6 files changed, 162 insertions(+), 154 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index 3b3b890cd..7848fe181 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -57,14 +57,7 @@ if (DEFINED FORCE_TEST) add_executable(test_disasm test_disasm.cpp disassembler.cpp) add_executable(test_asm test_asm.cpp assembler.cpp) - set_target_properties(test_disasm PROPERTIES - CXX_STANDARD 17 - CXX_VISIBILITY_PRESET hidden - CXX_STANDARD_REQUIRED ON - VISIBILITY_INLINES_HIDDEN ON - POSITION_INDEPENDENT_CODE ON) - - set_target_properties(test_asm PROPERTIES + set_target_properties(test_disasm test_asm PROPERTIES CXX_STANDARD 17 CXX_VISIBILITY_PRESET hidden CXX_STANDARD_REQUIRED ON diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp index a0f5176ad..d2fecb9f4 100644 --- a/arch/powerpc/arch_ppc.cpp +++ b/arch/powerpc/arch_ppc.cpp @@ -358,7 +358,7 @@ class PowerpcArchitecture: public Architecture return false; } - if (DoesQualifyForLocalDisassembly(data)) { + if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) { result.length = 4; return true; } @@ -457,149 +457,56 @@ class PowerpcArchitecture: public Architecture return true; } - bool DoesQualifyForLocalDisassembly(const uint8_t *data) - { - uint32_t insword = *(uint32_t *)data; - if(endian == BigEndian) - insword = bswap32(insword); - - // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo - uint32_t tmp = insword & 0xFC6007FF; - if (tmp==0xFC000040) - return true; - // 111100xxxxxxxxxxxxxxx00111010xxx <- xxpermr - if((insword & 0xFC0007F8) == 0xF00001D0) - return true; - // 000100xxxxxxxxxxxxxxxxxxx000110x <- psq_lx - // 000100xxxxxxxxxxxxxxxxxxx000111x <- psq_stx - // 000100xxxxxxxxxxxxxxxxxxx100110x <- psq_lux - // 000100xxxxxxxxxxxxxxxxxxx100111x <- psq_stux - tmp = insword & 0xFC00007E; - if (tmp==0x1000000C || tmp==0x1000000E || tmp==0x1000004C || tmp==0x1000004E) - return true; - // 000100xxxxxxxxxx00000xxxxx011000 <- ps_muls0 - // 000100xxxxxxxxxx00000xxxxx011001 <- ps_muls0. - // 000100xxxxxxxxxx00000xxxxx011010 <- ps_muls1 - // 000100xxxxxxxxxx00000xxxxx011011 <- ps_muls1. - tmp = insword & 0xFC00F83F; - if (tmp==0x10000018 || tmp==0x10000019 || tmp==0x1000001A || tmp==0x1000001B) - return true; - - return false; - } - - bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, vector &result) + bool PrintLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, vector &result, decomp_result* res) { (void)addr; + char buf[16]; + uint32_t local_op = PPC_INS_INVALID; - if (len < 4) return false; - uint32_t insword = *(uint32_t *)data; - if(endian == BigEndian) - insword = bswap32(insword); + struct cs_detail *detail = 0; + struct cs_ppc *ppc = 0; + struct cs_insn *insn = &(res->insn); + + detail = &(res->detail); + ppc = &(detail->ppc); + if (len < 4) + return false; len = 4; - char buf[16]; + local_op = DoesQualifyForLocalDisassembly(data, endian == BigEndian); + PerformLocalDisassembly(data, addr, len, res, endian == BigEndian); - // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC" - uint32_t tmp = insword & 0xFC6007FF; - if (tmp==0xFC000040) { - result.emplace_back(InstructionToken, "fcmpo"); + switch (local_op) + { + case PPC_INS_BN_FCMPO: + result.emplace_back(InstructionToken, insn->mnemonic); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "cr%d", (insword >> 23) & 7); + snprintf(buf, sizeof(buf), "cr%d", ppc->operands[0].reg); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", (insword >> 16) & 31); + snprintf(buf, sizeof(buf), "f%d", ppc->operands[1].reg); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", (insword >> 11) & 31); - result.emplace_back(RegisterToken, buf); - return true; - } - - // 111100AAAAABBBBBCCCCC00011010BCA "xxpermr vsA,vsB,vsC" - if ((insword & 0xFC0007F8)==0xF00001D0) { - int a = ((insword & 0x3E00000)>>21)|((insword & 0x1)<<5); - int b = ((insword & 0x1F0000)>>16)|((insword & 0x4)<<3); - int c = ((insword & 0xF800)>>11)|((insword & 0x2)<<4); - result.emplace_back(InstructionToken, "xxpermr"); - result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "vs%d", a); + snprintf(buf, sizeof(buf), "f%d", ppc->operands[2].reg); result.emplace_back(RegisterToken, buf); - result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", b); - result.emplace_back(RegisterToken, buf); - result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", c); - result.emplace_back(RegisterToken, buf); - return true; - } - - // 000100AAAAABBBBBCCCCCDEEE000110x psq_lx FREG,GPR,GPR,NUM,NUM - // 000100AAAAABBBBBCCCCCDEEE000111x psq_stx FREG,GPR,GPR,NUM,NUM - // 000100AAAAABBBBBCCCCCDEEE100110x psq_lux FREG,GPR,GPR,NUM,NUM - // 000100AAAAABBBBBCCCCCDEEE100111x psq_stux FREG,GPR,GPR,NUM,NUM - tmp = insword & 0xFC00007E; - if (tmp==0x1000000C || tmp==0x1000000E || tmp==0x1000004C || tmp==0x1000004E) { - switch(tmp) { - case 0x1000000C: - result.emplace_back(InstructionToken, "psq_lx"); - result.emplace_back(TextToken, " "); - break; - case 0x1000000E: result.emplace_back(InstructionToken, "psq_stx"); - result.emplace_back(TextToken, " "); - break; - case 0x1000004C: result.emplace_back(InstructionToken, "psq_lux"); - result.emplace_back(TextToken, " "); - break; - case 0x1000004E: result.emplace_back(InstructionToken, "psq_stux"); - result.emplace_back(TextToken, " "); - break; - } - snprintf(buf, sizeof(buf), "f%d", (insword & 0x3E00000) >> 21); - result.emplace_back(RegisterToken, buf); - result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "r%d", (insword & 0x1F0000) >> 16); - result.emplace_back(RegisterToken, buf); - result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "r%d", (insword & 0xF800) >> 11); - result.emplace_back(RegisterToken, buf); - result.emplace_back(OperandSeparatorToken, ", "); - tmp = (insword & 0x400)>>10; - snprintf(buf, sizeof(buf), "%d", tmp); - result.emplace_back(IntegerToken, buf, tmp, 1); - result.emplace_back(OperandSeparatorToken, ", "); - tmp = (insword & 0x380)>>7; - snprintf(buf, sizeof(buf), "%d", tmp); - result.emplace_back(IntegerToken, buf, tmp, 1); - return true; - } - - // 000100AAAAABBBBB00000CCCCC011000 ps_muls0 FREG,FREG,FREG - // 000100AAAAABBBBB00000CCCCC011001 ps_muls0. FREG,FREG,FREG - // 000100AAAAABBBBB00000CCCCC011010 ps_muls1 FREG,FREG,FREG - // 000100AAAAABBBBB00000CCCCC011011 ps_muls1. FREG,FREG,FREG - tmp = insword & 0xFC00F83F; - if (tmp==0x10000018 || tmp==0x10000019 || tmp==0x1000001A || tmp==0x1000001B) { - switch(tmp) { - case 0x10000018: result.emplace_back(InstructionToken, "ps_muls0"); break; - case 0x10000019: result.emplace_back(InstructionToken, "ps_muls0."); break; - case 0x1000001A: result.emplace_back(InstructionToken, "ps_muls1"); break; - case 0x1000001B: result.emplace_back(InstructionToken, "ps_muls1."); break; - } + break; + case PPC_INS_BN_XXPERMR: + result.emplace_back(InstructionToken, insn->mnemonic); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "f%d", (insword & 0x3E00000) >> 21); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[0].reg); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", (insword & 0x1F0000) >> 16); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[1].reg); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", (insword & 0x7C0) >> 6); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[2].reg); result.emplace_back(RegisterToken, buf); - return true; + break; + default: + return false; } - - return false; + return true; } /* populate the vector result with InstructionTextToken @@ -623,9 +530,9 @@ class PowerpcArchitecture: public Architecture goto cleanup; } - if (DoesQualifyForLocalDisassembly(data)) - return PerformLocalDisassembly(data, addr, len, result); - + if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) + // PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian); + return PrintLocalDisassembly(data, addr, len, result, &res); if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); goto cleanup; @@ -733,6 +640,7 @@ class PowerpcArchitecture: public Architecture virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override { bool rc = false; + struct decomp_result res = {0}; if (len < 4) { MYLOG("ERROR: need at least 4 bytes\n"); @@ -743,21 +651,16 @@ class PowerpcArchitecture: public Architecture // MYLOG("%s(data, 0x%llX, 0x%zX, il)\n", __func__, addr, len); //} - struct decomp_result res; - - if (DoesQualifyForLocalDisassembly(data)) { - il.AddInstruction(il.Unimplemented()); - rc = true; - len = 4; - goto cleanup; + if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) { + PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian); } - - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { + else if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); il.AddInstruction(il.Undefined()); goto cleanup; } +getil: rc = GetLowLevelILForPPCInstruction(this, il, data, addr, &res, endian == LittleEndian); len = 4; diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp index 31ac753cc..446845372 100644 --- a/arch/powerpc/disassembler.cpp +++ b/arch/powerpc/disassembler.cpp @@ -12,12 +12,90 @@ architecture plugin picture. //#define MYLOG BinaryNinja::LogDebug #include "disassembler.h" +#include "util.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; +int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian) +{ + uint32_t insword = *(uint32_t *)data; + int result = PPC_INS_INVALID; + uint32_t tmp = 0; + + if(bigendian == true) + insword = bswap32(insword); + + // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo + tmp = insword & 0xFC6007FF; + if (tmp==0xFC000040) + result = PPC_INS_BN_FCMPO; + // 111100xxxxxxxxxxxxxxx00111010xxx <- xxpermr + if((insword & 0xFC0007F8) == 0xF00001D0) + result = PPC_INS_BN_XXPERMR; + + return result; +} + +void ppc_fcmpo(uint32_t insword, decomp_result *res) +{ + // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC" + res->detail.ppc.operands[0].reg = (ppc_reg)(PPC_REG_CR0 + (insword >> 23) & 7); + res->detail.ppc.operands[0].type = PPC_OP_REG; + res->detail.ppc.operands[1].reg = (ppc_reg)(PPC_REG_F0 + (insword >> 16) & 31); + res->detail.ppc.operands[1].type = PPC_OP_REG; + res->detail.ppc.operands[2].reg = (ppc_reg)(PPC_REG_F0 + (insword >> 11) & 31); + res->detail.ppc.operands[2].type = PPC_OP_REG; + + res->insn.id = PPC_INS_BN_FCMPO; + res->detail.ppc.op_count = 3; + strncpy(res->insn.mnemonic, "fcmpo", sizeof(res->insn.mnemonic)); +} + +void ppc_xxpermr(uint32_t insword, decomp_result *res) +{ + // 111100AAAAABBBBBCCCCC00011010BCA "xxpermr vsA,vsB,vsC" + int a = ((insword & 0x3E00000)>>21)|((insword & 0x1)<<5); + int b = ((insword & 0x1F0000)>>16)|((insword & 0x4)<<3); + int c = ((insword & 0xF800)>>11)|((insword & 0x2)<<4); + + res->detail.ppc.operands[0].reg = (ppc_reg)(PPC_REG_VS0 + a); + res->detail.ppc.operands[0].type = PPC_OP_REG; + res->detail.ppc.operands[1].reg = (ppc_reg)(PPC_REG_VS0 + b); + res->detail.ppc.operands[1].type = PPC_OP_REG; + res->detail.ppc.operands[2].reg = (ppc_reg)(PPC_REG_VS0 + c); + res->detail.ppc.operands[2].type = PPC_OP_REG; + + res->insn.id = PPC_INS_BN_XXPERMR; + res->detail.ppc.op_count = 3; + strncpy(res->insn.mnemonic, "xxpermr", sizeof(res->insn.mnemonic)); +} + +bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian) +{ + uint32_t local_op = 0; + uint32_t insword = 0; + + if(bigendian == true) + insword = bswap32(insword); + local_op = DoesQualifyForLocalDisassembly(data, bigendian); + + switch(local_op) + { + case PPC_INS_BN_FCMPO: + ppc_fcmpo(insword, res); + break; + case PPC_INS_BN_XXPERMR: + ppc_xxpermr(insword, res); + break; + default: + return false; + } + return true; +} + extern "C" int powerpc_init(int cs_mode_arg) { diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h index 79bc9729e..9a5d79c38 100644 --- a/arch/powerpc/disassembler.h +++ b/arch/powerpc/disassembler.h @@ -33,6 +33,19 @@ enum ppc_status_t { STATUS_ERROR_UNSPEC=-1, STATUS_SUCCESS=0, STATUS_UNDEF_INSTR }; +typedef enum ppc_insn_bn { + PPC_INS_BN_FCMPO = PPC_INS_ENDING+1, + PPC_INS_BN_XXPERMR, + PPC_INS_BN_PSQ_LX, + PPC_INS_BN_PSQ_STX, + PPC_INS_BN_PSQ_LUX, + PPC_INS_BN_PSQ_STUX, + PPC_INS_BN_PS_MULS0, + PPC_INS_BN_PS_MULS0D, + PPC_INS_BN_PS_MULS1, + PPC_INS_BN_PS_MULS1D, + PPC_INS_BN_ENDING +} ppc_insn_bn; /* operand type */ enum operand_type_t { REG, VAL, LABEL }; @@ -60,6 +73,9 @@ struct decomp_result //***************************************************************************** // function prototypes //***************************************************************************** +int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian); +bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian); + extern "C" int powerpc_init(int); extern "C" void powerpc_release(void); extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr, diff --git a/arch/powerpc/il.cpp b/arch/powerpc/il.cpp index ed6e29a00..8cd9b104d 100644 --- a/arch/powerpc/il.cpp +++ b/arch/powerpc/il.cpp @@ -451,6 +451,9 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, { int i; bool rc = true; + struct cs_insn *insn = 0; + struct cs_detail *detail = 0; + struct cs_ppc *ppc = 0; /* bypass capstone path for *all* branching instructions; capstone * is too difficult to work with and is outright broken for some @@ -459,9 +462,9 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, if (LiftBranches(arch, il, data, addr, le)) return true; - struct cs_insn *insn = &(res->insn); - struct cs_detail *detail = &(res->detail); - struct cs_ppc *ppc = &(detail->ppc); + insn = &(res->insn); + detail = &(res->detail); + ppc = &(detail->ppc); /* There is a simplifying reduction available for: * rlwinm , , , , @@ -714,11 +717,26 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, // il.AddInstruction(ei2); // break; - // case PPC_INS_FCMPU: - // REQUIRE3OPS - // ei0 = il.FloatSub(4, il.Unimplemented(), il.Unimplemented(), (oper0->reg - PPC_REG_CR0) + IL_FLAGWRITE_INVL0); - // il.AddInstruction(ei0); - // break; + // TODO: high level IL is sometimes assuming incorrect variables, and setting floating points to + // standard registers. + // TODO: high level IL is accidentilly adding an extra subtract operand and assigning it to no one. + // TODO: final assignment for the fcmp is whether or not the sub is 0, not greater than 0. + case PPC_INS_FCMPU: + REQUIRE3OPS + ei0 = il.FloatSub(4, operToIL(il, oper1), operToIL(il, oper2), crxToFlagWriteType(oper0->reg)); + il.AddInstruction(ei0); + break; + + case PPC_INS_BN_FCMPO: + REQUIRE3OPS + ei0 = il.FloatSub(4, operToIL(il, oper1), operToIL(il, oper2), crxToFlagWriteType(oper0->reg)); + il.AddInstruction(ei0); + break; + + case PPC_INS_FMR: + REQUIRE2OPS + il.AddInstruction(il.SetRegister(4, oper0->reg, operToIL(il, oper1))); + break; case PPC_INS_CRAND: case PPC_INS_CRANDC: @@ -1954,7 +1972,6 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_FDIVS: case PPC_INS_FMADD: case PPC_INS_FMADDS: - case PPC_INS_FMR: case PPC_INS_FMSUB: case PPC_INS_FMSUBS: case PPC_INS_FMUL: diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index db60773e0..ee9e7f7f0 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -22,6 +22,7 @@ g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp dis int print_errors = 1; int cs_mode_local = 0; size_t address_size_ = 4; +bool bigendian = true; int disas_instr_word(uint32_t instr_word, char *buf) { @@ -32,7 +33,7 @@ int disas_instr_word(uint32_t instr_word, char *buf) struct cs_detail *detail = &(res.detail); struct cs_ppc *ppc = &(detail->ppc); - if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, true, &res, address_size_, cs_mode_local)) { + if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, bigendian, &res, address_size_, cs_mode_local)) { if(print_errors) printf("ERROR: powerpc_decompose()\n"); goto cleanup; } From ae8021177c9fe3c4e70d84f5b068ff765dd170f4 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Fri, 29 Mar 2024 16:59:31 -0400 Subject: [PATCH 07/14] removed duplicate enums --- arch/powerpc/disassembler.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h index 9a5d79c38..16a9a3430 100644 --- a/arch/powerpc/disassembler.h +++ b/arch/powerpc/disassembler.h @@ -36,14 +36,6 @@ enum ppc_status_t { typedef enum ppc_insn_bn { PPC_INS_BN_FCMPO = PPC_INS_ENDING+1, PPC_INS_BN_XXPERMR, - PPC_INS_BN_PSQ_LX, - PPC_INS_BN_PSQ_STX, - PPC_INS_BN_PSQ_LUX, - PPC_INS_BN_PSQ_STUX, - PPC_INS_BN_PS_MULS0, - PPC_INS_BN_PS_MULS0D, - PPC_INS_BN_PS_MULS1, - PPC_INS_BN_PS_MULS1D, PPC_INS_BN_ENDING } ppc_insn_bn; From 249bb518e1b61ce3c207053a59adc68799c65be8 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Tue, 7 May 2024 02:08:07 -0400 Subject: [PATCH 08/14] fixed disassembly for fp stuff --- arch/powerpc/CMakeLists.txt | 2 + arch/powerpc/arch_ppc.cpp | 14 ++++--- arch/powerpc/disassembler.cpp | 76 ++++++++++++++++++++++++++++++++--- arch/powerpc/test_disasm.cpp | 17 ++++++-- 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index 7848fe181..d148c690a 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -57,6 +57,8 @@ if (DEFINED FORCE_TEST) add_executable(test_disasm test_disasm.cpp disassembler.cpp) add_executable(test_asm test_asm.cpp assembler.cpp) + target_compile_definitions(test_disasm PRIVATE FORCE_TEST=1) + set_target_properties(test_disasm test_asm PROPERTIES CXX_STANDARD 17 CXX_VISIBILITY_PRESET hidden diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp index d2fecb9f4..478465788 100644 --- a/arch/powerpc/arch_ppc.cpp +++ b/arch/powerpc/arch_ppc.cpp @@ -482,25 +482,25 @@ class PowerpcArchitecture: public Architecture case PPC_INS_BN_FCMPO: result.emplace_back(InstructionToken, insn->mnemonic); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "cr%d", ppc->operands[0].reg); + snprintf(buf, sizeof(buf), "cr%d", ppc->operands[0].reg - PPC_REG_CR0); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", ppc->operands[1].reg); + snprintf(buf, sizeof(buf), "f%d", ppc->operands[1].reg - PPC_REG_F0); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", ppc->operands[2].reg); + snprintf(buf, sizeof(buf), "f%d", ppc->operands[2].reg - PPC_REG_F0); result.emplace_back(RegisterToken, buf); break; case PPC_INS_BN_XXPERMR: result.emplace_back(InstructionToken, insn->mnemonic); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[0].reg); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[0].reg - PPC_REG_VS0); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[1].reg); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[1].reg - PPC_REG_VS0); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[2].reg); + snprintf(buf, sizeof(buf), "vs%d", ppc->operands[2].reg - PPC_REG_VS0); result.emplace_back(RegisterToken, buf); break; default: @@ -531,8 +531,10 @@ class PowerpcArchitecture: public Architecture } if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) + { // PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian); return PrintLocalDisassembly(data, addr, len, result, &res); + } if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { MYLOG("ERROR: powerpc_decompose()\n"); goto cleanup; diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp index 446845372..71c2f846d 100644 --- a/arch/powerpc/disassembler.cpp +++ b/arch/powerpc/disassembler.cpp @@ -26,7 +26,9 @@ int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian) uint32_t tmp = 0; if(bigendian == true) + { insword = bswap32(insword); + } // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo tmp = insword & 0xFC6007FF; @@ -41,17 +43,78 @@ int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian) void ppc_fcmpo(uint32_t insword, decomp_result *res) { + unsigned regtmp = 0; + // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC" - res->detail.ppc.operands[0].reg = (ppc_reg)(PPC_REG_CR0 + (insword >> 23) & 7); + regtmp = PPC_REG_CR0 + ((insword >> 23) & 7); + res->detail.ppc.operands[0].reg = (ppc_reg)(regtmp); res->detail.ppc.operands[0].type = PPC_OP_REG; - res->detail.ppc.operands[1].reg = (ppc_reg)(PPC_REG_F0 + (insword >> 16) & 31); + + regtmp = PPC_REG_F0 + ((insword >> 16) & 31); + res->detail.ppc.operands[1].reg = (ppc_reg)(regtmp); res->detail.ppc.operands[1].type = PPC_OP_REG; - res->detail.ppc.operands[2].reg = (ppc_reg)(PPC_REG_F0 + (insword >> 11) & 31); + + regtmp = PPC_REG_F0 + ((insword >> 11) & 31); + res->detail.ppc.operands[2].reg = (ppc_reg)(regtmp); res->detail.ppc.operands[2].type = PPC_OP_REG; + +#ifdef FORCE_TEST + SStream ss; + struct cs_struct* handle = 0; + struct MCInst tempmc = {0}; + char* first_space = 0; + + // SStream_Init(&ss); + ss.index = 0; + ss.buffer[0] = '\0'; + regtmp = PPC_REG_CR0 + ((insword >> 23) & 7); + tempmc.Operands[0].MachineOperandType = MCOperand::kRegister; + tempmc.Operands[0].Kind = 1; + tempmc.Operands[0].RegVal = regtmp; + regtmp = PPC_REG_F0 + ((insword >> 16) & 31); + tempmc.Operands[1].MachineOperandType = MCOperand::kRegister; + tempmc.Operands[1].Kind = 1; + tempmc.Operands[1].RegVal = regtmp; + regtmp = PPC_REG_F0 + ((insword >> 11) & 31); + tempmc.Operands[2].Kind = 1; + tempmc.Operands[2].MachineOperandType = MCOperand::kRegister; + tempmc.Operands[2].RegVal = regtmp; + + // temporarily set this so that print processing succeeds + res->insn.id = PPC_INS_FCMPU; + + if (handle_big != 0) + { + handle = (struct cs_struct*)handle_big; + } + else if (handle_lil != 0) + { + handle = (struct cs_struct*)handle_lil; + } + +#define PPC_FCMPUS 804 + + tempmc.csh = handle; + tempmc.Opcode = PPC_FCMPUS; + tempmc.flat_insn = &res->insn; + tempmc.flat_insn->detail = &res->detail; + + if (handle != 0) + { + handle->printer(&tempmc, &ss, handle->printer_info); + } + + // replace the 'fcmpu' with 'fcmpo' + first_space = strchr(ss.buffer, ' '); + strncpy(res->insn.op_str, first_space + 1, sizeof(res->insn.op_str)); +#endif + + strncpy(res->insn.mnemonic, "fcmpo", sizeof(res->insn.mnemonic)); + + // reset this to the target value res->insn.id = PPC_INS_BN_FCMPO; res->detail.ppc.op_count = 3; - strncpy(res->insn.mnemonic, "fcmpo", sizeof(res->insn.mnemonic)); } void ppc_xxpermr(uint32_t insword, decomp_result *res) @@ -76,10 +139,13 @@ void ppc_xxpermr(uint32_t insword, decomp_result *res) bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian) { uint32_t local_op = 0; - uint32_t insword = 0; + uint32_t insword = *(uint32_t *)data; if(bigendian == true) + { insword = bswap32(insword); + } + local_op = DoesQualifyForLocalDisassembly(data, bigendian); switch(local_op) diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index ee9e7f7f0..00bcdab01 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -28,14 +28,25 @@ int disas_instr_word(uint32_t instr_word, char *buf) { int rc = -1; - struct decomp_result res; + struct decomp_result res = {0}; 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, bigendian, &res, address_size_, cs_mode_local)) { - if(print_errors) printf("ERROR: powerpc_decompose()\n"); - goto cleanup; + if(print_errors) + { + if (DoesQualifyForLocalDisassembly((uint8_t*)&instr_word, !bigendian) != PPC_INS_INVALID) + { + size_t instsz = 4; + PerformLocalDisassembly((uint8_t*)&instr_word, 0, instsz, &res, !bigendian); + } + else + { + printf("ERROR: powerpc_decompose()\n"); + goto cleanup; + } + } } /* MEGA DETAILS, IF YOU WANT 'EM */ From 4d6c5a7e30065de5f564bef752065330db6dc653 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Wed, 8 May 2024 18:16:20 -0400 Subject: [PATCH 09/14] adding mips tester --- arch/mips/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/CMakeLists.txt b/arch/mips/CMakeLists.txt index b85248c84..822097152 100644 --- a/arch/mips/CMakeLists.txt +++ b/arch/mips/CMakeLists.txt @@ -46,3 +46,6 @@ if(BN_INTERNAL_BUILD) LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR} RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) endif() + +add_executable(mipstest mips/mips.c mips/test.c) +target_link_libraries(mipstest PRIVATE arch_mips) From f6c8b412ed5b078ac68271c0688b7e21a37931ec Mon Sep 17 00:00:00 2001 From: David Riusech Date: Wed, 8 May 2024 19:19:52 -0400 Subject: [PATCH 10/14] test rework, gonna add the capstone stuff --- arch/mips/mips/test.c | 81 ++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c index fbe8335a6..26ba599b1 100644 --- a/arch/mips/mips/test.c +++ b/arch/mips/mips/test.c @@ -7,10 +7,11 @@ b mips_disassemble #include #include +#include #include "mips.h" -int disassemble(uint32_t insword, uint64_t address, enum MipsVersion version, char *result) +int disassemble(uint32_t insword, uint64_t address, MipsVersion version, char *result) { int rc; Instruction instr; @@ -39,42 +40,72 @@ int disassemble(uint32_t insword, uint64_t address, enum MipsVersion version, ch exit(-1); \ } +void usage(char** av) +{ + printf("usage:\n"); + printf("\t%s [instruction_words]\n", av[0]); + printf("\t%s test\n", av[0]); + printf("example:\n"); + printf("\t%s 3c028081 68435a50 24445a50 6c830007\n", av[0]); + printf("\t%s test\n", av[0]); + exit(-1); +} + int main(int ac, char **av) { char instxt[4096]; + uint32_t insword = 0; + uint64_t baseaddr = 0; + int instindex = 0; + int c = 0; - if(ac == 1) { - printf("usage:\n"); - printf("\t%s [
] \n", av[0]); - printf("\t%s \n", av[0]); - printf("\t%s test\n", av[0]); - printf("examples:\n"); - printf("\t%s 0 14E00003\n", av[0]); - printf("\t%s 00405A58 14E00003\n", av[0]); - printf("\t%s test\n", av[0]); - exit(-1); + while ((c = getopt(ac, av, "a:")) != -1) + { + switch (c) + { + case 'a': + baseaddr = strtoull(optarg, NULL, 0x10); + break; + default: + usage(av); + goto cleanup; + } } - if(ac == 2 && !strcmp(av[1], "test")) { + if (optind >= ac) + { + usage(av); + goto cleanup; + } + + instindex = optind; + + if (ac == 2 && !strcmp(av[1], "test")) + { disassemble(0x14E00003, 0, MIPS_32, instxt); ASSERT(!strcmp(instxt, "bne\t$a3, $zero, 0x10")); - disassemble(0x14E00003, 0x405a58, MIPS_32, instxt); + disassemble(0x14E00003, 4, MIPS_32, instxt); ASSERT(!strcmp(instxt, "bne\t$a3, $zero, 0x405a68")); exit(0); } - uint64_t address = 0; - uint32_t insword = 0; - if(ac == 2) { - address = 0; - insword = strtoul(av[1], NULL, 16); - } - else if(ac == 3) { - address = strtoul(av[1], NULL, 16); - insword = strtoul(av[2], NULL, 16); - } + while (instindex < ac) + { + insword = strtoul(av[instindex], NULL, 16); - if(0 == disassemble(insword, address, MIPS_32, instxt)) { - printf("%08llX: %08X %s\n", address, insword, instxt); + if (0 == disassemble(insword, baseaddr, MIPS_32, instxt)) + { + printf("%08llX: %08X %s\n", baseaddr, insword, instxt); + } + else + { + printf("%08llX: %08X ??\n", baseaddr, insword); + } + + baseaddr += 4; + instindex++; } + +cleanup: + return 0; } From 19fe070b0a608af66afd5f326191ffe838ea3f5d Mon Sep 17 00:00:00 2001 From: David Riusech Date: Wed, 8 May 2024 20:40:20 -0400 Subject: [PATCH 11/14] adding test updates and new architecture mips3 to disassembly --- arch/mips/arch_mips.cpp | 35 +++++++++++++++++++++++++---------- arch/mips/mips/test.c | 24 ++++++++++++++++++++---- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 6a3d80e4d..8928ffae6 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -182,19 +182,24 @@ class MipsArchitecture: public Architecture size_t m_bits; BNEndianness m_endian; uint32_t m_enablePseudoOps; + MipsVersion version_overwrite; virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result) { + MipsVersion version = version_overwrite; + memset(&result, 0, sizeof(result)); - if (mips_decompose((uint32_t*)data, maxLen, &result, m_bits == 64 ? MIPS_64 : MIPS_32, addr, m_endian, m_enablePseudoOps) != 0) + if (m_bits == 64) + { + version = MIPS_64; + } + + if (mips_decompose((uint32_t*)data, maxLen, &result, version, addr, m_endian, m_enablePseudoOps) != 0) return false; return true; } - virtual size_t GetAddressSize() const override - { - return m_bits / 8; - } + virtual size_t GetAddressSize() const override { return m_bits / 8; } size_t InstructionHasBranchDelay(const Instruction& instr) { @@ -383,7 +388,8 @@ class MipsArchitecture: public Architecture } public: - MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits): Architecture(name), m_bits(bits), m_endian(endian) + MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits, MipsVersion version_in): + Architecture(name), m_bits(bits), m_endian(endian), version_overwrite(version_in) { Ref settings = Settings::Instance(); m_enablePseudoOps = settings->Get("arch.mips.disassembly.pseudoOps") ? 1 : 0; @@ -2228,12 +2234,14 @@ extern "C" { InitMipsSettings(); - Architecture* mipsel = new MipsArchitecture("mipsel32", LittleEndian, 32); - Architecture* mipseb = new MipsArchitecture("mips32", BigEndian, 32); - Architecture* mips64eb = new MipsArchitecture("mips64", BigEndian, 64); + Architecture* mipsel = new MipsArchitecture("mipsel32", LittleEndian, 32, MIPS_32); + Architecture* mipseb = new MipsArchitecture("mips32", BigEndian, 32, MIPS_32); + Architecture* mips3 = new MipsArchitecture("mips3", BigEndian, 32, MIPS_3); + Architecture* mips64eb = new MipsArchitecture("mips64", BigEndian, 64, MIPS_64); Architecture::Register(mipsel); Architecture::Register(mipseb); + Architecture::Register(mips3); Architecture::Register(mips64eb); /* calling conventions */ @@ -2242,9 +2250,11 @@ extern "C" MipsN64CallingConvention* n64BE = new MipsN64CallingConvention(mips64eb); mipsel->RegisterCallingConvention(o32LE); - mipseb->RegisterCallingConvention(o32BE); mipsel->SetDefaultCallingConvention(o32LE); + mipseb->RegisterCallingConvention(o32BE); mipseb->SetDefaultCallingConvention(o32BE); + mips3->RegisterCallingConvention(o32BE); + mips3->SetDefaultCallingConvention(o32BE); mips64eb->RegisterCallingConvention(n64BE); mips64eb->SetDefaultCallingConvention(n64BE); @@ -2252,17 +2262,21 @@ extern "C" MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb); mipsel->RegisterCallingConvention(linuxSyscallLE); mipseb->RegisterCallingConvention(linuxSyscallBE); + mips3->RegisterCallingConvention(linuxSyscallBE); mipsel->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipsel)); mipseb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipseb)); + mips3->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips3)); mips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips64eb)); /* function recognizers */ mipsel->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); mipseb->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); + mips3->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); mipsel->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mipseb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); + mips3->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); // Register the architectures with the binary format parsers so that they know when to use @@ -2278,6 +2292,7 @@ extern "C" BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS64, BigEndian, mips64eb); BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS32, LittleEndian, mipsel); BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS32, BigEndian, mipseb); + BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS32, BigEndian, mips3); BinaryViewType::RegisterArchitecture("PE", 0x166, LittleEndian, mipsel); return true; } diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c index 26ba599b1..2062db6e5 100644 --- a/arch/mips/mips/test.c +++ b/arch/mips/mips/test.c @@ -58,11 +58,27 @@ int main(int ac, char **av) uint64_t baseaddr = 0; int instindex = 0; int c = 0; + int version = MIPS_32; - while ((c = getopt(ac, av, "a:")) != -1) + while ((c = getopt(ac, av, "klmnoa:")) != -1) { switch (c) { + case 'k': + version = MIPS_64; + break; + case 'l': + version = MIPS_1; + break; + case 'm': + version = MIPS_2; + break; + case 'n': + version = MIPS_3; + break; + case 'o': + version = MIPS_4; + break; case 'a': baseaddr = strtoull(optarg, NULL, 0x10); break; @@ -82,9 +98,9 @@ int main(int ac, char **av) if (ac == 2 && !strcmp(av[1], "test")) { - disassemble(0x14E00003, 0, MIPS_32, instxt); + disassemble(0x14E00003, 0, version, instxt); ASSERT(!strcmp(instxt, "bne\t$a3, $zero, 0x10")); - disassemble(0x14E00003, 4, MIPS_32, instxt); + disassemble(0x14E00003, 4, version, instxt); ASSERT(!strcmp(instxt, "bne\t$a3, $zero, 0x405a68")); exit(0); } @@ -93,7 +109,7 @@ int main(int ac, char **av) { insword = strtoul(av[instindex], NULL, 16); - if (0 == disassemble(insword, baseaddr, MIPS_32, instxt)) + if (0 == disassemble(insword, baseaddr, version, instxt)) { printf("%08llX: %08X %s\n", baseaddr, insword, instxt); } From 9dcd245558cbc44e443a8773bc0a7354b870e495 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Thu, 9 May 2024 18:31:49 -0400 Subject: [PATCH 12/14] cmakelist needed patch so it could build on mac and windows for mips --- arch/mips/CMakeLists.txt | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/mips/CMakeLists.txt b/arch/mips/CMakeLists.txt index 822097152..296a9b1a6 100644 --- a/arch/mips/CMakeLists.txt +++ b/arch/mips/CMakeLists.txt @@ -47,5 +47,21 @@ if(BN_INTERNAL_BUILD) RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) endif() -add_executable(mipstest mips/mips.c mips/test.c) -target_link_libraries(mipstest PRIVATE arch_mips) +if (DEFINED FORCE_TEST) + + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + add_executable(mipstest mips/mips.c mips/test.c) + + target_compile_definitions(mipstest PRIVATE FORCE_TEST=1) + + set_target_properties(mipstest PROPERTIES + CXX_STANDARD 17 + CXX_VISIBILITY_PRESET hidden + CXX_STANDARD_REQUIRED ON + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) + + target_link_libraries(mipstest PRIVATE arch_mips) + endif() +endif() + From cd28c25374ba9b34be38f973f71e3ca329a1aa57 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Sat, 18 May 2024 03:06:59 -0400 Subject: [PATCH 13/14] pull and test_disasm --- arch/powerpc/test_disasm.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index 00bcdab01..bae7f1082 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -22,7 +22,8 @@ g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp dis int print_errors = 1; int cs_mode_local = 0; size_t address_size_ = 4; -bool bigendian = true; +// data in default with strtoul is little endian +bool littleendian = true; int disas_instr_word(uint32_t instr_word, char *buf) { @@ -33,13 +34,13 @@ int disas_instr_word(uint32_t instr_word, char *buf) struct cs_detail *detail = &(res.detail); struct cs_ppc *ppc = &(detail->ppc); - if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, bigendian, &res, address_size_, cs_mode_local)) { + if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, littleendian, &res, address_size_, cs_mode_local)) { if(print_errors) { - if (DoesQualifyForLocalDisassembly((uint8_t*)&instr_word, !bigendian) != PPC_INS_INVALID) + if (DoesQualifyForLocalDisassembly((uint8_t*)&instr_word, !littleendian) != PPC_INS_INVALID) { size_t instsz = 4; - PerformLocalDisassembly((uint8_t*)&instr_word, 0, instsz, &res, !bigendian); + PerformLocalDisassembly((uint8_t*)&instr_word, 0, instsz, &res, !littleendian); } else { From 82e05b33da7403c0f9ea134c55663ac851b4fb78 Mon Sep 17 00:00:00 2001 From: David Riusech Date: Sat, 19 Oct 2024 15:17:55 -0400 Subject: [PATCH 14/14] removing the ppc --- arch/powerpc/CMakeLists.txt | 28 ----- arch/powerpc/arch_ppc.cpp | 220 ++++++++++++++++++++++------------ arch/powerpc/disassembler.cpp | 162 ++----------------------- arch/powerpc/disassembler.h | 15 +-- arch/powerpc/il.cpp | 86 ++----------- arch/powerpc/test_disasm.cpp | 74 ++---------- 6 files changed, 177 insertions(+), 408 deletions(-) diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt index d148c690a..57a68f6ee 100644 --- a/arch/powerpc/CMakeLists.txt +++ b/arch/powerpc/CMakeLists.txt @@ -47,31 +47,3 @@ if(BN_INTERNAL_BUILD) LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR} RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) endif() - -if (DEFINED FORCE_TEST) - set(TEST_INLCUDE_LIST ) - set(TEST_LINK_DIRECTORIES ) - set(TEST_LINK_LIBRARIES capstone) - - if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") - add_executable(test_disasm test_disasm.cpp disassembler.cpp) - add_executable(test_asm test_asm.cpp assembler.cpp) - - target_compile_definitions(test_disasm PRIVATE FORCE_TEST=1) - - set_target_properties(test_disasm test_asm PROPERTIES - CXX_STANDARD 17 - CXX_VISIBILITY_PRESET hidden - CXX_STANDARD_REQUIRED ON - VISIBILITY_INLINES_HIDDEN ON - POSITION_INDEPENDENT_CODE ON) - - target_include_directories(test_disasm PRIVATE ${TEST_INCLUDE_LIST}) - target_link_directories(test_disasm PRIVATE ${TEST_LINK_DIRECTORIES}) - target_link_libraries(test_disasm PRIVATE ${TEST_LINK_LIBRARIES}) - - target_include_directories(test_asm PRIVATE ${TEST_INCLUDE_LIST}) - target_link_directories(test_asm PRIVATE ${TEST_LINK_DIRECTORIES}) - target_link_libraries(test_asm PRIVATE ${TEST_LINK_LIBRARIES}) - endif() -endif() diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp index e21df4766..b9087aefe 100644 --- a/arch/powerpc/arch_ppc.cpp +++ b/arch/powerpc/arch_ppc.cpp @@ -281,7 +281,6 @@ class PowerpcArchitecture: public Architecture { private: BNEndianness endian; - int cs_mode_local; size_t addressSize; /* this can maybe be moved to the API later */ @@ -298,11 +297,10 @@ class PowerpcArchitecture: public Architecture public: /* initialization list */ - PowerpcArchitecture(const char* name, BNEndianness endian_, size_t addressSize_=4, int cs_mode_=0): Architecture(name) + PowerpcArchitecture(const char* name, BNEndianness endian_, size_t addressSize_=4): Architecture(name) { endian = endian_; addressSize = addressSize_; - cs_mode_local = cs_mode_; } /*************************************************************************/ @@ -358,13 +356,13 @@ class PowerpcArchitecture: public Architecture return false; } - if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) { + if (DoesQualifyForLocalDisassembly(data)) { result.length = 4; return true; } /* decompose the instruction to get branch info */ - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8)) { MYLOG("ERROR: powerpc_decompose()\n"); return false; } @@ -457,56 +455,149 @@ class PowerpcArchitecture: public Architecture return true; } - bool PrintLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, vector &result, decomp_result* res) + bool DoesQualifyForLocalDisassembly(const uint8_t *data) { - (void)addr; - char buf[16]; - uint32_t local_op = PPC_INS_INVALID; + uint32_t insword = *(uint32_t *)data; + if(endian == BigEndian) + insword = bswap32(insword); + + // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo + uint32_t tmp = insword & 0xFC6007FF; + if (tmp==0xFC000040) + return true; + // 111100xxxxxxxxxxxxxxx00111010xxx <- xxpermr + if((insword & 0xFC0007F8) == 0xF00001D0) + return true; + // 000100xxxxxxxxxxxxxxxxxxx000110x <- psq_lx + // 000100xxxxxxxxxxxxxxxxxxx000111x <- psq_stx + // 000100xxxxxxxxxxxxxxxxxxx100110x <- psq_lux + // 000100xxxxxxxxxxxxxxxxxxx100111x <- psq_stux + tmp = insword & 0xFC00007E; + if (tmp==0x1000000C || tmp==0x1000000E || tmp==0x1000004C || tmp==0x1000004E) + return true; + // 000100xxxxxxxxxx00000xxxxx011000 <- ps_muls0 + // 000100xxxxxxxxxx00000xxxxx011001 <- ps_muls0. + // 000100xxxxxxxxxx00000xxxxx011010 <- ps_muls1 + // 000100xxxxxxxxxx00000xxxxx011011 <- ps_muls1. + tmp = insword & 0xFC00F83F; + if (tmp==0x10000018 || tmp==0x10000019 || tmp==0x1000001A || tmp==0x1000001B) + return true; + + return false; + } - struct cs_detail *detail = 0; - struct cs_ppc *ppc = 0; - struct cs_insn *insn = &(res->insn); + bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, vector &result) + { + (void)addr; - detail = &(res->detail); - ppc = &(detail->ppc); + if (len < 4) return false; + uint32_t insword = *(uint32_t *)data; + if(endian == BigEndian) + insword = bswap32(insword); - if (len < 4) - return false; len = 4; - local_op = DoesQualifyForLocalDisassembly(data, endian == BigEndian); - PerformLocalDisassembly(data, addr, len, res, endian == BigEndian); + char buf[16]; - switch (local_op) - { - case PPC_INS_BN_FCMPO: - result.emplace_back(InstructionToken, insn->mnemonic); + // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC" + uint32_t tmp = insword & 0xFC6007FF; + if (tmp==0xFC000040) { + result.emplace_back(InstructionToken, "fcmpo"); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "cr%d", ppc->operands[0].reg - PPC_REG_CR0); + snprintf(buf, sizeof(buf), "cr%d", (insword >> 23) & 7); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", ppc->operands[1].reg - PPC_REG_F0); + snprintf(buf, sizeof(buf), "f%d", (insword >> 16) & 31); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "f%d", ppc->operands[2].reg - PPC_REG_F0); + snprintf(buf, sizeof(buf), "f%d", (insword >> 11) & 31); result.emplace_back(RegisterToken, buf); - break; - case PPC_INS_BN_XXPERMR: - result.emplace_back(InstructionToken, insn->mnemonic); + return true; + } + + // 111100AAAAABBBBBCCCCC00011010BCA "xxpermr vsA,vsB,vsC" + if ((insword & 0xFC0007F8)==0xF00001D0) { + int a = ((insword & 0x3E00000)>>21)|((insword & 0x1)<<5); + int b = ((insword & 0x1F0000)>>16)|((insword & 0x4)<<3); + int c = ((insword & 0xF800)>>11)|((insword & 0x2)<<4); + result.emplace_back(InstructionToken, "xxpermr"); result.emplace_back(TextToken, " "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[0].reg - PPC_REG_VS0); + snprintf(buf, sizeof(buf), "vs%d", a); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[1].reg - PPC_REG_VS0); + snprintf(buf, sizeof(buf), "vs%d", b); result.emplace_back(RegisterToken, buf); result.emplace_back(OperandSeparatorToken, ", "); - snprintf(buf, sizeof(buf), "vs%d", ppc->operands[2].reg - PPC_REG_VS0); + snprintf(buf, sizeof(buf), "vs%d", c); result.emplace_back(RegisterToken, buf); - break; - default: - return false; + return true; } - return true; + + // 000100AAAAABBBBBCCCCCDEEE000110x psq_lx FREG,GPR,GPR,NUM,NUM + // 000100AAAAABBBBBCCCCCDEEE000111x psq_stx FREG,GPR,GPR,NUM,NUM + // 000100AAAAABBBBBCCCCCDEEE100110x psq_lux FREG,GPR,GPR,NUM,NUM + // 000100AAAAABBBBBCCCCCDEEE100111x psq_stux FREG,GPR,GPR,NUM,NUM + tmp = insword & 0xFC00007E; + if (tmp==0x1000000C || tmp==0x1000000E || tmp==0x1000004C || tmp==0x1000004E) { + switch(tmp) { + case 0x1000000C: + result.emplace_back(InstructionToken, "psq_lx"); + result.emplace_back(TextToken, " "); + break; + case 0x1000000E: result.emplace_back(InstructionToken, "psq_stx"); + result.emplace_back(TextToken, " "); + break; + case 0x1000004C: result.emplace_back(InstructionToken, "psq_lux"); + result.emplace_back(TextToken, " "); + break; + case 0x1000004E: result.emplace_back(InstructionToken, "psq_stux"); + result.emplace_back(TextToken, " "); + break; + } + snprintf(buf, sizeof(buf), "f%d", (insword & 0x3E00000) >> 21); + result.emplace_back(RegisterToken, buf); + result.emplace_back(OperandSeparatorToken, ", "); + snprintf(buf, sizeof(buf), "r%d", (insword & 0x1F0000) >> 16); + result.emplace_back(RegisterToken, buf); + result.emplace_back(OperandSeparatorToken, ", "); + snprintf(buf, sizeof(buf), "r%d", (insword & 0xF800) >> 11); + result.emplace_back(RegisterToken, buf); + result.emplace_back(OperandSeparatorToken, ", "); + tmp = (insword & 0x400)>>10; + snprintf(buf, sizeof(buf), "%d", tmp); + result.emplace_back(IntegerToken, buf, tmp, 1); + result.emplace_back(OperandSeparatorToken, ", "); + tmp = (insword & 0x380)>>7; + snprintf(buf, sizeof(buf), "%d", tmp); + result.emplace_back(IntegerToken, buf, tmp, 1); + return true; + } + + // 000100AAAAABBBBB00000CCCCC011000 ps_muls0 FREG,FREG,FREG + // 000100AAAAABBBBB00000CCCCC011001 ps_muls0. FREG,FREG,FREG + // 000100AAAAABBBBB00000CCCCC011010 ps_muls1 FREG,FREG,FREG + // 000100AAAAABBBBB00000CCCCC011011 ps_muls1. FREG,FREG,FREG + tmp = insword & 0xFC00F83F; + if (tmp==0x10000018 || tmp==0x10000019 || tmp==0x1000001A || tmp==0x1000001B) { + switch(tmp) { + case 0x10000018: result.emplace_back(InstructionToken, "ps_muls0"); break; + case 0x10000019: result.emplace_back(InstructionToken, "ps_muls0."); break; + case 0x1000001A: result.emplace_back(InstructionToken, "ps_muls1"); break; + case 0x1000001B: result.emplace_back(InstructionToken, "ps_muls1."); break; + } + result.emplace_back(TextToken, " "); + snprintf(buf, sizeof(buf), "f%d", (insword & 0x3E00000) >> 21); + result.emplace_back(RegisterToken, buf); + result.emplace_back(OperandSeparatorToken, ", "); + snprintf(buf, sizeof(buf), "f%d", (insword & 0x1F0000) >> 16); + result.emplace_back(RegisterToken, buf); + result.emplace_back(OperandSeparatorToken, ", "); + snprintf(buf, sizeof(buf), "f%d", (insword & 0x7C0) >> 6); + result.emplace_back(RegisterToken, buf); + return true; + } + + return false; } /* populate the vector result with InstructionTextToken @@ -530,12 +621,10 @@ class PowerpcArchitecture: public Architecture goto cleanup; } - if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) - { - // PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian); - return PrintLocalDisassembly(data, addr, len, result, &res); - } - if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { + if (DoesQualifyForLocalDisassembly(data)) + return PerformLocalDisassembly(data, addr, len, result); + + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8)) { MYLOG("ERROR: powerpc_decompose()\n"); goto cleanup; } @@ -642,7 +731,6 @@ class PowerpcArchitecture: public Architecture virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override { bool rc = false; - struct decomp_result res = {0}; if (len < 4) { MYLOG("ERROR: need at least 4 bytes\n"); @@ -653,16 +741,21 @@ class PowerpcArchitecture: public Architecture // MYLOG("%s(data, 0x%llX, 0x%zX, il)\n", __func__, addr, len); //} - if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) { - PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian); + struct decomp_result res; + + if (DoesQualifyForLocalDisassembly(data)) { + il.AddInstruction(il.Unimplemented()); + rc = true; + len = 4; + goto cleanup; } - else if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) { + + if(powerpc_decompose(data, 4, (uint32_t)addr, endian == LittleEndian, &res, GetAddressSize() == 8)) { MYLOG("ERROR: powerpc_decompose()\n"); il.AddInstruction(il.Undefined()); goto cleanup; } -getil: rc = GetLowLevelILForPPCInstruction(this, il, data, addr, &res, endian == LittleEndian); len = 4; @@ -714,7 +807,7 @@ class PowerpcArchitecture: public Architecture } auto liftOps = [&]() { - if ((op == LLIL_SUB) || (op == LLIL_FSUB)) + if (op == LLIL_SUB) { left = il.GetExprForRegisterOrConstant(operands[0], size); right = il.GetExprForRegisterOrConstant(operands[1], size); @@ -831,7 +924,7 @@ class PowerpcArchitecture: public Architecture virtual string GetRegisterName(uint32_t regId) override { - const char *result = powerpc_reg_to_str(regId, cs_mode_local); + const char *result = powerpc_reg_to_str(regId); if(result == NULL) result = ""; @@ -2380,15 +2473,6 @@ extern "C" Architecture* ppc = new PowerpcArchitecture("ppc", BigEndian); Architecture::Register(ppc); - Architecture* ppc_qpx = new PowerpcArchitecture("ppc_qpx", BigEndian, 4, CS_MODE_QPX); - Architecture::Register(ppc_qpx); - - Architecture* ppc_spe = new PowerpcArchitecture("ppc_spe", BigEndian, 4, CS_MODE_SPE); - Architecture::Register(ppc_spe); - - Architecture* ppc_ps = new PowerpcArchitecture("ppc_ps", BigEndian, 4, CS_MODE_PS); - Architecture::Register(ppc_ps); - Architecture* ppc64 = new PowerpcArchitecture("ppc64", BigEndian, 8); Architecture::Register(ppc64); @@ -2403,19 +2487,10 @@ extern "C" conv = new PpcSvr4CallingConvention(ppc); ppc->RegisterCallingConvention(conv); ppc->SetDefaultCallingConvention(conv); - ppc_qpx->RegisterCallingConvention(conv); - ppc_qpx->SetDefaultCallingConvention(conv); - ppc_spe->RegisterCallingConvention(conv); - ppc_spe->SetDefaultCallingConvention(conv); - ppc_ps->RegisterCallingConvention(conv); - ppc_ps->SetDefaultCallingConvention(conv); ppc64->RegisterCallingConvention(conv); ppc64->SetDefaultCallingConvention(conv); conv = new PpcLinuxSyscallCallingConvention(ppc); ppc->RegisterCallingConvention(conv); - ppc_qpx->RegisterCallingConvention(conv); - ppc_spe->RegisterCallingConvention(conv); - ppc_ps->RegisterCallingConvention(conv); ppc64->RegisterCallingConvention(conv); conv = new PpcSvr4CallingConvention(ppc_le); @@ -2429,15 +2504,9 @@ extern "C" /* function recognizer */ ppc->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); - ppc_qpx->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); - ppc_spe->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); - ppc_ps->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); ppc_le->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer()); ppc->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); - ppc_qpx->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); - ppc_spe->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); - ppc_ps->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); ppc_le->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler()); ppc_le->RegisterRelocationHandler("Mach-O", new PpcMachoRelocationHandler()); /* call the STATIC RegisterArchitecture with "Mach-O" @@ -2471,13 +2540,6 @@ extern "C" ppc /* the architecture */ ); - BinaryViewType::RegisterArchitecture( - "ELF", /* name of the binary view type */ - EM_PPC, /* id (key in m_arch map) */ - BigEndian, - ppc_ps /* the architecture */ - ); - BinaryViewType::RegisterArchitecture( "ELF", /* name of the binary view type */ EM_PPC64, /* id (key in m_arch map) */ diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp index 71c2f846d..480ab658b 100644 --- a/arch/powerpc/disassembler.cpp +++ b/arch/powerpc/disassembler.cpp @@ -12,158 +12,14 @@ architecture plugin picture. //#define MYLOG BinaryNinja::LogDebug #include "disassembler.h" -#include "util.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; -int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian) -{ - uint32_t insword = *(uint32_t *)data; - int result = PPC_INS_INVALID; - uint32_t tmp = 0; - - if(bigendian == true) - { - insword = bswap32(insword); - } - - // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo - tmp = insword & 0xFC6007FF; - if (tmp==0xFC000040) - result = PPC_INS_BN_FCMPO; - // 111100xxxxxxxxxxxxxxx00111010xxx <- xxpermr - if((insword & 0xFC0007F8) == 0xF00001D0) - result = PPC_INS_BN_XXPERMR; - - return result; -} - -void ppc_fcmpo(uint32_t insword, decomp_result *res) -{ - unsigned regtmp = 0; - - // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC" - regtmp = PPC_REG_CR0 + ((insword >> 23) & 7); - res->detail.ppc.operands[0].reg = (ppc_reg)(regtmp); - res->detail.ppc.operands[0].type = PPC_OP_REG; - - regtmp = PPC_REG_F0 + ((insword >> 16) & 31); - res->detail.ppc.operands[1].reg = (ppc_reg)(regtmp); - res->detail.ppc.operands[1].type = PPC_OP_REG; - - regtmp = PPC_REG_F0 + ((insword >> 11) & 31); - res->detail.ppc.operands[2].reg = (ppc_reg)(regtmp); - res->detail.ppc.operands[2].type = PPC_OP_REG; - - -#ifdef FORCE_TEST - SStream ss; - struct cs_struct* handle = 0; - struct MCInst tempmc = {0}; - char* first_space = 0; - - // SStream_Init(&ss); - ss.index = 0; - ss.buffer[0] = '\0'; - regtmp = PPC_REG_CR0 + ((insword >> 23) & 7); - tempmc.Operands[0].MachineOperandType = MCOperand::kRegister; - tempmc.Operands[0].Kind = 1; - tempmc.Operands[0].RegVal = regtmp; - regtmp = PPC_REG_F0 + ((insword >> 16) & 31); - tempmc.Operands[1].MachineOperandType = MCOperand::kRegister; - tempmc.Operands[1].Kind = 1; - tempmc.Operands[1].RegVal = regtmp; - regtmp = PPC_REG_F0 + ((insword >> 11) & 31); - tempmc.Operands[2].Kind = 1; - tempmc.Operands[2].MachineOperandType = MCOperand::kRegister; - tempmc.Operands[2].RegVal = regtmp; - - // temporarily set this so that print processing succeeds - res->insn.id = PPC_INS_FCMPU; - - if (handle_big != 0) - { - handle = (struct cs_struct*)handle_big; - } - else if (handle_lil != 0) - { - handle = (struct cs_struct*)handle_lil; - } - -#define PPC_FCMPUS 804 - - tempmc.csh = handle; - tempmc.Opcode = PPC_FCMPUS; - tempmc.flat_insn = &res->insn; - tempmc.flat_insn->detail = &res->detail; - - if (handle != 0) - { - handle->printer(&tempmc, &ss, handle->printer_info); - } - - // replace the 'fcmpu' with 'fcmpo' - first_space = strchr(ss.buffer, ' '); - strncpy(res->insn.op_str, first_space + 1, sizeof(res->insn.op_str)); -#endif - - strncpy(res->insn.mnemonic, "fcmpo", sizeof(res->insn.mnemonic)); - - // reset this to the target value - res->insn.id = PPC_INS_BN_FCMPO; - res->detail.ppc.op_count = 3; -} - -void ppc_xxpermr(uint32_t insword, decomp_result *res) -{ - // 111100AAAAABBBBBCCCCC00011010BCA "xxpermr vsA,vsB,vsC" - int a = ((insword & 0x3E00000)>>21)|((insword & 0x1)<<5); - int b = ((insword & 0x1F0000)>>16)|((insword & 0x4)<<3); - int c = ((insword & 0xF800)>>11)|((insword & 0x2)<<4); - - res->detail.ppc.operands[0].reg = (ppc_reg)(PPC_REG_VS0 + a); - res->detail.ppc.operands[0].type = PPC_OP_REG; - res->detail.ppc.operands[1].reg = (ppc_reg)(PPC_REG_VS0 + b); - res->detail.ppc.operands[1].type = PPC_OP_REG; - res->detail.ppc.operands[2].reg = (ppc_reg)(PPC_REG_VS0 + c); - res->detail.ppc.operands[2].type = PPC_OP_REG; - - res->insn.id = PPC_INS_BN_XXPERMR; - res->detail.ppc.op_count = 3; - strncpy(res->insn.mnemonic, "xxpermr", sizeof(res->insn.mnemonic)); -} - -bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian) -{ - uint32_t local_op = 0; - uint32_t insword = *(uint32_t *)data; - - if(bigendian == true) - { - insword = bswap32(insword); - } - - local_op = DoesQualifyForLocalDisassembly(data, bigendian); - - switch(local_op) - { - case PPC_INS_BN_FCMPO: - ppc_fcmpo(insword, res); - break; - case PPC_INS_BN_XXPERMR: - ppc_xxpermr(insword, res); - break; - default: - return false; - } - return true; -} - extern "C" int -powerpc_init(int cs_mode_arg) +powerpc_init(void) { int rc = -1; @@ -175,12 +31,12 @@ powerpc_init(int cs_mode_arg) } /* initialize capstone handle */ - if(cs_open(CS_ARCH_PPC, (cs_mode)((int)CS_MODE_BIG_ENDIAN | cs_mode_arg), &handle_big) != CS_ERR_OK) { + 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)((int)CS_MODE_LITTLE_ENDIAN | cs_mode_arg), &handle_lil) != CS_ERR_OK) { + if(cs_open(CS_ARCH_PPC, CS_MODE_LITTLE_ENDIAN, &handle_lil) != CS_ERR_OK) { MYLOG("ERROR: cs_open()\n"); goto cleanup; } @@ -213,13 +69,13 @@ powerpc_release(void) extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, - struct decomp_result *res, bool is_64bit, int cs_mode_arg) + struct decomp_result *res, bool is_64bit) { int rc = -1; res->status = STATUS_ERROR_UNSPEC; if(!handle_lil) { - powerpc_init(cs_mode_arg); + powerpc_init(); } //typedef struct cs_insn { @@ -264,7 +120,6 @@ powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, // } cs_ppc_op; csh handle; - struct cs_struct *hand_tmp = 0; cs_insn *insn = 0; /* instruction information cs_disasm() will allocate array of cs_insn here */ @@ -274,9 +129,6 @@ powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end, if(lil_end) handle = handle_lil; res->handle = handle; - hand_tmp = (struct cs_struct *)handle; - hand_tmp->mode = (cs_mode)((int)hand_tmp->mode | cs_mode_arg); - /* call */ size_t n = cs_disasm(handle, data, size, addr, 1, &insn); if(n != 1) { @@ -322,10 +174,10 @@ powerpc_disassemble(struct decomp_result *res, char *buf, size_t len) } extern "C" const char * -powerpc_reg_to_str(uint32_t rid, int cs_mode_arg) +powerpc_reg_to_str(uint32_t rid) { if(!handle_lil) { - powerpc_init(cs_mode_arg); + powerpc_init(); } return cs_reg_name(handle_lil, rid); diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h index 16a9a3430..e1d3ca556 100644 --- a/arch/powerpc/disassembler.h +++ b/arch/powerpc/disassembler.h @@ -23,7 +23,6 @@ Then some helpers if you need them: /* capstone stuff /usr/local/include/capstone */ #include "capstone/capstone.h" -#include "capstone/cs_priv.h" #include "capstone/ppc.h" //***************************************************************************** @@ -33,11 +32,6 @@ enum ppc_status_t { STATUS_ERROR_UNSPEC=-1, STATUS_SUCCESS=0, STATUS_UNDEF_INSTR }; -typedef enum ppc_insn_bn { - PPC_INS_BN_FCMPO = PPC_INS_ENDING+1, - PPC_INS_BN_XXPERMR, - PPC_INS_BN_ENDING -} ppc_insn_bn; /* operand type */ enum operand_type_t { REG, VAL, LABEL }; @@ -65,14 +59,11 @@ struct decomp_result //***************************************************************************** // function prototypes //***************************************************************************** -int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian); -bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian); - -extern "C" int powerpc_init(int); +extern "C" int powerpc_init(void); extern "C" void powerpc_release(void); extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr, - bool lil_end, struct decomp_result *result, bool is_64bit, int cs_mode); + bool lil_end, struct decomp_result *result, bool is_64bit); extern "C" int powerpc_disassemble(struct decomp_result *, char *buf, size_t len); -extern "C" const char *powerpc_reg_to_str(uint32_t rid, int); +extern "C" const char *powerpc_reg_to_str(uint32_t rid); diff --git a/arch/powerpc/il.cpp b/arch/powerpc/il.cpp index 8cd9b104d..76cf74199 100644 --- a/arch/powerpc/il.cpp +++ b/arch/powerpc/il.cpp @@ -451,9 +451,6 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, { int i; bool rc = true; - struct cs_insn *insn = 0; - struct cs_detail *detail = 0; - struct cs_ppc *ppc = 0; /* bypass capstone path for *all* branching instructions; capstone * is too difficult to work with and is outright broken for some @@ -462,9 +459,9 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, if (LiftBranches(arch, il, data, addr, le)) return true; - insn = &(res->insn); - detail = &(res->detail); - ppc = &(detail->ppc); + struct cs_insn *insn = &(res->insn); + struct cs_detail *detail = &(res->detail); + struct cs_ppc *ppc = &(detail->ppc); /* There is a simplifying reduction available for: * rlwinm , , , , @@ -717,26 +714,11 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, // il.AddInstruction(ei2); // break; - // TODO: high level IL is sometimes assuming incorrect variables, and setting floating points to - // standard registers. - // TODO: high level IL is accidentilly adding an extra subtract operand and assigning it to no one. - // TODO: final assignment for the fcmp is whether or not the sub is 0, not greater than 0. - case PPC_INS_FCMPU: - REQUIRE3OPS - ei0 = il.FloatSub(4, operToIL(il, oper1), operToIL(il, oper2), crxToFlagWriteType(oper0->reg)); - il.AddInstruction(ei0); - break; - - case PPC_INS_BN_FCMPO: - REQUIRE3OPS - ei0 = il.FloatSub(4, operToIL(il, oper1), operToIL(il, oper2), crxToFlagWriteType(oper0->reg)); - il.AddInstruction(ei0); - break; - - case PPC_INS_FMR: - REQUIRE2OPS - il.AddInstruction(il.SetRegister(4, oper0->reg, operToIL(il, oper1))); - break; + // case PPC_INS_FCMPU: + // REQUIRE3OPS + // ei0 = il.FloatSub(4, il.Unimplemented(), il.Unimplemented(), (oper0->reg - PPC_REG_CR0) + IL_FLAGWRITE_INVL0); + // il.AddInstruction(ei0); + // break; case PPC_INS_CRAND: case PPC_INS_CRANDC: @@ -1713,53 +1695,6 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, il.AddInstruction(il.Trap(0)); break; - case PPC_INS_STFS: - REQUIRE2OPS - ei0 = il.Store(4, - operToIL(il, oper1), - operToIL(il, oper0) - ); - il.AddInstruction(ei0); - - break; - - case PPC_INS_STFD: - REQUIRE2OPS - ei0 = il.Store(8, - operToIL(il, oper1), - operToIL(il, oper0) - ); - il.AddInstruction(ei0); - - break; - - case PPC_INS_LFS: - REQUIRE2OPS - ei0 = operToIL(il, oper1); // d(rA) or 0 - ei0 = il.Load(4, ei0); // [d(rA)] - ei0 = il.SetRegister(4, oper0->reg, ei0); // rD = [d(rA)] - il.AddInstruction(ei0); - - break; - - case PPC_INS_LFD: - REQUIRE2OPS - ei0 = operToIL(il, oper1); // d(rA) or 0 - ei0 = il.Load(8, ei0); // [d(rA)] - ei0 = il.SetRegister(8, oper0->reg, ei0); // rD = [d(rA)] - il.AddInstruction(ei0); - - break; - - // case PPC_INS_FCMPO: /* compare (signed) word(32-bit) */ - // REQUIRE2OPS - // ei0 = operToIL(il, oper2 ? oper1 : oper0); - // ei1 = operToIL(il, oper2 ? oper2 : oper1); - // ei2 = il.Sub(4, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0)); - // il.AddInstruction(ei2); - // break; - - case PPC_INS_BCL: case PPC_INS_BCLR: case PPC_INS_BCLRL: @@ -1972,6 +1907,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_FDIVS: case PPC_INS_FMADD: case PPC_INS_FMADDS: + case PPC_INS_FMR: case PPC_INS_FMSUB: case PPC_INS_FMSUBS: case PPC_INS_FMUL: @@ -2001,11 +1937,13 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_ISYNC: case PPC_INS_LDARX: case PPC_INS_LDBRX: + case PPC_INS_LFD: case PPC_INS_LFDU: case PPC_INS_LFDUX: case PPC_INS_LFDX: case PPC_INS_LFIWAX: case PPC_INS_LFIWZX: + case PPC_INS_LFS: case PPC_INS_LFSU: case PPC_INS_LFSUX: case PPC_INS_LFSX: @@ -2069,10 +2007,12 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il, case PPC_INS_SLBMTE: case PPC_INS_STDBRX: case PPC_INS_STDCX: + case PPC_INS_STFD: case PPC_INS_STFDU: case PPC_INS_STFDUX: case PPC_INS_STFDX: case PPC_INS_STFIWX: + case PPC_INS_STFS: case PPC_INS_STFSU: case PPC_INS_STFSUX: case PPC_INS_STFSX: diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp index bae7f1082..b893d2ab9 100644 --- a/arch/powerpc/test_disasm.cpp +++ b/arch/powerpc/test_disasm.cpp @@ -15,39 +15,22 @@ g++ -std=c++11 -O0 -g -I capstone/include -L./build/capstone test_disasm.cpp dis #include #include -#include - #include "disassembler.h" int print_errors = 1; -int cs_mode_local = 0; -size_t address_size_ = 4; -// data in default with strtoul is little endian -bool littleendian = true; int disas_instr_word(uint32_t instr_word, char *buf) { int rc = -1; - struct decomp_result res = {0}; + 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, littleendian, &res, address_size_, cs_mode_local)) { - if(print_errors) - { - if (DoesQualifyForLocalDisassembly((uint8_t*)&instr_word, !littleendian) != PPC_INS_INVALID) - { - size_t instsz = 4; - PerformLocalDisassembly((uint8_t*)&instr_word, 0, instsz, &res, !littleendian); - } - else - { - printf("ERROR: powerpc_decompose()\n"); - goto cleanup; - } - } + 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 */ @@ -123,52 +106,21 @@ int disas_instr_word(uint32_t instr_word, char *buf) return rc; } -void usage() -{ - printf("send argument \"repl\" or \"speed\"\n"); -} - int main(int ac, char **av) { int rc = -1; char buf[256]; - int index; - char* disasm_cmd = 0; - int c; - -#define BATCH 10000000 - opterr = 0; - - while ((c = getopt(ac, av, "qsp")) != -1) - { - switch (c) - { - case 'q': - cs_mode_local = CS_MODE_QPX; - break; - case 's': - cs_mode_local = CS_MODE_SPE; - break; - case 'p': - cs_mode_local = CS_MODE_PS; - break; - default: - usage(); - goto cleanup; - } - } - if (optind >= ac) - { - usage(); - goto cleanup; - } + #define BATCH 10000000 - disasm_cmd = av[optind]; + powerpc_init(); - powerpc_init(cs_mode_local); + if(ac <= 1) { + printf("send argument \"repl\" or \"speed\"\n"); + goto cleanup; + } - if(!strcasecmp(disasm_cmd, "repl")) { + if(!strcasecmp(av[1], "repl")) { printf("REPL mode!\n"); printf("example inputs (write the words as if after endian fetch):\n"); printf("93e1fffc\n"); @@ -196,7 +148,7 @@ int main(int ac, char **av) printf("%s\n", buf); } } - else if(!strcasecmp(disasm_cmd, "speed")) { + 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; @@ -215,7 +167,7 @@ int main(int ac, char **av) printf("current rate: %f instructions per second\n", (float)BATCH/ellapsed); } } - else if(!strcasecmp(disasm_cmd, "speed2")) { + 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;