ftrace.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Code for replacing ftrace calls with jumps.
  3. *
  4. * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  5. *
  6. * Thanks goes to Ingo Molnar, for suggesting the idea.
  7. * Mathieu Desnoyers, for suggesting postponing the modifications.
  8. * Arjan van de Ven, for keeping me straight, and explaining to me
  9. * the dangers of modifying code on the run.
  10. */
  11. #include <linux/spinlock.h>
  12. #include <linux/hardirq.h>
  13. #include <linux/ftrace.h>
  14. #include <linux/percpu.h>
  15. #include <linux/init.h>
  16. #include <linux/list.h>
  17. #include <asm/alternative.h>
  18. #define CALL_BACK 5
  19. /* Long is fine, even if it is only 4 bytes ;-) */
  20. static long *ftrace_nop;
  21. union ftrace_code_union {
  22. char code[5];
  23. struct {
  24. char e8;
  25. int offset;
  26. } __attribute__((packed));
  27. };
  28. notrace int ftrace_ip_converted(unsigned long ip)
  29. {
  30. unsigned long save;
  31. ip -= CALL_BACK;
  32. save = *(long *)ip;
  33. return save == *ftrace_nop;
  34. }
  35. static int notrace ftrace_calc_offset(long ip, long addr)
  36. {
  37. return (int)(addr - ip);
  38. }
  39. notrace unsigned char *ftrace_nop_replace(void)
  40. {
  41. return (char *)ftrace_nop;
  42. }
  43. notrace unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
  44. {
  45. static union ftrace_code_union calc;
  46. calc.e8 = 0xe8;
  47. calc.offset = ftrace_calc_offset(ip, addr);
  48. /*
  49. * No locking needed, this must be called via kstop_machine
  50. * which in essence is like running on a uniprocessor machine.
  51. */
  52. return calc.code;
  53. }
  54. notrace int
  55. ftrace_modify_code(unsigned long ip, unsigned char *old_code,
  56. unsigned char *new_code)
  57. {
  58. unsigned replaced;
  59. unsigned old = *(unsigned *)old_code; /* 4 bytes */
  60. unsigned new = *(unsigned *)new_code; /* 4 bytes */
  61. unsigned char newch = new_code[4];
  62. int faulted = 0;
  63. /* move the IP back to the start of the call */
  64. ip -= CALL_BACK;
  65. /*
  66. * Note: Due to modules and __init, code can
  67. * disappear and change, we need to protect against faulting
  68. * as well as code changing.
  69. *
  70. * No real locking needed, this code is run through
  71. * kstop_machine.
  72. */
  73. asm volatile (
  74. "1: lock\n"
  75. " cmpxchg %3, (%2)\n"
  76. " jnz 2f\n"
  77. " movb %b4, 4(%2)\n"
  78. "2:\n"
  79. ".section .fixup, \"ax\"\n"
  80. " movl $1, %0\n"
  81. "3: jmp 2b\n"
  82. ".previous\n"
  83. _ASM_EXTABLE(1b, 3b)
  84. : "=r"(faulted), "=a"(replaced)
  85. : "r"(ip), "r"(new), "r"(newch),
  86. "0"(faulted), "a"(old)
  87. : "memory");
  88. sync_core();
  89. if (replaced != old && replaced != new)
  90. faulted = 2;
  91. return faulted;
  92. }
  93. int __init ftrace_dyn_arch_init(void)
  94. {
  95. const unsigned char *const *noptable = find_nop_table();
  96. ftrace_nop = (unsigned long *)noptable[CALL_BACK];
  97. return 0;
  98. }