内核源:
// SPDX-License-Identifier: GPL-2.0
#include <linux/syscalls.h>
#include <linux/pid.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/percpu.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <asm/fpsimd.h>
#include <linux/thread_info.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
#include <uapi/asm/ptrace.h>
#include <linux/sched/signal.h>
#include <linux/rcupdate.h>
#include <linux/cpumask.h>
/**
* 寄存器编号与名称映射(核心修复:统一LR寄存器编号)
* - X0-X29 → 0-29
* - LR寄存器 → 30
* - PC寄存器 → 31
*/
#define REG_X0 0
#define REG_X1 1
#define REG_X2 2
#define REG_X3 3
#define REG_X4 4
#define REG_X5 5
#define REG_X6 6
#define REG_X7 7
#define REG_X8 8
#define REG_X9 9
#define REG_X10 10
#define REG_X11 11
#define REG_X12 12
#define REG_X13 13
#define REG_X14 14
#define REG_X15 15
#define REG_X16 16
#define REG_X17 17
#define REG_X18 18
#define REG_X19 19
#define REG_X20 20
#define REG_X21 21
#define REG_X22 22
#define REG_X23 23
#define REG_X24 24
#define REG_X25 25
#define REG_X26 26
#define REG_X27 27
#define REG_X28 28
#define REG_X29 29
#define REG_LR 30 // LR寄存器固定为30
#define REG_PC 31
/**
* 内核与用户态共享的数据结构
* 用于传递寄存器状态和修改结果
*/
struct reg_data {
int pid; // 目标进程PID
int hit_flag; // 断点命中标志(0=未命中,1=命中)
int modify_flag; // 修改请求标志(0=无请求,1=有请求)
int modify_reg; // 要修改的寄存器编号(0-31)
int modify_result; // 修改结果(0=成功, -1=无效寄存器, -2=地址无效)
unsigned long long new_val; // 要修改的新值(用户输入)
unsigned long long modified_val; // 修改后的实际值(回传用户)
struct pt_regs regs; // 通用寄存器组(X0-X30、PC、SP等)
struct user_fpsimd_state fp_regs; // 浮点寄存器组
};
// 全局变量
static struct perf_event __percpu **bp = NULL; // 硬件断点句柄(percpu类型)
static struct reg_data *g_reg_data = NULL; // 共享数据区
static struct mutex reg_mutex; // 保护共享数据的互斥锁
static wait_queue_head_t reg_waitq; // 通知用户态的等待队列
static bool is_initialized = false; // 初始化标志
static bool bp_active = false; // 断点活跃标志
static atomic_t callback_count = ATOMIC_INIT(0); // 活跃回调计数器(防资源提前释放)
/**
* 断点命中回调函数
* 功能:断点触发时保存寄存器状态到共享数据区
*/
static void hit_handler(struct perf_event *bp_event,
struct perf_sample_data *data,
struct pt_regs *regs)
{
struct user_fpsimd_state fp; // 浮点寄存器状态
struct task_struct *current_task;
// 快速检查:断点已取消则直接返回
if (!bp_active)
return;
atomic_inc(&callback_count); // 增加回调计数
// 检查共享数据区有效性
if (!g_reg_data) {
atomic_dec(&callback_count);
return;
}
current_task = current;
// 保存浮点寄存器状态(区分用户态/内核态)
if (!user_mode(regs)) {
fpsimd_save_state(&fp); // 内核态:直接保存
} else {
memcpy(&fp, ¤t_task->thread.uw.fpsimd_state, sizeof(fp)); // 用户态:从进程读取
}
// 临界区:更新共享数据
mutex_lock(®_mutex);
if (g_reg_data) {
memcpy(&g_reg_data->regs, regs, sizeof(struct pt_regs)); // 保存通用寄存器
memcpy(&g_reg_data->fp_regs, &fp, sizeof(struct user_fpsimd_state)); // 保存浮点寄存器
g_reg_data->hit_flag = 1; // 标记断点命中
pr_info("断点命中,已更新共享数据(PID:%d)\n", current->pid);
}
mutex_unlock(®_mutex);
wake_up_interruptible(®_waitq); // 唤醒用户态进程
atomic_dec(&callback_count); // 减少回调计数
}
/**
* 系统调用:process_mrelease(调用号448)
* 功能:设置/取消断点、修改寄存器、数据交互
*/
SYSCALL_DEFINE4(process_mrelease, int, pid, unsigned long long, addr,
int, len, int, type)
{
struct perf_event_attr attr = {}; // 断点属性配置
struct pid *pid_struct = NULL; // 目标进程PID结构体
struct task_struct *tsk = NULL; // 目标进程结构体
int ret = 0; // 系统调用返回值
int cpu;
// 初始化同步机制(仅首次调用)
if (!is_initialized) {
mutex_init(®_mutex);
init_waitqueue_head(®_waitq);
is_initialized = true;
}
switch (type) {
// 处理寄存器修改请求(type=4)
case 4:
mutex_lock(®_mutex);
if (g_reg_data && g_reg_data->modify_flag) {
int reg = g_reg_data->modify_reg; // 寄存器编号(0-31)
unsigned long long val = g_reg_data->new_val; // 新值
unsigned long long *target_reg = NULL; // 目标寄存器指针
// 初始化修改结果
g_reg_data->modify_result = 0;
g_reg_data->modified_val = 0;
// 解析寄存器编号,定位目标寄存器(核心修复:LR对应30)
if (reg == REG_PC) { // PC寄存器(编号31)
if (!access_ok((void __user *)val, 4)) { // 验证PC地址有效性
g_reg_data->modify_result = -2;
pr_err("修改PC失败:无效地址\n");
goto unlock_modify;
}
target_reg = &g_reg_data->regs.pc; // PC在pt_regs中的位置
}
// 核心修复:LR寄存器明确处理
else if (reg == REG_LR) { // LR寄存器(编号30)
target_reg = &g_reg_data->regs.regs[REG_LR]; // LR在regs数组中的位置
}
else if (reg >= REG_X0 && reg <= REG_X29) { // X0-X29(编号0-29)
target_reg = &g_reg_data->regs.regs[reg];
}
else { // 无效编号
g_reg_data->modify_result = -1;
pr_err("修改失败:无效寄存器编号 %d\n", reg);
goto unlock_modify;
}
// 执行修改并记录结果
*target_reg = val;
g_reg_data->modified_val = val; // 回传实际修改值
g_reg_data->modify_result = 0; // 标记成功
pr_info("修改寄存器成功:编号%d → 0x%llx\n", reg, val);
}
unlock_modify:
g_reg_data->modify_flag = 0; // 清除修改请求
mutex_unlock(®_mutex);
return ret;
// 取消断点(type=5)
case 5: {
unsigned long flags;
if (!bp_active) {
pr_info("断点已取消,无需重复操作\n");
return 0;
}
local_irq_save(flags); // 禁用中断
bp_active = false; // 标记断点失效
// 等待所有回调完成
while (atomic_read(&callback_count) > 0)
cpu_relax();
// 释放所有CPU上的断点资源
if (bp && !IS_ERR(bp)) {
for_each_possible_cpu(cpu) {
struct perf_event **percpu_bp = per_cpu_ptr(bp, cpu);
if (*percpu_bp && !IS_ERR(*percpu_bp)) {
perf_event_disable(*percpu_bp);
unregister_wide_hw_breakpoint(bp);
*percpu_bp = NULL;
}
}
free_percpu(bp);
bp = NULL;
}
// 释放共享数据区
mutex_lock(®_mutex);
if (g_reg_data) {
kfree(g_reg_data);
g_reg_data = NULL;
}
mutex_unlock(®_mutex);
local_irq_restore(flags); // 恢复中断
pr_info("断点已安全取消\n");
return 0;
}
// 拷贝数据到用户空间(type=6)
case 6:
if (!g_reg_data || !access_ok((void __user*)addr, sizeof(struct reg_data))) {
ret = -EINVAL;
pr_err("拷贝数据失败:无效地址\n");
break;
}
mutex_lock(®_mutex);
if (copy_to_user((void __user*)addr, g_reg_data, sizeof(struct reg_data))) {
ret = -EFAULT;
pr_err("拷贝数据失败\n");
}
mutex_unlock(®_mutex);
break;
// 重置标志(type=7)
case 7:
mutex_lock(®_mutex);
if (g_reg_data) {
g_reg_data->hit_flag = 0;
g_reg_data->modify_result = 0;
g_reg_data->modified_val = 0;
}
mutex_unlock(®_mutex);
break;
// 核心修复:新增数据设置到内核(type=8)
case 8:
if (!access_ok((void __user*)addr, sizeof(struct reg_data))) {
ret = -EINVAL;
pr_err("设置数据失败:无效地址\n");
break;
}
mutex_lock(®_mutex);
if (!g_reg_data) {
mutex_unlock(®_mutex);
ret = -EFAULT;
pr_err("共享数据区未初始化\n");
break;
}
if (copy_from_user(g_reg_data, (void __user*)addr, sizeof(struct reg_data))) {
mutex_unlock(®_mutex);
ret = -EFAULT;
pr_err("设置数据失败\n");
break;
}
mutex_unlock(®_mutex);
pr_info("内核共享数据已更新\n");
break;
// 设置硬件断点(type=0-3:读/写/读写/执行)
default: {
// 清理旧断点
if (bp && !IS_ERR(bp)) {
for_each_possible_cpu(cpu) {
struct perf_event **percpu_bp = per_cpu_ptr(bp, cpu);
if (*percpu_bp && !IS_ERR(*percpu_bp)) {
perf_event_disable(*percpu_bp);
unregister_wide_hw_breakpoint(bp);
*percpu_bp = NULL;
}
}
free_percpu(bp);
bp = NULL;
}
// 初始化共享数据区
if (!g_reg_data) {
g_reg_data = kmalloc(sizeof(struct reg_data), GFP_KERNEL);
if (!g_reg_data) {
ret = -ENOMEM;
pr_err("内存分配失败\n");
return ret;
}
memset(g_reg_data, 0, sizeof(struct reg_data));
g_reg_data->pid = pid;
}
// 获取目标进程
pid_struct = find_get_pid(pid);
if (!pid_struct) {
ret = -ESRCH;
pr_err("进程不存在:PID=%d\n", pid);
break;
}
tsk = get_pid_task(pid_struct, PIDTYPE_PID);
put_pid(pid_struct);
if (!tsk || !tsk->mm) {
ret = -ESRCH;
pr_err("进程已退出:PID=%d\n", pid);
break;
}
// 配置断点属性
hw_breakpoint_init(&attr);
attr.bp_addr = addr; // 监控地址
attr.bp_len = (len == 8) ? HW_BREAKPOINT_LEN_8 : HW_BREAKPOINT_LEN_4; // 监控长度
// 设置断点类型
switch (type) {
case 0: attr.bp_type = HW_BREAKPOINT_R; break;
case 1: attr.bp_type = HW_BREAKPOINT_W; break;
case 2: attr.bp_type = HW_BREAKPOINT_RW; break;
case 3: attr.bp_type = HW_BREAKPOINT_X; break;
default:
ret = -EINVAL;
pr_err("无效断点类型(支持0-3)\n");
goto put_task;
}
// 注册断点
bp = register_wide_hw_breakpoint(&attr, hit_handler, tsk);
if (IS_ERR(bp)) {
ret = PTR_ERR(bp);
bp = NULL;
pr_err("断点注册失败:%d\n", ret);
goto put_task;
}
bp_active = true;
pr_info("断点注册成功:PID=%d, 地址=0x%llx\n", pid, addr);
put_task:
put_task_struct(tsk);
break;
}
}
return ret;
}
用户源;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
// 系统调用号(需与内核一致)
#define __NR_process_mrelease 448
/**
* 寄存器编号定义(与内核严格一致)
*/
#define REG_X0 0
#define REG_X1 1
#define REG_X2 2
#define REG_X3 3
#define REG_X4 4
#define REG_X5 5
#define REG_X6 6
#define REG_X7 7
#define REG_X8 8
#define REG_X9 9
#define REG_X10 10
#define REG_X11 11
#define REG_X12 12
#define REG_X13 13
#define REG_X14 14
#define REG_X15 15
#define REG_X16 16
#define REG_X17 17
#define REG_X18 18
#define REG_X19 19
#define REG_X20 20
#define REG_X21 21
#define REG_X22 22
#define REG_X23 23
#define REG_X24 24
#define REG_X25 25
#define REG_X26 26
#define REG_X27 27
#define REG_X28 28
#define REG_X29 29
#define REG_LR 30 // LR寄存器
#define REG_PC 31 // PC寄存器
/**
* 浮点寄存器结构(与内核user_fpsimd_state一致)
*/
struct user_fpsimd_state {
uint64_t vregs[32]; // 32个64位浮点寄存器(V0-V31)
uint32_t fpsr; // 浮点状态寄存器
uint32_t fpcr; // 浮点控制寄存器
};
/**
* 通用寄存器结构(与内核pt_regs一致)
*/
struct pt_regs {
uint64_t regs[31]; // X0-X30(索引0-30,其中30为LR)
uint64_t sp; // 栈指针(SP)
uint64_t pc; // 程序计数器(PC)
uint64_t pstate; // 状态寄存器(PSTATE)
};
/**
* 共享数据结构(与内核一致)
*/
struct reg_data {
int pid; // 目标进程PID
int hit_flag; // 断点命中标志
int modify_flag; // 修改请求标志(1表示有修改请求)
int modify_reg; // 要修改的寄存器编号(0-31)
int modify_result; // 修改结果(0=成功, -1=无效寄存器, -2=地址无效)
uint64_t new_val; // 要修改的新值
uint64_t modified_val; // 修改后的实际值
struct pt_regs regs; // 通用寄存器状态(修改后的值)
struct user_fpsimd_state fp_regs; // 浮点寄存器状态
};
/**
* 系统调用封装函数
*/
static inline int process_mrelease(int pid, uint64_t addr, int len, int type)
{
return syscall(__NR_process_mrelease, pid, addr, len, type);
}
/**
* 从内核获取寄存器数据(包括修改结果)
*/
static int get_reg_data(int pid, struct reg_data *data)
{
return process_mrelease(pid, (uint64_t)data, sizeof(*data), 6);
}
/**
* 向内核发送寄存器修改请求
*/
static int set_reg_modify_request(int pid, struct reg_data *data)
{
// 通过type=8将修改请求传递给内核
return process_mrelease(pid, (uint64_t)data, 0, 8);
}
/**
* 重置断点命中标志和修改结果
*/
static void reset_hit_flag(int pid)
{
process_mrelease(pid, 0, 0, 7);
}
/**
* 将寄存器名称解析为编号(如"X0"→0,"LR"→30)
*/
static int parse_reg_name(const char *name) {
if (strcasecmp(name, "PC") == 0)
return REG_PC;
if (strcasecmp(name, "LR") == 0)
return REG_LR;
if (strncasecmp(name, "X", 1) == 0 && strlen(name) > 1) {
int idx;
if (sscanf(name + 1, "%d", &idx) == 1) {
if (idx >= 0 && idx <= 29)
return idx;
}
}
return -1; // 无效寄存器
}
/**
* 将寄存器编号转换为名称(如30→"LR")
*/
static const char* reg_num_to_name(int num) {
if (num == REG_PC) return "PC";
if (num == REG_LR) return "LR";
if (num >= 0 && num <= 29) {
static char buf[8];
snprintf(buf, sizeof(buf), "X%d", num);
return buf;
}
return "未知";
}
/**
* 打印寄存器修改结果
*/
static void print_modify_result(struct reg_data *data) {
const char *reg_name = reg_num_to_name(data->modify_reg);
printf("\n======= 寄存器修改结果 =======\n");
if (data->modify_result == 0) {
printf("✅ 修改成功!\n");
printf("寄存器 %s 的新值:%llu (0x%llx)\n",
reg_name, data->modified_val, data->modified_val);
} else if (data->modify_result == -1) {
printf("❌ 修改失败:无效寄存器编号\n");
} else if (data->modify_result == -2) {
printf("❌ 修改失败:PC地址无效(不可访问)\n");
}
printf("=============================\n");
}
/**
* 打印断点命中时的寄存器状态
*/
static void print_regs(struct reg_data *data) {
printf("\n======= 断点命中 @ PC: 0x%llx =======\n", data->regs.pc);
printf("(十六进制地址 | 十进制值)\n");
// 打印X0-X29
printf("\n【64位通用寄存器】\n");
for (int i = 0; i < 30; i++) {
printf("%-4s: 0x%llx (%20llu)\n",
reg_num_to_name(i),
data->regs.regs[i],
data->regs.regs[i]);
}
// 打印LR、SP、PC、PSTATE
printf("%-4s: 0x%llx (%20llu)\n",
"LR", data->regs.regs[30], data->regs.regs[30]);
printf("%-4s: 0x%llx (%20llu)\n",
"SP", data->regs.sp, data->regs.sp);
printf("%-4s: 0x%llx (%20llu)\n",
"PC", data->regs.pc, data->regs.pc);
printf("%-4s: 0x%llx (状态寄存器)\n",
"PSTATE", data->regs.pstate);
printf("=========================================\n");
}
/**
* 询问用户是否取消断点
*/
static int ask_cancel_breakpoint(int pid) {
char input[16];
printf("\n是否取消当前断点?(y/n): ");
if (!fgets(input, sizeof(input), stdin)) {
fprintf(stderr, "输入错误,继续监控...\n");
return 0;
}
if (input[0] == 'y' || input[0] == 'Y') {
process_mrelease(pid, 0, 0, 5); // 发送取消断点命令
printf("已取消断点,退出程序\n");
return 1;
}
return 0;
}
/**
* 信号处理函数(Ctrl+C时取消断点)
*/
static void sigint_handler(int signum) {
process_mrelease(0, 0, 0, 5); // 取消所有断点
exit(0);
}
int main() {
int pid, type, len = 8; // len=8表示监控8字节地址
uint64_t addr; // 断点监控的地址
char input[256]; // 用户输入缓冲区
struct reg_data *user_data = NULL; // 用户态共享数据结构体
int ret = 0;
// 注册信号处理(Ctrl+C时清理断点)
signal(SIGINT, sigint_handler);
// 分配用户态共享数据内存
user_data = (struct reg_data*)malloc(sizeof(struct reg_data));
if (!user_data) {
fprintf(stderr, "内存分配失败\n");
return 1;
}
memset(user_data, 0, sizeof(struct reg_data));
// 获取用户输入(目标进程PID、监控地址、断点类型)
printf("===== Linux内核硬件断点调试工具 =====\n");
printf("目标进程PID: ");
if (!fgets(input, sizeof(input), stdin) || sscanf(input, "%d", &pid) != 1) {
fprintf(stderr, "无效PID\n");
goto cleanup;
}
printf("监控地址(0x开头): ");
if (!fgets(input, sizeof(input), stdin) ||
sscanf(input, "0x%llx", &addr) != 1) {
fprintf(stderr, "无效地址\n");
goto cleanup;
}
printf("断点类型(0-3,提示:0=读 1=写 2=读写 3=执行): ");
if (!fgets(input, sizeof(input), stdin) ||
sscanf(input, "%d", &type) != 1 || type < 0 || type > 3) {
fprintf(stderr, "无效类型\n");
goto cleanup;
}
// 设置硬件断点
ret = process_mrelease(pid, addr, len, type);
if (ret < 0) {
perror("设置断点失败");
goto cleanup;
}
printf("\n等待断点命中...(输入Q退出)\n");
// 主循环:等待断点命中并处理
while (1) {
struct pollfd pfd = {.fd = STDIN_FILENO, .events = POLLIN};
int ready = poll(&pfd, 1, 500); // 等待用户输入或超时
// 从内核获取寄存器数据(检查是否命中断点)
struct reg_data kernel_data;
memset(&kernel_data, 0, sizeof(kernel_data));
ret = get_reg_data(pid, &kernel_data);
if (ret < 0) continue;
// 断点命中:处理寄存器显示和修改
if (kernel_data.hit_flag) {
memcpy(user_data, &kernel_data, sizeof(struct reg_data));
print_regs(user_data); // 打印当前寄存器状态
// 询问用户是否修改寄存器
printf("\n是否修改寄存器?(y/n): ");
if (!fgets(input, sizeof(input), stdin)) {
reset_hit_flag(pid); // 重置命中标志
if (ask_cancel_breakpoint(pid)) break;
continue;
}
if (input[0] == 'y' || input[0] == 'Y') {
// 获取要修改的寄存器名称
printf("请输入寄存器名称(X0-X29、LR、PC): ");
if (!fgets(input, sizeof(input), stdin)) {
reset_hit_flag(pid);
if (ask_cancel_breakpoint(pid)) break;
continue;
}
input[strcspn(input, "\n")] = 0; // 去除换行符
// 解析寄存器编号
int reg_idx = parse_reg_name(input);
if (reg_idx < 0) {
fprintf(stderr, "无效寄存器名称\n");
reset_hit_flag(pid);
if (ask_cancel_breakpoint(pid)) break;
continue;
}
// 获取要修改的新值
printf("请输入新值(十进制或0x十六进制): ");
if (!fgets(input, sizeof(input), stdin)) {
reset_hit_flag(pid);
if (ask_cancel_breakpoint(pid)) break;
continue;
}
// 解析输入的数值(支持十进制和十六进制)
uint64_t new_val;
char *endptr;
if (strncasecmp(input, "0x", 2) == 0) {
new_val = strtoull(input + 2, &endptr, 16); // 十六进制
} else {
new_val = strtoull(input, &endptr, 10); // 十进制
}
if (*endptr != '\n' && *endptr != '\0') { // 检查解析是否成功
fprintf(stderr, "无效数值\n");
reset_hit_flag(pid);
if (ask_cancel_breakpoint(pid)) break;
continue;
}
// 构造修改请求(设置标志、寄存器编号、新值)
struct reg_data modify_req;
memset(&modify_req, 0, sizeof(modify_req));
modify_req.pid = pid;
modify_req.modify_flag = 1; // 标记有修改请求
modify_req.modify_reg = reg_idx;
modify_req.new_val = new_val;
// 发送修改请求到内核(内核会在下次断点命中时处理)
ret = set_reg_modify_request(pid, &modify_req);
if (ret < 0) {
perror("发送修改请求失败");
reset_hit_flag(pid);
if (ask_cancel_breakpoint(pid)) break;
continue;
}
printf("修改请求已发送,等待断点命中并执行修改...\n");
}
// 重置命中标志,准备下一次监控
reset_hit_flag(pid);
// 询问是否取消断点
if (ask_cancel_breakpoint(pid)) break;
}
// 检查用户是否输入Q退出
if (ready > 0 && (pfd.revents & POLLIN)) {
if (fgets(input, sizeof(input), stdin) && input[0] == 'Q') {
process_mrelease(pid, 0, 0, 5); // 取消断点
printf("已退出程序\n");
break;
}
}
}
cleanup:
free(user_data); // 释放用户态内存
return ret;
}
帮我删除内核和用户源所有修改寄存器操作 仔细阅读linux文档和rwprocmem33 帮我修复好取消断点概率死机崩溃 长时间断点死机崩溃 选择只读 写 执行概率死机崩溃 用户源增加自行输入 4 8字节长度 打印寄存器信息对其 只需打印十六进制地址 打印大写寄存器 地址不要出现0x00000开头 只需0x11111111这样 避免太乱 用户源在进行断点后接收所有日志信息 代码已经具备了系统调用 所以你不要乱碰 采用集成到内核中 不使用模块 修复好检查无问题无编译报错后完整发给我两份代码 全程中文注释 中文打印 设备:红米k70 内核:5.15
最新发布