162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Here's a sample kernel module showing the use of kprobes to dump a 462306a36Sopenharmony_ci * stack trace and selected registers when kernel_clone() is called. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * For more information on theory of operation of kprobes, see 762306a36Sopenharmony_ci * Documentation/trace/kprobes.rst 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * You will see the trace data in /var/log/messages and on the console 1062306a36Sopenharmony_ci * whenever kernel_clone() is invoked to create a new process. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/kprobes.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic char symbol[KSYM_NAME_LEN] = "kernel_clone"; 2062306a36Sopenharmony_cimodule_param_string(symbol, symbol, KSYM_NAME_LEN, 0644); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* For each probe you need to allocate a kprobe structure */ 2362306a36Sopenharmony_cistatic struct kprobe kp = { 2462306a36Sopenharmony_ci .symbol_name = symbol, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* kprobe pre_handler: called just before the probed instruction is executed */ 2862306a36Sopenharmony_cistatic int __kprobes handler_pre(struct kprobe *p, struct pt_regs *regs) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci#ifdef CONFIG_X86 3162306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, ip = %lx, flags = 0x%lx\n", 3262306a36Sopenharmony_ci p->symbol_name, p->addr, regs->ip, regs->flags); 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci#ifdef CONFIG_PPC 3562306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n", 3662306a36Sopenharmony_ci p->symbol_name, p->addr, regs->nip, regs->msr); 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci#ifdef CONFIG_MIPS 3962306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n", 4062306a36Sopenharmony_ci p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status); 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci#ifdef CONFIG_ARM64 4362306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, pstate = 0x%lx\n", 4462306a36Sopenharmony_ci p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate); 4562306a36Sopenharmony_ci#endif 4662306a36Sopenharmony_ci#ifdef CONFIG_ARM 4762306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, cpsr = 0x%lx\n", 4862306a36Sopenharmony_ci p->symbol_name, p->addr, (long)regs->ARM_pc, (long)regs->ARM_cpsr); 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci#ifdef CONFIG_RISCV 5162306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, status = 0x%lx\n", 5262306a36Sopenharmony_ci p->symbol_name, p->addr, regs->epc, regs->status); 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci#ifdef CONFIG_S390 5562306a36Sopenharmony_ci pr_info("<%s> p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n", 5662306a36Sopenharmony_ci p->symbol_name, p->addr, regs->psw.addr, regs->flags); 5762306a36Sopenharmony_ci#endif 5862306a36Sopenharmony_ci#ifdef CONFIG_LOONGARCH 5962306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, era = 0x%lx, estat = 0x%lx\n", 6062306a36Sopenharmony_ci p->symbol_name, p->addr, regs->csr_era, regs->csr_estat); 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* A dump_stack() here will give a stack backtrace */ 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* kprobe post_handler: called after the probed instruction is executed */ 6862306a36Sopenharmony_cistatic void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs, 6962306a36Sopenharmony_ci unsigned long flags) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci#ifdef CONFIG_X86 7262306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, flags = 0x%lx\n", 7362306a36Sopenharmony_ci p->symbol_name, p->addr, regs->flags); 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci#ifdef CONFIG_PPC 7662306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, msr = 0x%lx\n", 7762306a36Sopenharmony_ci p->symbol_name, p->addr, regs->msr); 7862306a36Sopenharmony_ci#endif 7962306a36Sopenharmony_ci#ifdef CONFIG_MIPS 8062306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, status = 0x%lx\n", 8162306a36Sopenharmony_ci p->symbol_name, p->addr, regs->cp0_status); 8262306a36Sopenharmony_ci#endif 8362306a36Sopenharmony_ci#ifdef CONFIG_ARM64 8462306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, pstate = 0x%lx\n", 8562306a36Sopenharmony_ci p->symbol_name, p->addr, (long)regs->pstate); 8662306a36Sopenharmony_ci#endif 8762306a36Sopenharmony_ci#ifdef CONFIG_ARM 8862306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, cpsr = 0x%lx\n", 8962306a36Sopenharmony_ci p->symbol_name, p->addr, (long)regs->ARM_cpsr); 9062306a36Sopenharmony_ci#endif 9162306a36Sopenharmony_ci#ifdef CONFIG_RISCV 9262306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, status = 0x%lx\n", 9362306a36Sopenharmony_ci p->symbol_name, p->addr, regs->status); 9462306a36Sopenharmony_ci#endif 9562306a36Sopenharmony_ci#ifdef CONFIG_S390 9662306a36Sopenharmony_ci pr_info("<%s> p->addr, 0x%p, flags = 0x%lx\n", 9762306a36Sopenharmony_ci p->symbol_name, p->addr, regs->flags); 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci#ifdef CONFIG_LOONGARCH 10062306a36Sopenharmony_ci pr_info("<%s> p->addr = 0x%p, estat = 0x%lx\n", 10162306a36Sopenharmony_ci p->symbol_name, p->addr, regs->csr_estat); 10262306a36Sopenharmony_ci#endif 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int __init kprobe_init(void) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int ret; 10862306a36Sopenharmony_ci kp.pre_handler = handler_pre; 10962306a36Sopenharmony_ci kp.post_handler = handler_post; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret = register_kprobe(&kp); 11262306a36Sopenharmony_ci if (ret < 0) { 11362306a36Sopenharmony_ci pr_err("register_kprobe failed, returned %d\n", ret); 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci pr_info("Planted kprobe at %p\n", kp.addr); 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void __exit kprobe_exit(void) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci unregister_kprobe(&kp); 12362306a36Sopenharmony_ci pr_info("kprobe at %p unregistered\n", kp.addr); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cimodule_init(kprobe_init) 12762306a36Sopenharmony_cimodule_exit(kprobe_exit) 12862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 129