diff --git a/.github/workflows/build-wheels-publish.yml b/.github/workflows/build-wheels-publish.yml index b331f38494..25182eb5d3 100644 --- a/.github/workflows/build-wheels-publish.yml +++ b/.github/workflows/build-wheels-publish.yml @@ -134,7 +134,7 @@ jobs: python3 -m pip install -U pip wheel python3 -m wheel tags --python-tag='py2' --abi-tag=none wheelhouse/*cp37*.whl - - uses: LizardByte/actions/actions/setup_python@v2025.715.25226 + - uses: LizardByte/actions/actions/setup_python@v2026.212.22356 if: (runner.os == 'Linux' && (matrix.arch == 'x86_64' || matrix.arch == 'aarch64') && matrix.cibw_build == 'cp*-manylinux*') || (runner.os == 'macOS' && matrix.arch == 'arm64') || (runner.os == 'Windows' && matrix.arch == 'AMD64') with: python-version: 2.7 diff --git a/bindings/python/tests/test_ppc.py b/bindings/python/tests/test_ppc.py index 2bb4fe3aaa..3d75b37667 100755 --- a/bindings/python/tests/test_ppc.py +++ b/bindings/python/tests/test_ppc.py @@ -57,5 +57,42 @@ def test_ppc(): print("ERROR: %s" % e) +def test_ppc64(): + print("Emulate PPC64 code") + try: + # Initialize emulator in PPC64 EB mode + mu = Uc(UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, PPC_CODE) + + # initialize machine registers + mu.reg_write(UC_PPC_REG_3, 0x1234) + mu.reg_write(UC_PPC_REG_6, 0x6789) + mu.reg_write(UC_PPC_REG_26, 0x5555) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(PPC_CODE)) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + r26 = mu.reg_read(UC_PPC_REG_26) + print(">>> r26 = 0x%x" % r26) + + except UcError as e: + print("ERROR: %s" % e) + + if __name__ == '__main__': test_ppc() + test_ppc64() diff --git a/bindings/rust/unicorn-engine/src/tests/ppc.rs b/bindings/rust/unicorn-engine/src/tests/ppc.rs index 44ff88e1d5..f2b0bc3640 100644 --- a/bindings/rust/unicorn-engine/src/tests/ppc.rs +++ b/bindings/rust/unicorn-engine/src/tests/ppc.rs @@ -89,3 +89,24 @@ fn test_ppc32_spr_time() { uc.emu_start(CODE_START, CODE_START + code.len() as u64, 0, 0) .unwrap(); } + +#[test] +fn test_ppc64_add() { + let code = [ + 0x7f, 0x46, 0x1a, 0x14, // add 26, 6, 3 + ]; + let r3: u64 = 42; + let r6: u64 = 1337; + + let mut uc = uc_common_setup(Arch::PPC, Mode::PPC64 | Mode::BIG_ENDIAN, None, &code, ()); + + uc.reg_write(RegisterPPC::R3, r3).unwrap(); + uc.reg_write(RegisterPPC::R6, r6).unwrap(); + + uc.emu_start(CODE_START, CODE_START + code.len() as u64, 0, 0) + .unwrap(); + + let reg = uc.reg_read(RegisterPPC::R26).unwrap(); + + assert_eq!(reg, 1379); +} diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index b4ffc6bc75..0b38b2cd69 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -143,7 +143,7 @@ typedef enum uc_mode { // ppc UC_MODE_PPC32 = 1 << 2, // 32-bit mode - UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) + UC_MODE_PPC64 = 1 << 3, // 64-bit mode UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) diff --git a/qemu/target/ppc/translate_init.inc.c b/qemu/target/ppc/translate_init.inc.c index d2fb1974ad..988f74e148 100644 --- a/qemu/target/ppc/translate_init.inc.c +++ b/qemu/target/ppc/translate_init.inc.c @@ -11024,10 +11024,13 @@ PowerPCCPU *cpu_ppc_init(struct uc_struct *uc) memset(cpu, 0, sizeof(*cpu)); #ifdef TARGET_PPC64 if (uc->cpu_model == INT_MAX) { - uc->cpu_model = UC_CPU_PPC64_POWER10_V1_0 + UC_CPU_PPC32_7457A_V1_2 + 1; // power10_v1.0 - } else if (uc->cpu_model + UC_CPU_PPC32_7457A_V1_2 + 1 >= ARRAY_SIZE(ppc_cpus)) { - free(cpu); - return NULL; + uc->cpu_model = UC_CPU_PPC64_970_V2_2 + UC_CPU_PPC32_7457A_V1_2 + 1; // 970_v2.2 + } else { + uc->cpu_model += UC_CPU_PPC32_7457A_V1_2 + 1; + if (uc->cpu_model >= ARRAY_SIZE(ppc_cpus)) { + free(cpu); + return NULL; + } } #else if (uc->cpu_model == INT_MAX) { diff --git a/samples/sample_ppc.c b/samples/sample_ppc.c index cd09ae5e75..205c35223f 100644 --- a/samples/sample_ppc.c +++ b/samples/sample_ppc.c @@ -82,9 +82,65 @@ static void test_ppc(void) uc_close(uc); } +static void test_ppc64(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + uint64_t r3 = 0x1234; // R3 register + uint64_t r6 = 0x6789; // R6 register + uint64_t r26 = 0x8877; // R26 register (result) + + printf("Emulate PPC64 code\n"); + + // Initialize emulator in PPC64 mode + err = uc_open(UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", err, + uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, PPC_CODE, sizeof(PPC_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_PPC_REG_3, &r3); + uc_reg_write(uc, UC_PPC_REG_6, &r6); + uc_reg_write(uc, UC_PPC_REG_26, &r26); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(PPC_CODE) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + return; + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_PPC_REG_26, &r26); + printf(">>> r26 = 0x%" PRIx64 "\n", r26); + + // close engine when done + uc_close(uc); +} + int main(int argc, char **argv, char **envp) { test_ppc(); + test_ppc64(); return 0; } diff --git a/tests/unit/test_ppc.c b/tests/unit/test_ppc.c index 5463b21f0e..1fc6cdc2fa 100644 --- a/tests/unit/test_ppc.c +++ b/tests/unit/test_ppc.c @@ -119,9 +119,207 @@ static void test_ppc32_spr_time(void) OK(uc_close(uc)); } + +static void test_ppc64_add(void) +{ + uc_engine *uc; + char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3 + uint64_t reg; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + reg = 42; + OK(uc_reg_write(uc, UC_PPC_REG_3, ®)); + reg = 1337; + OK(uc_reg_write(uc, UC_PPC_REG_6, ®)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_26, ®)); + + TEST_CHECK(reg == 1379); + + OK(uc_close(uc)); +} + +static void test_ppc64_add_large(void) +{ + uc_engine *uc; + char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3 + uint64_t reg; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + reg = 0x100000000ULL; + OK(uc_reg_write(uc, UC_PPC_REG_3, ®)); + reg = 0x200000000ULL; + OK(uc_reg_write(uc, UC_PPC_REG_6, ®)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_26, ®)); + + TEST_CHECK(reg == 0x300000000ULL); + + OK(uc_close(uc)); +} + +static void test_ppc64_fadd(void) +{ + uc_engine *uc; + char code[] = "\xfc\xc4\x28\x2a"; // fadd 6, 4, 5 + uint64_t r_msr; + uint64_t r_fpr4, r_fpr5, r_fpr6; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + OK(uc_reg_read(uc, UC_PPC_REG_MSR, &r_msr)); + r_msr |= (1 << 13); // enable FP + r_msr |= (1ULL << 63); // SF bit + OK(uc_reg_write(uc, UC_PPC_REG_MSR, &r_msr)); + + r_fpr4 = 0xC053400000000000ul; + r_fpr5 = 0x400C000000000000ul; + OK(uc_reg_write(uc, UC_PPC_REG_FPR4, &r_fpr4)); + OK(uc_reg_write(uc, UC_PPC_REG_FPR5, &r_fpr5)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_FPR6, &r_fpr6)); + + TEST_CHECK(r_fpr6 == 0xC052600000000000ul); + + OK(uc_close(uc)); +} + +static void test_ppc64_sc_cb(uc_engine *uc, uint32_t intno, void *data) +{ + uc_emu_stop(uc); + return; +} + +static void test_ppc64_sc(void) +{ + uc_engine *uc; + char code[] = "\x44\x00\x00\x02"; // sc + uint64_t r_pc; + uc_hook h; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + OK(uc_hook_add(uc, &h, UC_HOOK_INTR, test_ppc64_sc_cb, NULL, 1, 0)); + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_PC, &r_pc)); + + TEST_CHECK(r_pc == code_start + 4); + + OK(uc_close(uc)); +} + +static void test_ppc64_cr(void) +{ + uc_engine *uc; + uint32_t r_cr = 0x12345678; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + NULL, 0); + + OK(uc_reg_write(uc, UC_PPC_REG_CR, &r_cr)); + r_cr = 0; + OK(uc_reg_read(uc, UC_PPC_REG_CR, &r_cr)); + + TEST_CHECK(r_cr == 0x12345678); + + OK(uc_close(uc)); +} + +static void test_ppc64_ld(void) +{ + uc_engine *uc; + char code[] = "\xe8\x64\x00\x00"; // ld 3, 0(4) + uint64_t reg; + char data[] = "\x12\x34\x56\x78\x9A\xBC\xDE\xF0"; + uint64_t data_addr = 0x2000; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + OK(uc_mem_write(uc, data_addr, data, sizeof(data) - 1)); + + reg = data_addr; + OK(uc_reg_write(uc, UC_PPC_REG_4, ®)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_3, ®)); + + TEST_CHECK(reg == 0x123456789ABCDEF0ULL); + + OK(uc_close(uc)); +} + +static void test_ppc64_std(void) +{ + uc_engine *uc; + char code[] = "\xf8\x64\x00\x00"; // std 3, 0(4) + uint64_t reg; + uint64_t data_addr = 0x2000; + uint8_t buf[8]; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + reg = 0xAABBCCDD11223344ULL; + OK(uc_reg_write(uc, UC_PPC_REG_3, ®)); + reg = data_addr; + OK(uc_reg_write(uc, UC_PPC_REG_4, ®)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_mem_read(uc, data_addr, buf, 8)); + + TEST_CHECK(buf[0] == 0xAA); + TEST_CHECK(buf[1] == 0xBB); + TEST_CHECK(buf[2] == 0xCC); + TEST_CHECK(buf[3] == 0xDD); + TEST_CHECK(buf[4] == 0x11); + TEST_CHECK(buf[5] == 0x22); + TEST_CHECK(buf[6] == 0x33); + TEST_CHECK(buf[7] == 0x44); + + OK(uc_close(uc)); +} + +static void test_ppc64_spr_time(void) +{ + char code[] = ("\x7c\x76\x02\xa6" // mfspr r3, DEC + "\x7c\x6c\x42\xa6" // mfspr r3, TBL + ); + + uc_engine *uc; + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN, + code, sizeof(code) - 1); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + OK(uc_close(uc)); +} + TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, {"test_ppc32_fadd", test_ppc32_fadd}, {"test_ppc32_sc", test_ppc32_sc}, {"test_ppc32_cr", test_ppc32_cr}, {"test_ppc32_spr_time", test_ppc32_spr_time}, + {"test_ppc64_add", test_ppc64_add}, + {"test_ppc64_add_large", test_ppc64_add_large}, + {"test_ppc64_fadd", test_ppc64_fadd}, + {"test_ppc64_sc", test_ppc64_sc}, + {"test_ppc64_cr", test_ppc64_cr}, + {"test_ppc64_ld", test_ppc64_ld}, + {"test_ppc64_std", test_ppc64_std}, + {"test_ppc64_spr_time", test_ppc64_spr_time}, {NULL, NULL}}; \ No newline at end of file