162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * data_breakpoint.c - Sample HW Breakpoint file to watch kernel data address 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * usage: insmod data_breakpoint.ko ksym=<ksym_name> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is a kernel module that places a breakpoint over ksym_name kernel 862306a36Sopenharmony_ci * variable using Hardware Breakpoint register. The corresponding handler which 962306a36Sopenharmony_ci * prints a backtrace is invoked every time a write operation is performed on 1062306a36Sopenharmony_ci * that variable. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2009 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Author: K.Prasad <prasad@linux.vnet.ibm.com> 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci#include <linux/module.h> /* Needed by all modules */ 1762306a36Sopenharmony_ci#include <linux/kernel.h> /* Needed for KERN_INFO */ 1862306a36Sopenharmony_ci#include <linux/init.h> /* Needed for the macros */ 1962306a36Sopenharmony_ci#include <linux/kallsyms.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/perf_event.h> 2262306a36Sopenharmony_ci#include <linux/hw_breakpoint.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic struct perf_event * __percpu *sample_hbp; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic char ksym_name[KSYM_NAME_LEN] = "jiffies"; 2762306a36Sopenharmony_cimodule_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO); 2862306a36Sopenharmony_ciMODULE_PARM_DESC(ksym, "Kernel symbol to monitor; this module will report any" 2962306a36Sopenharmony_ci " write operations on the kernel symbol"); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void sample_hbp_handler(struct perf_event *bp, 3262306a36Sopenharmony_ci struct perf_sample_data *data, 3362306a36Sopenharmony_ci struct pt_regs *regs) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci printk(KERN_INFO "%s value is changed\n", ksym_name); 3662306a36Sopenharmony_ci dump_stack(); 3762306a36Sopenharmony_ci printk(KERN_INFO "Dump stack from sample_hbp_handler\n"); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int __init hw_break_module_init(void) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int ret; 4362306a36Sopenharmony_ci struct perf_event_attr attr; 4462306a36Sopenharmony_ci void *addr = __symbol_get(ksym_name); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!addr) 4762306a36Sopenharmony_ci return -ENXIO; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci hw_breakpoint_init(&attr); 5062306a36Sopenharmony_ci attr.bp_addr = (unsigned long)addr; 5162306a36Sopenharmony_ci attr.bp_len = HW_BREAKPOINT_LEN_4; 5262306a36Sopenharmony_ci attr.bp_type = HW_BREAKPOINT_W; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL); 5562306a36Sopenharmony_ci if (IS_ERR((void __force *)sample_hbp)) { 5662306a36Sopenharmony_ci ret = PTR_ERR((void __force *)sample_hbp); 5762306a36Sopenharmony_ci goto fail; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci printk(KERN_INFO "HW Breakpoint for %s write installed\n", ksym_name); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cifail: 6562306a36Sopenharmony_ci printk(KERN_INFO "Breakpoint registration failed\n"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void __exit hw_break_module_exit(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unregister_wide_hw_breakpoint(sample_hbp); 7362306a36Sopenharmony_ci#ifdef CONFIG_MODULE_UNLOAD 7462306a36Sopenharmony_ci __symbol_put(ksym_name); 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci printk(KERN_INFO "HW Breakpoint for %s write uninstalled\n", ksym_name); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cimodule_init(hw_break_module_init); 8062306a36Sopenharmony_cimodule_exit(hw_break_module_exit); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 8362306a36Sopenharmony_ciMODULE_AUTHOR("K.Prasad"); 8462306a36Sopenharmony_ciMODULE_DESCRIPTION("ksym breakpoint"); 85