trace_syscalls.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #include <linux/kernel.h>
  2. #include <linux/ftrace.h>
  3. #include <asm/syscall.h>
  4. #include "trace_output.h"
  5. #include "trace.h"
  6. static atomic_t refcount;
  7. /* Our two options */
  8. enum {
  9. TRACE_SYSCALLS_OPT_TYPES = 0x1,
  10. };
  11. static struct tracer_opt syscalls_opts[] = {
  12. { TRACER_OPT(syscall_arg_type, TRACE_SYSCALLS_OPT_TYPES) },
  13. { }
  14. };
  15. static struct tracer_flags syscalls_flags = {
  16. .val = 0, /* By default: no args types */
  17. .opts = syscalls_opts
  18. };
  19. enum print_line_t
  20. print_syscall_enter(struct trace_iterator *iter, int flags)
  21. {
  22. struct trace_seq *s = &iter->seq;
  23. struct trace_entry *ent = iter->ent;
  24. struct syscall_trace_enter *trace;
  25. struct syscall_metadata *entry;
  26. int i, ret, syscall;
  27. trace_assign_type(trace, ent);
  28. syscall = trace->nr;
  29. entry = syscall_nr_to_meta(syscall);
  30. if (!entry)
  31. goto end;
  32. ret = trace_seq_printf(s, "%s(", entry->name);
  33. if (!ret)
  34. return TRACE_TYPE_PARTIAL_LINE;
  35. for (i = 0; i < entry->nb_args; i++) {
  36. /* parameter types */
  37. if (syscalls_flags.val & TRACE_SYSCALLS_OPT_TYPES) {
  38. ret = trace_seq_printf(s, "%s ", entry->types[i]);
  39. if (!ret)
  40. return TRACE_TYPE_PARTIAL_LINE;
  41. }
  42. /* parameter values */
  43. ret = trace_seq_printf(s, "%s: %lx%s ", entry->args[i],
  44. trace->args[i],
  45. i == entry->nb_args - 1 ? ")" : ",");
  46. if (!ret)
  47. return TRACE_TYPE_PARTIAL_LINE;
  48. }
  49. end:
  50. trace_seq_printf(s, "\n");
  51. return TRACE_TYPE_HANDLED;
  52. }
  53. enum print_line_t
  54. print_syscall_exit(struct trace_iterator *iter, int flags)
  55. {
  56. struct trace_seq *s = &iter->seq;
  57. struct trace_entry *ent = iter->ent;
  58. struct syscall_trace_exit *trace;
  59. int syscall;
  60. struct syscall_metadata *entry;
  61. int ret;
  62. trace_assign_type(trace, ent);
  63. syscall = trace->nr;
  64. entry = syscall_nr_to_meta(syscall);
  65. if (!entry) {
  66. trace_seq_printf(s, "\n");
  67. return TRACE_TYPE_HANDLED;
  68. }
  69. ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
  70. trace->ret);
  71. if (!ret)
  72. return TRACE_TYPE_PARTIAL_LINE;
  73. return TRACE_TYPE_HANDLED;
  74. }
  75. void start_ftrace_syscalls(void)
  76. {
  77. unsigned long flags;
  78. struct task_struct *g, *t;
  79. if (atomic_inc_return(&refcount) != 1)
  80. goto out;
  81. arch_init_ftrace_syscalls();
  82. read_lock_irqsave(&tasklist_lock, flags);
  83. do_each_thread(g, t) {
  84. set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
  85. } while_each_thread(g, t);
  86. read_unlock_irqrestore(&tasklist_lock, flags);
  87. out:
  88. atomic_dec(&refcount);
  89. }
  90. void stop_ftrace_syscalls(void)
  91. {
  92. unsigned long flags;
  93. struct task_struct *g, *t;
  94. if (atomic_dec_return(&refcount))
  95. goto out;
  96. read_lock_irqsave(&tasklist_lock, flags);
  97. do_each_thread(g, t) {
  98. clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
  99. } while_each_thread(g, t);
  100. read_unlock_irqrestore(&tasklist_lock, flags);
  101. out:
  102. atomic_inc(&refcount);
  103. }
  104. void ftrace_syscall_enter(struct pt_regs *regs)
  105. {
  106. struct syscall_trace_enter *entry;
  107. struct syscall_metadata *sys_data;
  108. struct ring_buffer_event *event;
  109. int size;
  110. int syscall_nr;
  111. int cpu;
  112. syscall_nr = syscall_get_nr(current, regs);
  113. cpu = raw_smp_processor_id();
  114. sys_data = syscall_nr_to_meta(syscall_nr);
  115. if (!sys_data)
  116. return;
  117. size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
  118. event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER, size,
  119. 0, 0);
  120. if (!event)
  121. return;
  122. entry = ring_buffer_event_data(event);
  123. entry->nr = syscall_nr;
  124. syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args);
  125. trace_current_buffer_unlock_commit(event, 0, 0);
  126. trace_wake_up();
  127. }
  128. void ftrace_syscall_exit(struct pt_regs *regs)
  129. {
  130. struct syscall_trace_exit *entry;
  131. struct syscall_metadata *sys_data;
  132. struct ring_buffer_event *event;
  133. int syscall_nr;
  134. int cpu;
  135. syscall_nr = syscall_get_nr(current, regs);
  136. cpu = raw_smp_processor_id();
  137. sys_data = syscall_nr_to_meta(syscall_nr);
  138. if (!sys_data)
  139. return;
  140. event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT,
  141. sizeof(*entry), 0, 0);
  142. if (!event)
  143. return;
  144. entry = ring_buffer_event_data(event);
  145. entry->nr = syscall_nr;
  146. entry->ret = syscall_get_return_value(current, regs);
  147. trace_current_buffer_unlock_commit(event, 0, 0);
  148. trace_wake_up();
  149. }
  150. static int init_syscall_tracer(struct trace_array *tr)
  151. {
  152. start_ftrace_syscalls();
  153. return 0;
  154. }
  155. static void reset_syscall_tracer(struct trace_array *tr)
  156. {
  157. stop_ftrace_syscalls();
  158. }
  159. static struct trace_event syscall_enter_event = {
  160. .type = TRACE_SYSCALL_ENTER,
  161. .trace = print_syscall_enter,
  162. };
  163. static struct trace_event syscall_exit_event = {
  164. .type = TRACE_SYSCALL_EXIT,
  165. .trace = print_syscall_exit,
  166. };
  167. static struct tracer syscall_tracer __read_mostly = {
  168. .name = "syscall",
  169. .init = init_syscall_tracer,
  170. .reset = reset_syscall_tracer,
  171. .flags = &syscalls_flags,
  172. };
  173. __init int register_ftrace_syscalls(void)
  174. {
  175. int ret;
  176. ret = register_ftrace_event(&syscall_enter_event);
  177. if (!ret) {
  178. printk(KERN_WARNING "event %d failed to register\n",
  179. syscall_enter_event.type);
  180. WARN_ON_ONCE(1);
  181. }
  182. ret = register_ftrace_event(&syscall_exit_event);
  183. if (!ret) {
  184. printk(KERN_WARNING "event %d failed to register\n",
  185. syscall_exit_event.type);
  186. WARN_ON_ONCE(1);
  187. }
  188. return register_tracer(&syscall_tracer);
  189. }
  190. device_initcall(register_ftrace_syscalls);