|
| 1 | +/* |
| 2 | + * kp_do_current_softirqs.c |
| 3 | + * Based on kernel's kprobe_example.c. Determine if do_currrent_softirqs() |
| 4 | + * is run from ksoftirqd or is invoked after __local_bh_enable(). |
| 5 | + * |
| 6 | + * Alison Chaiken, alison@she-devel.com |
| 7 | + */ |
| 8 | + |
| 9 | +#include <linux/kernel.h> |
| 10 | +#include <linux/module.h> |
| 11 | +#include <linux/kprobes.h> |
| 12 | +#include <asm/ptrace.h> |
| 13 | +#include <linux/moduleparam.h> |
| 14 | +#include <linux/interrupt.h> |
| 15 | + |
| 16 | +static unsigned long proc_mode; |
| 17 | +unsigned int id; |
| 18 | +static int eth_irq_procid = 9; |
| 19 | +static int can_irq_procid = 10; |
| 20 | +module_param(eth_irq_procid, int, 0); |
| 21 | +module_param(can_irq_procid, int, 0); |
| 22 | +MODULE_PARM_DESC(eth_irq_procid, "Set to the number of the core where eth IRQ runs."); |
| 23 | +MODULE_PARM_DESC(can_irq_procid, "Set to the number of the core where CAN IRQ runs."); |
| 24 | +MODULE_DESCRIPTION("Determine which function invokes do_current_softirqs."); |
| 25 | +MODULE_LICENSE("GPL"); |
| 26 | + |
| 27 | +/* For each probe you need to allocate a kprobe structure */ |
| 28 | +static struct kprobe kp = { |
| 29 | + .symbol_name = "do_current_softirqs", |
| 30 | +}; |
| 31 | + |
| 32 | +/* kprobe pre_handler: called just before the probed instruction is executed */ |
| 33 | +static int handler_pre(struct kprobe *p, struct pt_regs *regs) |
| 34 | +{ |
| 35 | + int raised; |
| 36 | + struct thread_info *ti; |
| 37 | + struct task_struct *task; |
| 38 | + |
| 39 | + id = smp_processor_id(); |
| 40 | + |
| 41 | + raised = __ffs(current->softirqs_raised); |
| 42 | + |
| 43 | + /* change id to that where the eth IRQ is pinned */ |
| 44 | + if ((raised == NET_RX_SOFTIRQ) && (id == eth_irq_procid)) { |
| 45 | + ti = current_thread_info(); |
| 46 | + task = ti->task; |
| 47 | + pr_debug("task->comm is %s\n", task->comm); |
| 48 | + |
| 49 | + if (strstr(task->comm, "ksoftirq")) |
| 50 | + p->ksoftirqd_count++; |
| 51 | + if (strstr(task->comm, "irq/")) |
| 52 | + p->local_bh_enable_count++; |
| 53 | + } |
| 54 | +#ifdef CONFIG_CAN |
| 55 | + /* change id to that where the CAN IRQ is pinned */ |
| 56 | + if ((raised == NET_RX_SOFTIRQ) && (id == can_irq_procid)) |
| 57 | + WARN_ONCE(1, "CAN NAPI.\n"); |
| 58 | +#endif |
| 59 | + return 0; |
| 60 | +} |
| 61 | + |
| 62 | +/* kprobe post_handler: called after the probed instruction is executed */ |
| 63 | +static void handler_post(struct kprobe *p, struct pt_regs *regs, |
| 64 | + unsigned long flags) |
| 65 | +{ |
| 66 | + proc_mode = processor_mode(regs); |
| 67 | + |
| 68 | +#ifdef CONFIG_ARM |
| 69 | + if (p->call_count == 1) |
| 70 | + pr_info("%s post_handler: p->addr = 0x%p, lr = 0x%lx, interrupts enabled: %s, IRQ_MODE %s\n", |
| 71 | + p->symbol_name, p->addr, regs->ARM_lr, |
| 72 | + interrupts_enabled(regs) ? "yes" : "no", |
| 73 | + (proc_mode == IRQ_MODE) ? "ON" : "OFF"); |
| 74 | +#endif |
| 75 | +} |
| 76 | + |
| 77 | +/* |
| 78 | + * fault_handler: this is called if an exception is generated for any |
| 79 | + * instruction within the pre- or post-handler, or when Kprobes |
| 80 | + * single-steps the probed instruction. |
| 81 | + */ |
| 82 | +static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) |
| 83 | +{ |
| 84 | + pr_info("fault_handler: p->addr = 0x%p, trap #%dn", |
| 85 | + p->addr, trapnr); |
| 86 | + /* Return 0 because we don't handle the fault. */ |
| 87 | + return 0; |
| 88 | +} |
| 89 | + |
| 90 | +static int __init kprobe_init(void) |
| 91 | +{ |
| 92 | + int ret; |
| 93 | + |
| 94 | + kp.pre_handler = handler_pre; |
| 95 | + kp.post_handler = handler_post; |
| 96 | + kp.fault_handler = handler_fault; |
| 97 | + |
| 98 | + ret = register_kprobe(&kp); |
| 99 | + if (ret < 0) { |
| 100 | + pr_info("register_kprobe failed, returned %d\n", ret); |
| 101 | + return ret; |
| 102 | + } |
| 103 | + pr_info("Planted kprobe at %p\n", kp.addr); |
| 104 | + return 0; |
| 105 | +} |
| 106 | + |
| 107 | +static void __exit kprobe_exit(void) |
| 108 | +{ |
| 109 | + pr_info("%s: %u from ksofirqd, %u from __local_bh_enable\n", |
| 110 | + kp.symbol_name, kp.ksoftirqd_count, |
| 111 | + kp.local_bh_enable_count); |
| 112 | + unregister_kprobe(&kp); |
| 113 | + pr_info("kprobe at %p unregistered\n", kp.addr); |
| 114 | +} |
| 115 | + |
| 116 | +module_init(kprobe_init) |
| 117 | +module_exit(kprobe_exit) |
| 118 | +MODULE_LICENSE("GPL"); |
0 commit comments