Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-wheels-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions bindings/python/tests/test_ppc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
21 changes: 21 additions & 0 deletions bindings/rust/unicorn-engine/src/tests/ppc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion include/unicorn/unicorn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
11 changes: 7 additions & 4 deletions qemu/target/ppc/translate_init.inc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
56 changes: 56 additions & 0 deletions samples/sample_ppc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
198 changes: 198 additions & 0 deletions tests/unit/test_ppc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
reg = 1337;
OK(uc_reg_write(uc, UC_PPC_REG_6, &reg));

OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));

OK(uc_reg_read(uc, UC_PPC_REG_26, &reg));

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));
reg = 0x200000000ULL;
OK(uc_reg_write(uc, UC_PPC_REG_6, &reg));

OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));

OK(uc_reg_read(uc, UC_PPC_REG_26, &reg));

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, &reg));

OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));

OK(uc_reg_read(uc, UC_PPC_REG_3, &reg));

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));
reg = data_addr;
OK(uc_reg_write(uc, UC_PPC_REG_4, &reg));

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}};
Loading