18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NOTE: This example is works on x86 and powerpc.
48c2ecf20Sopenharmony_ci * Here's a sample kernel module showing the use of kprobes to dump a
58c2ecf20Sopenharmony_ci * stack trace and selected registers when kernel_clone() is called.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * For more information on theory of operation of kprobes, see
88c2ecf20Sopenharmony_ci * Documentation/trace/kprobes.rst
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * You will see the trace data in /var/log/messages and on the console
118c2ecf20Sopenharmony_ci * whenever kernel_clone() is invoked to create a new process.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/kprobes.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define MAX_SYMBOL_LEN	64
198c2ecf20Sopenharmony_cistatic char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
208c2ecf20Sopenharmony_cimodule_param_string(symbol, symbol, sizeof(symbol), 0644);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* For each probe you need to allocate a kprobe structure */
238c2ecf20Sopenharmony_cistatic struct kprobe kp = {
248c2ecf20Sopenharmony_ci	.symbol_name	= symbol,
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* kprobe pre_handler: called just before the probed instruction is executed */
288c2ecf20Sopenharmony_cistatic int __kprobes handler_pre(struct kprobe *p, struct pt_regs *regs)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
318c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
328c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->ip, regs->flags);
338c2ecf20Sopenharmony_ci#endif
348c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
358c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",
368c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->nip, regs->msr);
378c2ecf20Sopenharmony_ci#endif
388c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS
398c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",
408c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
418c2ecf20Sopenharmony_ci#endif
428c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64
438c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"
448c2ecf20Sopenharmony_ci			" pstate = 0x%lx\n",
458c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci#ifdef CONFIG_S390
488c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",
498c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->psw.addr, regs->flags);
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* A dump_stack() here will give a stack backtrace */
538c2ecf20Sopenharmony_ci	return 0;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* kprobe post_handler: called after the probed instruction is executed */
578c2ecf20Sopenharmony_cistatic void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs,
588c2ecf20Sopenharmony_ci				unsigned long flags)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
618c2ecf20Sopenharmony_ci	pr_info("<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",
628c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->flags);
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
658c2ecf20Sopenharmony_ci	pr_info("<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",
668c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->msr);
678c2ecf20Sopenharmony_ci#endif
688c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS
698c2ecf20Sopenharmony_ci	pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
708c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->cp0_status);
718c2ecf20Sopenharmony_ci#endif
728c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64
738c2ecf20Sopenharmony_ci	pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",
748c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, (long)regs->pstate);
758c2ecf20Sopenharmony_ci#endif
768c2ecf20Sopenharmony_ci#ifdef CONFIG_S390
778c2ecf20Sopenharmony_ci	pr_info("<%s> pre_handler: p->addr, 0x%p, flags = 0x%lx\n",
788c2ecf20Sopenharmony_ci		p->symbol_name, p->addr, regs->flags);
798c2ecf20Sopenharmony_ci#endif
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/*
838c2ecf20Sopenharmony_ci * fault_handler: this is called if an exception is generated for any
848c2ecf20Sopenharmony_ci * instruction within the pre- or post-handler, or when Kprobes
858c2ecf20Sopenharmony_ci * single-steps the probed instruction.
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
908c2ecf20Sopenharmony_ci	/* Return 0 because we don't handle the fault. */
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci/* NOKPROBE_SYMBOL() is also available */
948c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(handler_fault);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int __init kprobe_init(void)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	int ret;
998c2ecf20Sopenharmony_ci	kp.pre_handler = handler_pre;
1008c2ecf20Sopenharmony_ci	kp.post_handler = handler_post;
1018c2ecf20Sopenharmony_ci	kp.fault_handler = handler_fault;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ret = register_kprobe(&kp);
1048c2ecf20Sopenharmony_ci	if (ret < 0) {
1058c2ecf20Sopenharmony_ci		pr_err("register_kprobe failed, returned %d\n", ret);
1068c2ecf20Sopenharmony_ci		return ret;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci	pr_info("Planted kprobe at %p\n", kp.addr);
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void __exit kprobe_exit(void)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	unregister_kprobe(&kp);
1158c2ecf20Sopenharmony_ci	pr_info("kprobe at %p unregistered\n", kp.addr);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cimodule_init(kprobe_init)
1198c2ecf20Sopenharmony_cimodule_exit(kprobe_exit)
1208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
121