kprobes.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Kernel Probes (KProbes)
  3. * kernel/kprobes.c
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. *
  19. * Copyright (C) IBM Corporation, 2002, 2004
  20. *
  21. * 2002-Oct Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
  22. * Probes initial implementation (includes suggestions from
  23. * Rusty Russell).
  24. * 2004-Aug Updated by Prasanna S Panchamukhi <prasanna@in.ibm.com> with
  25. * hlists and exceptions notifier as suggested by Andi Kleen.
  26. * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
  27. * interface to access function arguments.
  28. * 2004-Sep Prasanna S Panchamukhi <prasanna@in.ibm.com> Changed Kprobes
  29. * exceptions notifier to be first on the priority list.
  30. */
  31. #include <linux/kprobes.h>
  32. #include <linux/spinlock.h>
  33. #include <linux/hash.h>
  34. #include <linux/init.h>
  35. #include <linux/module.h>
  36. #include <asm/cacheflush.h>
  37. #include <asm/errno.h>
  38. #include <asm/kdebug.h>
  39. #define KPROBE_HASH_BITS 6
  40. #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
  41. static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
  42. unsigned int kprobe_cpu = NR_CPUS;
  43. static DEFINE_SPINLOCK(kprobe_lock);
  44. /* Locks kprobe: irqs must be disabled */
  45. void lock_kprobes(void)
  46. {
  47. spin_lock(&kprobe_lock);
  48. kprobe_cpu = smp_processor_id();
  49. }
  50. void unlock_kprobes(void)
  51. {
  52. kprobe_cpu = NR_CPUS;
  53. spin_unlock(&kprobe_lock);
  54. }
  55. /* You have to be holding the kprobe_lock */
  56. struct kprobe *get_kprobe(void *addr)
  57. {
  58. struct hlist_head *head;
  59. struct hlist_node *node;
  60. head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
  61. hlist_for_each(node, head) {
  62. struct kprobe *p = hlist_entry(node, struct kprobe, hlist);
  63. if (p->addr == addr)
  64. return p;
  65. }
  66. return NULL;
  67. }
  68. int register_kprobe(struct kprobe *p)
  69. {
  70. int ret = 0;
  71. unsigned long flags = 0;
  72. if ((ret = arch_prepare_kprobe(p)) != 0) {
  73. goto rm_kprobe;
  74. }
  75. spin_lock_irqsave(&kprobe_lock, flags);
  76. INIT_HLIST_NODE(&p->hlist);
  77. if (get_kprobe(p->addr)) {
  78. ret = -EEXIST;
  79. goto out;
  80. }
  81. arch_copy_kprobe(p);
  82. hlist_add_head(&p->hlist,
  83. &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
  84. p->opcode = *p->addr;
  85. *p->addr = BREAKPOINT_INSTRUCTION;
  86. flush_icache_range((unsigned long) p->addr,
  87. (unsigned long) p->addr + sizeof(kprobe_opcode_t));
  88. out:
  89. spin_unlock_irqrestore(&kprobe_lock, flags);
  90. rm_kprobe:
  91. if (ret == -EEXIST)
  92. arch_remove_kprobe(p);
  93. return ret;
  94. }
  95. void unregister_kprobe(struct kprobe *p)
  96. {
  97. unsigned long flags;
  98. arch_remove_kprobe(p);
  99. spin_lock_irqsave(&kprobe_lock, flags);
  100. *p->addr = p->opcode;
  101. hlist_del(&p->hlist);
  102. flush_icache_range((unsigned long) p->addr,
  103. (unsigned long) p->addr + sizeof(kprobe_opcode_t));
  104. spin_unlock_irqrestore(&kprobe_lock, flags);
  105. }
  106. static struct notifier_block kprobe_exceptions_nb = {
  107. .notifier_call = kprobe_exceptions_notify,
  108. .priority = 0x7fffffff /* we need to notified first */
  109. };
  110. int register_jprobe(struct jprobe *jp)
  111. {
  112. /* Todo: Verify probepoint is a function entry point */
  113. jp->kp.pre_handler = setjmp_pre_handler;
  114. jp->kp.break_handler = longjmp_break_handler;
  115. return register_kprobe(&jp->kp);
  116. }
  117. void unregister_jprobe(struct jprobe *jp)
  118. {
  119. unregister_kprobe(&jp->kp);
  120. }
  121. static int __init init_kprobes(void)
  122. {
  123. int i, err = 0;
  124. /* FIXME allocate the probe table, currently defined statically */
  125. /* initialize all list heads */
  126. for (i = 0; i < KPROBE_TABLE_SIZE; i++)
  127. INIT_HLIST_HEAD(&kprobe_table[i]);
  128. err = register_die_notifier(&kprobe_exceptions_nb);
  129. return err;
  130. }
  131. __initcall(init_kprobes);
  132. EXPORT_SYMBOL_GPL(register_kprobe);
  133. EXPORT_SYMBOL_GPL(unregister_kprobe);
  134. EXPORT_SYMBOL_GPL(register_jprobe);
  135. EXPORT_SYMBOL_GPL(unregister_jprobe);
  136. EXPORT_SYMBOL_GPL(jprobe_return);