From 6ccf4d4e81b49d07485087315fb41817497df8f3 Mon Sep 17 00:00:00 2001 From: Kubo Takehiro Date: Wed, 19 Oct 2022 19:04:11 +0900 Subject: [PATCH] Support PowerPC fix #25 --- README.md | 5 ++ src/linux/elf.c | 12 +++++ src/linux/injector_internal.h | 9 ++++ src/linux/remote_call.c | 97 ++++++++++++++++++++++++++++++++++- src/linux/util.c | 4 ++ 5 files changed, 125 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60c1d4d..5bbe2a5 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,11 @@ See [`Usage` section and `Sample` section in linux-inject][`inject`] and substit *1: tested on [debian 11 mips64el](https://www.debian.org/releases/bullseye/mips64el/ch02s01.en.html#idm271) on [QEMU](https://www.qemu.org/). *2: failure with `64-bit target process isn't supported by 32-bit process`. +* PowerPC + + * **ppc64le** (tested on [alpine 3.16.2 ppc64le](https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/ppc64le/) on [QEMU](https://www.qemu.org/)) + * **powerpc (big endian)** (tested on [ubuntu 16.04 powerpc](https://old-releases.ubuntu.com/releases/xenial/) on [QEMU](https://www.qemu.org/) + * RISC-V * **riscv64** (tested on [Ubuntu 22.04.1 riscv64 on QEMU](https://wiki.ubuntu.com/RISC-V#Booting_with_QEMU)) diff --git a/src/linux/elf.c b/src/linux/elf.c index 4c76995..19a4bdc 100644 --- a/src/linux/elf.c +++ b/src/linux/elf.c @@ -218,6 +218,18 @@ int injector__collect_libc_information(injector_t *injector) injector->sys_munmap = 4000 + 91; } break; + case EM_PPC64: + injector->arch = ARCH_POWERPC_64; + injector->sys_mmap = 90; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; + case EM_PPC: + injector->arch = ARCH_POWERPC; + injector->sys_mmap = 90; + injector->sys_mprotect = 125; + injector->sys_munmap = 91; + break; #ifdef EM_RISCV case EM_RISCV: if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { diff --git a/src/linux/injector_internal.h b/src/linux/injector_internal.h index 5bf2b15..bc74c24 100644 --- a/src/linux/injector_internal.h +++ b/src/linux/injector_internal.h @@ -48,6 +48,11 @@ #define user_regs_struct pt_regs #endif +#ifdef __powerpc__ +#include +#define user_regs_struct pt_regs +#endif + #ifdef __riscv #include #endif @@ -76,6 +81,8 @@ typedef enum { ARCH_MIPS_64, ARCH_MIPS_N32, ARCH_MIPS_O32, + ARCH_POWERPC_64, + ARCH_POWERPC, ARCH_RISCV_64, ARCH_RISCV_32, } arch_t; @@ -88,6 +95,8 @@ typedef union { uint32_t u32[2]; #elif defined(__mips__) uint32_t u32[4]; +#elif defined(__powerpc__) + uint32_t u32[2]; #elif defined(__riscv) uint32_t u32[2]; #endif diff --git a/src/linux/remote_call.c b/src/linux/remote_call.c index 08d58af..8d3e5d7 100644 --- a/src/linux/remote_call.c +++ b/src/linux/remote_call.c @@ -112,6 +112,48 @@ static void print_regs(const injector_t *injector, const struct pt_regs *regs) #define PRINT_REGS(injector, regs) print_regs((injector), (regs)) #endif /* __mips__ */ + +#ifdef __powerpc__ +static void print_regs(const injector_t *injector, const struct pt_regs *regs) +{ +#undef WIDTH +#ifdef __LP64__ +#define WIDTH "016" +#define softe_or_mq_str "softe" +#define softe_or_mq softe +#else +#define WIDTH "08" +#define softe_or_mq_str "mq " +#define softe_or_mq mq +#endif + DEBUG(" Registers:\n"); + DEBUG(" gpr0 gpr1 gpr2 gpr3 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[0], regs->gpr[1], regs->gpr[2], regs->gpr[3]); + DEBUG(" gpr4 gpr5 gpr6 gpr7 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); + DEBUG(" gpr8 gpr9 gpr10 gpr11 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); + DEBUG(" gpr12 gpr13 gpr14 gpr15 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); + DEBUG(" gpr16 gpr17 gpr18 gpr19 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); + DEBUG(" gpr20 gpr21 gpr22 gpr23 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); + DEBUG(" gpr24 gpr25 gpr26 gpr27 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); + DEBUG(" gpr28 gpr29 gpr30 gpr31 : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); + DEBUG(" nip msr orig_gpr3 ctr : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->nip, regs->msr, regs->orig_gpr3, regs->ctr); + DEBUG(" link xer ccr "softe_or_mq_str" : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->link, regs->xer, regs->ccr, regs->softe_or_mq); + DEBUG(" trap dar dsisr result : %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx %"WIDTH"lx\n", + regs->trap, regs->dar, regs->dsisr, regs->result); +#undef WIDTH +} +#define PRINT_REGS(injector, regs) print_regs((injector), (regs)) +#endif + #ifdef __riscv #define REG_RA 1 #define REG_T1 6 @@ -176,7 +218,7 @@ int injector__call_syscall(const injector_t *injector, long *retval, long syscal long arg1, arg2, arg3, arg4, arg5, arg6; va_list ap; int rv; -#if !defined(__mips__) +#if !defined(__mips__) && !defined(__powerpc__) user_reg_t *reg_return = NULL; #if defined(__aarch64__) uint32_t *reg32_return = NULL; @@ -340,6 +382,26 @@ int injector__call_syscall(const injector_t *injector, long *retval, long syscal } break; #endif +#if defined(__powerpc__) +#ifdef __LP64__ + case ARCH_POWERPC_64: +#endif + case ARCH_POWERPC: + /* setup instructions */ + code.u32[0] = 0x44000002; /* sc */ + code.u32[1] = 0x7fe00008; /* trap */ + code_size = 2 * 4; + /* setup registers */ + regs.nip = injector->code_addr; + regs.gpr[PT_R0] = syscall_number; + regs.gpr[PT_R3] = arg1; + regs.gpr[PT_R4] = arg2; + regs.gpr[PT_R5] = arg3; + regs.gpr[PT_R6] = arg4; + regs.gpr[PT_R7] = arg5; + regs.gpr[PT_R8] = arg6; + break; +#endif #if defined(__riscv) #ifdef __LP64__ case ARCH_RISCV_64: @@ -383,7 +445,15 @@ int injector__call_syscall(const injector_t *injector, long *retval, long syscal errno = (int)regs.regs[REG_V0]; *retval = -1; } -#else /* defined(__mips__) */ +#elif defined(__powerpc__) + /* https://github.com/strace/strace/blob/v5.19/src/linux/powerpc/get_error.c#L21-L26 */ + if (regs.ccr & 0x10000000) { + errno = (int)regs.gpr[PT_R3]; + *retval = -1; + } else { + *retval = (long)regs.gpr[PT_R3]; + } +#else #if defined(__aarch64__) if (reg32_return != NULL) { if (*reg32_return <= -4096u) { @@ -582,6 +652,29 @@ int injector__call_function(const injector_t *injector, long *retval, long funct reg_return = ®s.regs[REG_V0]; break; #endif +#if defined(__powerpc__) +#ifdef __LP64__ + case ARCH_POWERPC_64: +#endif + case ARCH_POWERPC: + /* setup instructions */ + code.u32[0] = 0x4e800421; /* bctrl */ + code.u32[1] = 0x7fe00008; /* trap */ + code_size = 2 * 4; + /* setup registers */ + regs.nip = injector->code_addr; + regs.gpr[PT_R1] = injector->stack + injector->stack_size - 256; + regs.ctr = function_addr; + regs.gpr[PT_R3] = arg1; + regs.gpr[PT_R4] = arg2; + regs.gpr[PT_R5] = arg3; + regs.gpr[PT_R6] = arg4; + regs.gpr[PT_R7] = arg5; + regs.gpr[PT_R8] = arg6; + regs.gpr[PT_R12] = function_addr; + reg_return = ®s.gpr[PT_R3]; + break; +#endif #if defined(__riscv) #ifdef __LP64__ case ARCH_RISCV_64: diff --git a/src/linux/util.c b/src/linux/util.c index e1b52ac..3146743 100644 --- a/src/linux/util.c +++ b/src/linux/util.c @@ -69,6 +69,10 @@ const char *injector__arch2name(arch_t arch) return "MIPS N32 ABI"; case ARCH_MIPS_O32: return "MIPS O32 ABI"; + case ARCH_POWERPC_64: + return "PowerPC 64-bit"; + case ARCH_POWERPC: + return "PowerPC"; case ARCH_RISCV_64: return "RISC-V 64"; case ARCH_RISCV_32: