aarch64架构下如何通过ptrace获取/设置程序寄存器
aarch64架构下ptrace操作寄存器的正确方案
你看到的sys/user.h里的注释,是android-ndk-r10e这个老旧版本工具链的头文件遗留说明,不代表aarch64架构不支持ptrace操作寄存器。32位ARM沿用的传统user结构体体系本来就没有在aarch64上保留,不是你漏找了定义,是aarch64的ptrace寄存器接口换了头文件、结构体和调用方式。
核心操作要点
- 头文件不需要依赖
sys/user.h,直接引入<sys/ptrace.h>、<asm/ptrace.h>和<sys/uio.h>即可,所有寄存器相关的结构体和常量定义都在这几个头文件中。 - aarch64下对应两类常用寄存器结构体:
- 通用寄存器组:
struct user_pt_regs,包含X0~X30共31个通用寄存器,以及SP、PC、PSTATE(程序状态寄存器),普通断点调试、函数调用参数修改操作这个结构体就足够。 - 浮点/SIMD寄存器组:
struct user_fpsimd_state,包含V0~V31共32个128位向量寄存器,以及FPSR、FPCR浮点状态控制寄存器,需要操作浮点/Neon指令场景才用到。
- 通用寄存器组:
- ptrace调用不要用老旧的
PTRACE_GETREGS/PTRACE_SETREGS(部分内核做了兼容但不保证跨版本可用),统一用标准的PTRACE_GETREGSET/PTRACE_SETREGSET接口:- 操作通用寄存器时,regset类型传
NT_PRSTATUS - 操作浮点寄存器时,regset类型传
NT_FPREGSET - 参数通过
struct iovec传递寄存器结构体的地址和长度。
- 操作通用寄存器时,regset类型传
最简调用示例
#include <sys/ptrace.h> #include <asm/ptrace.h> #include <sys/uio.h> #include <stdio.h> #include <stdint.h> void read_aarch64_regs(pid_t tracee_pid) { struct user_pt_regs regs; struct iovec regs_io = { .iov_base = ®s, .iov_len = sizeof(regs) }; if (ptrace(PTRACE_GETREGSET, tracee_pid, NT_PRSTATUS, ®s_io) == -1) { perror("ptrace get regs failed"); return; } // 读取寄存器示例:打印X0和PC值 printf("X0 = 0x%llx, PC = 0x%llx\n", regs.regs[0], regs.pc); // 修改寄存器示例:把X0改成0x1234 regs.regs[0] = 0x1234; ptrace(PTRACE_SETREGSET, tracee_pid, NT_PRSTATUS, ®s_io); }
针对NDK r10e的特殊说明
r10e是2015年发布的极早版本aarch64 NDK,部分版本的头文件确实缺失struct user_pt_regs的定义,如果不想升级NDK,可以手动按照内核固定布局补全结构体:
struct user_pt_regs { uint64_t regs[31]; // X0~X30 uint64_t sp; uint64_t pc; uint64_t pstate; };
这个布局是aarch64内核ABI固定的,不会随版本变化,直接定义即可正常使用。不要尝试用PTRACE_PEEKUSER加偏移的方式读寄存器,aarch64的user区布局没有对外做稳定偏移承诺,不同内核版本可能出现偏移不兼容问题。
内容的提问来源于stack exchange,提问作者Daniel Walker
相关产品推荐
相关产品推荐

