Blame view
kernel/trace/trace_syscalls.c
16.6 KB
47788c58e tracing/syscalls:... |
1 |
#include <trace/syscall.h> |
1c569f026 tracing: Create g... |
2 |
#include <trace/events/syscalls.h> |
5a0e3ad6a include cleanup: ... |
3 |
#include <linux/slab.h> |
ee08c6ecc tracing/ftrace: s... |
4 |
#include <linux/kernel.h> |
56d82e000 kernel: Add <linu... |
5 |
#include <linux/module.h> /* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */ |
fb34a08c3 tracing: Add trac... |
6 |
#include <linux/ftrace.h> |
cdd6c482c perf: Do the big ... |
7 |
#include <linux/perf_event.h> |
ee08c6ecc tracing/ftrace: s... |
8 9 10 11 |
#include <asm/syscall.h> #include "trace_output.h" #include "trace.h" |
5be71b61f tracing/syscalls:... |
12 |
static DEFINE_MUTEX(syscall_trace_lock); |
fb34a08c3 tracing: Add trac... |
13 14 |
static int sys_refcount_enter; static int sys_refcount_exit; |
57421dbbd tracing: Convert ... |
15 16 |
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
ee08c6ecc tracing/ftrace: s... |
17 |
|
2239291ae tracing: Remove p... |
18 19 20 21 |
static int syscall_enter_register(struct ftrace_event_call *event, enum trace_reg type); static int syscall_exit_register(struct ftrace_event_call *event, enum trace_reg type); |
2e33af029 tracing: Move fie... |
22 23 24 25 26 27 28 29 30 31 |
static int syscall_enter_define_fields(struct ftrace_event_call *call); static int syscall_exit_define_fields(struct ftrace_event_call *call); static struct list_head * syscall_get_enter_fields(struct ftrace_event_call *call) { struct syscall_metadata *entry = call->data; return &entry->enter_fields; } |
80decc70a tracing: Move pri... |
32 |
struct trace_event_functions enter_syscall_print_funcs = { |
7f85803a2 tracing: Remove s... |
33 |
.trace = print_syscall_enter, |
80decc70a tracing: Move pri... |
34 35 36 |
}; struct trace_event_functions exit_syscall_print_funcs = { |
7f85803a2 tracing: Remove s... |
37 |
.trace = print_syscall_exit, |
80decc70a tracing: Move pri... |
38 |
}; |
2239291ae tracing: Remove p... |
39 |
struct ftrace_event_class event_class_syscall_enter = { |
7f85803a2 tracing: Remove s... |
40 41 42 43 44 |
.system = "syscalls", .reg = syscall_enter_register, .define_fields = syscall_enter_define_fields, .get_fields = syscall_get_enter_fields, .raw_init = init_syscall_trace, |
2239291ae tracing: Remove p... |
45 46 47 |
}; struct ftrace_event_class event_class_syscall_exit = { |
7f85803a2 tracing: Remove s... |
48 49 50 51 52 |
.system = "syscalls", .reg = syscall_exit_register, .define_fields = syscall_exit_define_fields, .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields), .raw_init = init_syscall_trace, |
8f0820183 tracing: Create c... |
53 |
}; |
3d56e331b tracing: Replace ... |
54 55 |
extern struct syscall_metadata *__start_syscalls_metadata[]; extern struct syscall_metadata *__stop_syscalls_metadata[]; |
c44fc7708 tracing: Move sys... |
56 57 |
static struct syscall_metadata **syscalls_metadata; |
b2d554968 tracing/syscalls:... |
58 59 60 61 62 63 64 65 66 67 68 69 |
#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) { /* * Only compare after the "sys" prefix. Archs that use * syscall wrappers may have syscalls symbols aliases prefixed * with "SyS" instead of "sys", leading to an unwanted * mismatch. */ return !strcmp(sym + 3, name + 3); } #endif |
3d56e331b tracing: Replace ... |
70 71 |
static __init struct syscall_metadata * find_syscall_meta(unsigned long syscall) |
c44fc7708 tracing: Move sys... |
72 |
{ |
3d56e331b tracing: Replace ... |
73 74 |
struct syscall_metadata **start; struct syscall_metadata **stop; |
c44fc7708 tracing: Move sys... |
75 |
char str[KSYM_SYMBOL_LEN]; |
3d56e331b tracing: Replace ... |
76 77 |
start = __start_syscalls_metadata; stop = __stop_syscalls_metadata; |
c44fc7708 tracing: Move sys... |
78 |
kallsyms_lookup(syscall, NULL, NULL, NULL, str); |
ae07f551c tracing/syscalls:... |
79 80 |
if (arch_syscall_match_sym_name(str, "sys_ni_syscall")) return NULL; |
c44fc7708 tracing: Move sys... |
81 |
for ( ; start < stop; start++) { |
b2d554968 tracing/syscalls:... |
82 |
if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name)) |
3d56e331b tracing: Replace ... |
83 |
return *start; |
c44fc7708 tracing: Move sys... |
84 85 86 87 88 89 90 91 92 93 94 |
} return NULL; } static struct syscall_metadata *syscall_nr_to_meta(int nr) { if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) return NULL; return syscalls_metadata[nr]; } |
bed1ffca0 tracing/syscalls:... |
95 |
enum print_line_t |
a9a577638 tracing: Allow ev... |
96 97 |
print_syscall_enter(struct trace_iterator *iter, int flags, struct trace_event *event) |
bed1ffca0 tracing/syscalls:... |
98 99 100 101 102 103 |
{ struct trace_seq *s = &iter->seq; struct trace_entry *ent = iter->ent; struct syscall_trace_enter *trace; struct syscall_metadata *entry; int i, ret, syscall; |
64c12e044 tracing: Add indi... |
104 |
trace = (typeof(trace))ent; |
bed1ffca0 tracing/syscalls:... |
105 |
syscall = trace->nr; |
bed1ffca0 tracing/syscalls:... |
106 |
entry = syscall_nr_to_meta(syscall); |
64c12e044 tracing: Add indi... |
107 |
|
bed1ffca0 tracing/syscalls:... |
108 109 |
if (!entry) goto end; |
32c0edaea tracing: Remove d... |
110 |
if (entry->enter_event->event.type != ent->type) { |
64c12e044 tracing: Add indi... |
111 112 113 |
WARN_ON_ONCE(1); goto end; } |
bed1ffca0 tracing/syscalls:... |
114 115 116 117 118 119 |
ret = trace_seq_printf(s, "%s(", entry->name); if (!ret) return TRACE_TYPE_PARTIAL_LINE; for (i = 0; i < entry->nb_args; i++) { /* parameter types */ |
ba8b3a40b tracing/syscalls:... |
120 |
if (trace_flags & TRACE_ITER_VERBOSE) { |
bed1ffca0 tracing/syscalls:... |
121 122 123 124 125 |
ret = trace_seq_printf(s, "%s ", entry->types[i]); if (!ret) return TRACE_TYPE_PARTIAL_LINE; } /* parameter values */ |
4539f0770 tracing/syscalls:... |
126 |
ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i], |
bed1ffca0 tracing/syscalls:... |
127 |
trace->args[i], |
4539f0770 tracing/syscalls:... |
128 |
i == entry->nb_args - 1 ? "" : ", "); |
bed1ffca0 tracing/syscalls:... |
129 130 131 |
if (!ret) return TRACE_TYPE_PARTIAL_LINE; } |
4539f0770 tracing/syscalls:... |
132 133 134 |
ret = trace_seq_putc(s, ')'); if (!ret) return TRACE_TYPE_PARTIAL_LINE; |
bed1ffca0 tracing/syscalls:... |
135 |
end: |
4539f0770 tracing/syscalls:... |
136 137 138 139 |
ret = trace_seq_putc(s, ' '); if (!ret) return TRACE_TYPE_PARTIAL_LINE; |
bed1ffca0 tracing/syscalls:... |
140 141 142 143 |
return TRACE_TYPE_HANDLED; } enum print_line_t |
a9a577638 tracing: Allow ev... |
144 145 |
print_syscall_exit(struct trace_iterator *iter, int flags, struct trace_event *event) |
bed1ffca0 tracing/syscalls:... |
146 147 148 149 150 151 152 |
{ struct trace_seq *s = &iter->seq; struct trace_entry *ent = iter->ent; struct syscall_trace_exit *trace; int syscall; struct syscall_metadata *entry; int ret; |
64c12e044 tracing: Add indi... |
153 |
trace = (typeof(trace))ent; |
bed1ffca0 tracing/syscalls:... |
154 |
syscall = trace->nr; |
bed1ffca0 tracing/syscalls:... |
155 |
entry = syscall_nr_to_meta(syscall); |
64c12e044 tracing: Add indi... |
156 |
|
bed1ffca0 tracing/syscalls:... |
157 158 159 160 161 |
if (!entry) { trace_seq_printf(s, " "); return TRACE_TYPE_HANDLED; } |
32c0edaea tracing: Remove d... |
162 |
if (entry->exit_event->event.type != ent->type) { |
64c12e044 tracing: Add indi... |
163 164 165 |
WARN_ON_ONCE(1); return TRACE_TYPE_UNHANDLED; } |
bed1ffca0 tracing/syscalls:... |
166 167 168 169 170 171 172 173 |
ret = trace_seq_printf(s, "%s -> 0x%lx ", entry->name, trace->ret); if (!ret) return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_HANDLED; } |
e6971969c tracing/syscalls:... |
174 175 176 177 178 |
extern char *__bad_type_size(void); #define SYSCALL_FIELD(type, name) \ sizeof(type) != sizeof(trace.name) ? \ __bad_type_size() : \ |
26a50744b tracing/events: A... |
179 180 |
#type, #name, offsetof(typeof(trace), name), \ sizeof(trace.name), is_signed_type(type) |
e6971969c tracing/syscalls:... |
181 |
|
50307a45f tracing/syscalls:... |
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
static int __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) { int i; int pos = 0; /* When len=0, we just calculate the needed length */ #define LEN_OR_ZERO (len ? len - pos : 0) pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); for (i = 0; i < entry->nb_args; i++) { pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", entry->args[i], sizeof(unsigned long), i == entry->nb_args - 1 ? "" : ", "); } pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); for (i = 0; i < entry->nb_args; i++) { pos += snprintf(buf + pos, LEN_OR_ZERO, ", ((unsigned long)(REC->%s))", entry->args[i]); } #undef LEN_OR_ZERO /* return the length of print_fmt */ return pos; } static int set_syscall_print_fmt(struct ftrace_event_call *call) { char *print_fmt; int len; struct syscall_metadata *entry = call->data; if (entry->enter_event != call) { call->print_fmt = "\"0x%lx\", REC->ret"; return 0; } /* First: called with 0 length to calculate the needed length */ len = __set_enter_print_fmt(entry, NULL, 0); print_fmt = kmalloc(len + 1, GFP_KERNEL); if (!print_fmt) return -ENOMEM; /* Second: actually write the @print_fmt */ __set_enter_print_fmt(entry, print_fmt, len + 1); call->print_fmt = print_fmt; return 0; } static void free_syscall_print_fmt(struct ftrace_event_call *call) { struct syscall_metadata *entry = call->data; if (entry->enter_event == call) kfree(call->print_fmt); } |
2e33af029 tracing: Move fie... |
242 |
static int syscall_enter_define_fields(struct ftrace_event_call *call) |
540b7b8d6 tracing/syscalls:... |
243 244 |
{ struct syscall_trace_enter trace; |
31c16b133 trace_syscalls: S... |
245 |
struct syscall_metadata *meta = call->data; |
540b7b8d6 tracing/syscalls:... |
246 |
int ret; |
540b7b8d6 tracing/syscalls:... |
247 248 |
int i; int offset = offsetof(typeof(trace), args); |
0f1ef51d2 trace_syscalls: A... |
249 250 251 |
ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); if (ret) return ret; |
540b7b8d6 tracing/syscalls:... |
252 |
for (i = 0; i < meta->nb_args; i++) { |
aeaeae118 tracing: Restore ... |
253 254 |
ret = trace_define_field(call, meta->types[i], meta->args[i], offset, |
43b51ead3 tracing/filters: ... |
255 256 |
sizeof(unsigned long), 0, FILTER_OTHER); |
540b7b8d6 tracing/syscalls:... |
257 258 259 260 261 |
offset += sizeof(unsigned long); } return ret; } |
2e33af029 tracing: Move fie... |
262 |
static int syscall_exit_define_fields(struct ftrace_event_call *call) |
540b7b8d6 tracing/syscalls:... |
263 264 265 |
{ struct syscall_trace_exit trace; int ret; |
0f1ef51d2 trace_syscalls: A... |
266 267 268 |
ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); if (ret) return ret; |
26a50744b tracing/events: A... |
269 |
ret = trace_define_field(call, SYSCALL_FIELD(long, ret), |
43b51ead3 tracing/filters: ... |
270 |
FILTER_OTHER); |
540b7b8d6 tracing/syscalls:... |
271 272 273 |
return ret; } |
38516ab59 tracing: Let trac... |
274 |
void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id) |
ee08c6ecc tracing/ftrace: s... |
275 |
{ |
bed1ffca0 tracing/syscalls:... |
276 277 278 |
struct syscall_trace_enter *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; |
e77405ad8 tracing: pass aro... |
279 |
struct ring_buffer *buffer; |
bed1ffca0 tracing/syscalls:... |
280 |
int size; |
ee08c6ecc tracing/ftrace: s... |
281 282 283 |
int syscall_nr; syscall_nr = syscall_get_nr(current, regs); |
cd0980fc8 tracing: Check in... |
284 285 |
if (syscall_nr < 0) return; |
fb34a08c3 tracing: Add trac... |
286 287 |
if (!test_bit(syscall_nr, enabled_enter_syscalls)) return; |
ee08c6ecc tracing/ftrace: s... |
288 |
|
bed1ffca0 tracing/syscalls:... |
289 290 291 292 293 |
sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; |
fcc19438d trace_syscalls: R... |
294 |
event = trace_current_buffer_lock_reserve(&buffer, |
32c0edaea tracing: Remove d... |
295 |
sys_data->enter_event->event.type, size, 0, 0); |
bed1ffca0 tracing/syscalls:... |
296 297 298 299 300 301 |
if (!event) return; entry = ring_buffer_event_data(event); entry->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); |
e77405ad8 tracing: pass aro... |
302 303 304 |
if (!filter_current_check_discard(buffer, sys_data->enter_event, entry, event)) trace_current_buffer_unlock_commit(buffer, event, 0, 0); |
ee08c6ecc tracing/ftrace: s... |
305 |
} |
38516ab59 tracing: Let trac... |
306 |
void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret) |
ee08c6ecc tracing/ftrace: s... |
307 |
{ |
bed1ffca0 tracing/syscalls:... |
308 309 310 |
struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; |
e77405ad8 tracing: pass aro... |
311 |
struct ring_buffer *buffer; |
ee08c6ecc tracing/ftrace: s... |
312 313 314 |
int syscall_nr; syscall_nr = syscall_get_nr(current, regs); |
cd0980fc8 tracing: Check in... |
315 316 |
if (syscall_nr < 0) return; |
fb34a08c3 tracing: Add trac... |
317 318 |
if (!test_bit(syscall_nr, enabled_exit_syscalls)) return; |
ee08c6ecc tracing/ftrace: s... |
319 |
|
bed1ffca0 tracing/syscalls:... |
320 321 322 |
sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; |
fcc19438d trace_syscalls: R... |
323 |
event = trace_current_buffer_lock_reserve(&buffer, |
32c0edaea tracing: Remove d... |
324 |
sys_data->exit_event->event.type, sizeof(*entry), 0, 0); |
bed1ffca0 tracing/syscalls:... |
325 326 327 328 329 330 |
if (!event) return; entry = ring_buffer_event_data(event); entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); |
e77405ad8 tracing: pass aro... |
331 332 333 |
if (!filter_current_check_discard(buffer, sys_data->exit_event, entry, event)) trace_current_buffer_unlock_commit(buffer, event, 0, 0); |
ee08c6ecc tracing/ftrace: s... |
334 |
} |
bd1a5c849 tracing: Ftrace d... |
335 |
int reg_event_syscall_enter(struct ftrace_event_call *call) |
ee08c6ecc tracing/ftrace: s... |
336 |
{ |
fb34a08c3 tracing: Add trac... |
337 338 |
int ret = 0; int num; |
fb34a08c3 tracing: Add trac... |
339 |
|
c252f6579 trace_syscalls: A... |
340 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
3773b389b tracing/syscalls:... |
341 |
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) |
fb34a08c3 tracing: Add trac... |
342 343 344 |
return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_enter) |
38516ab59 tracing: Let trac... |
345 |
ret = register_trace_sys_enter(ftrace_syscall_enter, NULL); |
3b8e42738 tracing: Move a p... |
346 |
if (!ret) { |
fb34a08c3 tracing: Add trac... |
347 348 349 350 351 |
set_bit(num, enabled_enter_syscalls); sys_refcount_enter++; } mutex_unlock(&syscall_trace_lock); return ret; |
ee08c6ecc tracing/ftrace: s... |
352 |
} |
bd1a5c849 tracing: Ftrace d... |
353 |
void unreg_event_syscall_enter(struct ftrace_event_call *call) |
ee08c6ecc tracing/ftrace: s... |
354 |
{ |
fb34a08c3 tracing: Add trac... |
355 |
int num; |
ee08c6ecc tracing/ftrace: s... |
356 |
|
c252f6579 trace_syscalls: A... |
357 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
3773b389b tracing/syscalls:... |
358 |
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) |
fb34a08c3 tracing: Add trac... |
359 360 361 362 363 |
return; mutex_lock(&syscall_trace_lock); sys_refcount_enter--; clear_bit(num, enabled_enter_syscalls); if (!sys_refcount_enter) |
38516ab59 tracing: Let trac... |
364 |
unregister_trace_sys_enter(ftrace_syscall_enter, NULL); |
fb34a08c3 tracing: Add trac... |
365 366 |
mutex_unlock(&syscall_trace_lock); } |
ee08c6ecc tracing/ftrace: s... |
367 |
|
bd1a5c849 tracing: Ftrace d... |
368 |
int reg_event_syscall_exit(struct ftrace_event_call *call) |
ee08c6ecc tracing/ftrace: s... |
369 |
{ |
fb34a08c3 tracing: Add trac... |
370 371 |
int ret = 0; int num; |
fb34a08c3 tracing: Add trac... |
372 |
|
c252f6579 trace_syscalls: A... |
373 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
3773b389b tracing/syscalls:... |
374 |
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) |
fb34a08c3 tracing: Add trac... |
375 376 377 |
return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_exit) |
38516ab59 tracing: Let trac... |
378 |
ret = register_trace_sys_exit(ftrace_syscall_exit, NULL); |
3b8e42738 tracing: Move a p... |
379 |
if (!ret) { |
fb34a08c3 tracing: Add trac... |
380 381 |
set_bit(num, enabled_exit_syscalls); sys_refcount_exit++; |
ee08c6ecc tracing/ftrace: s... |
382 |
} |
fb34a08c3 tracing: Add trac... |
383 384 385 |
mutex_unlock(&syscall_trace_lock); return ret; } |
ee08c6ecc tracing/ftrace: s... |
386 |
|
bd1a5c849 tracing: Ftrace d... |
387 |
void unreg_event_syscall_exit(struct ftrace_event_call *call) |
fb34a08c3 tracing: Add trac... |
388 389 |
{ int num; |
ee08c6ecc tracing/ftrace: s... |
390 |
|
c252f6579 trace_syscalls: A... |
391 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
3773b389b tracing/syscalls:... |
392 |
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) |
fb34a08c3 tracing: Add trac... |
393 394 395 396 397 |
return; mutex_lock(&syscall_trace_lock); sys_refcount_exit--; clear_bit(num, enabled_exit_syscalls); if (!sys_refcount_exit) |
38516ab59 tracing: Let trac... |
398 |
unregister_trace_sys_exit(ftrace_syscall_exit, NULL); |
fb34a08c3 tracing: Add trac... |
399 |
mutex_unlock(&syscall_trace_lock); |
ee08c6ecc tracing/ftrace: s... |
400 |
} |
fb34a08c3 tracing: Add trac... |
401 |
|
a1301da09 trace_syscalls: R... |
402 403 404 |
int init_syscall_trace(struct ftrace_event_call *call) { int id; |
ba976970c tracing/syscalls:... |
405 406 407 408 409 410 411 412 413 |
int num; num = ((struct syscall_metadata *)call->data)->syscall_nr; if (num < 0 || num >= NR_syscalls) { pr_debug("syscall %s metadata not mapped, disabling ftrace event ", ((struct syscall_metadata *)call->data)->name); return -ENOSYS; } |
a1301da09 trace_syscalls: R... |
414 |
|
50307a45f tracing/syscalls:... |
415 416 |
if (set_syscall_print_fmt(call) < 0) return -ENOMEM; |
c7ef3a900 tracing: Have sys... |
417 418 419 |
id = trace_event_raw_init(call); if (id < 0) { |
50307a45f tracing/syscalls:... |
420 |
free_syscall_print_fmt(call); |
c7ef3a900 tracing: Have sys... |
421 |
return id; |
50307a45f tracing/syscalls:... |
422 |
} |
c7ef3a900 tracing: Have sys... |
423 424 |
return id; |
a1301da09 trace_syscalls: R... |
425 |
} |
c763ba06b tracing/syscalls:... |
426 |
unsigned long __init __weak arch_syscall_addr(int nr) |
e7b8e675d tracing: Unify ar... |
427 428 429 |
{ return (unsigned long)sys_call_table[nr]; } |
c44fc7708 tracing: Move sys... |
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
int __init init_ftrace_syscalls(void) { struct syscall_metadata *meta; unsigned long addr; int i; syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls, GFP_KERNEL); if (!syscalls_metadata) { WARN_ON(1); return -ENOMEM; } for (i = 0; i < NR_syscalls; i++) { addr = arch_syscall_addr(i); meta = find_syscall_meta(addr); |
c252f6579 trace_syscalls: A... |
446 447 448 449 |
if (!meta) continue; meta->syscall_nr = i; |
c44fc7708 tracing: Move sys... |
450 451 452 453 454 455 |
syscalls_metadata[i] = meta; } return 0; } core_initcall(init_ftrace_syscalls); |
07b139c8c perf events: Remo... |
456 |
#ifdef CONFIG_PERF_EVENTS |
19007a67a tracing: Support ... |
457 |
|
97d5a2200 perf: Drop the ob... |
458 459 460 461 |
static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls); static int sys_perf_refcount_enter; static int sys_perf_refcount_exit; |
f4b5ffccc tracing: Add perf... |
462 |
|
38516ab59 tracing: Let trac... |
463 |
static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) |
f4b5ffccc tracing: Add perf... |
464 465 |
{ struct syscall_metadata *sys_data; |
20ab4425a tracing: Allocate... |
466 |
struct syscall_trace_enter *rec; |
1c024eca5 perf, trace: Opti... |
467 |
struct hlist_head *head; |
f4b5ffccc tracing: Add perf... |
468 |
int syscall_nr; |
4ed7c92d6 perf_events: Undo... |
469 |
int rctx; |
19007a67a tracing: Support ... |
470 |
int size; |
f4b5ffccc tracing: Add perf... |
471 472 |
syscall_nr = syscall_get_nr(current, regs); |
97d5a2200 perf: Drop the ob... |
473 |
if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) |
f4b5ffccc tracing: Add perf... |
474 475 476 477 478 |
return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; |
19007a67a tracing: Support ... |
479 480 481 482 |
/* get the size after alignment with the u32 buffer size field */ size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec); size = ALIGN(size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); |
97d5a2200 perf: Drop the ob... |
483 484 |
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "perf buffer not large enough")) |
20ab4425a tracing: Allocate... |
485 |
return; |
97d5a2200 perf: Drop the ob... |
486 |
rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size, |
ff5f149b6 Merge branch 'per... |
487 |
sys_data->enter_event->event.type, regs, &rctx); |
430ad5a60 perf: Factorize t... |
488 489 |
if (!rec) return; |
20ab4425a tracing: Allocate... |
490 |
|
20ab4425a tracing: Allocate... |
491 492 493 |
rec->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, (unsigned long *)&rec->args); |
1c024eca5 perf, trace: Opti... |
494 |
|
3771f0771 perf_events, trac... |
495 |
head = this_cpu_ptr(sys_data->enter_event->perf_events); |
1c024eca5 perf, trace: Opti... |
496 |
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); |
f4b5ffccc tracing: Add perf... |
497 |
} |
97d5a2200 perf: Drop the ob... |
498 |
int perf_sysenter_enable(struct ftrace_event_call *call) |
f4b5ffccc tracing: Add perf... |
499 500 501 |
{ int ret = 0; int num; |
3bbe84e9d trace_syscalls: S... |
502 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
f4b5ffccc tracing: Add perf... |
503 504 |
mutex_lock(&syscall_trace_lock); |
97d5a2200 perf: Drop the ob... |
505 |
if (!sys_perf_refcount_enter) |
38516ab59 tracing: Let trac... |
506 |
ret = register_trace_sys_enter(perf_syscall_enter, NULL); |
f4b5ffccc tracing: Add perf... |
507 508 509 510 |
if (ret) { pr_info("event trace: Could not activate" "syscall entry trace point"); } else { |
97d5a2200 perf: Drop the ob... |
511 512 |
set_bit(num, enabled_perf_enter_syscalls); sys_perf_refcount_enter++; |
f4b5ffccc tracing: Add perf... |
513 514 515 516 |
} mutex_unlock(&syscall_trace_lock); return ret; } |
97d5a2200 perf: Drop the ob... |
517 |
void perf_sysenter_disable(struct ftrace_event_call *call) |
f4b5ffccc tracing: Add perf... |
518 519 |
{ int num; |
3bbe84e9d trace_syscalls: S... |
520 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
f4b5ffccc tracing: Add perf... |
521 522 |
mutex_lock(&syscall_trace_lock); |
97d5a2200 perf: Drop the ob... |
523 524 525 |
sys_perf_refcount_enter--; clear_bit(num, enabled_perf_enter_syscalls); if (!sys_perf_refcount_enter) |
38516ab59 tracing: Let trac... |
526 |
unregister_trace_sys_enter(perf_syscall_enter, NULL); |
f4b5ffccc tracing: Add perf... |
527 528 |
mutex_unlock(&syscall_trace_lock); } |
38516ab59 tracing: Let trac... |
529 |
static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) |
f4b5ffccc tracing: Add perf... |
530 531 |
{ struct syscall_metadata *sys_data; |
20ab4425a tracing: Allocate... |
532 |
struct syscall_trace_exit *rec; |
1c024eca5 perf, trace: Opti... |
533 |
struct hlist_head *head; |
f4b5ffccc tracing: Add perf... |
534 |
int syscall_nr; |
4ed7c92d6 perf_events: Undo... |
535 |
int rctx; |
20ab4425a tracing: Allocate... |
536 |
int size; |
f4b5ffccc tracing: Add perf... |
537 538 |
syscall_nr = syscall_get_nr(current, regs); |
97d5a2200 perf: Drop the ob... |
539 |
if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) |
f4b5ffccc tracing: Add perf... |
540 541 542 543 544 |
return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; |
20ab4425a tracing: Allocate... |
545 546 547 |
/* We can probably do that at build time */ size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); size -= sizeof(u32); |
19007a67a tracing: Support ... |
548 |
|
20ab4425a tracing: Allocate... |
549 550 551 552 |
/* * Impossible, but be paranoid with the future * How to put this check outside runtime? */ |
97d5a2200 perf: Drop the ob... |
553 554 |
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "exit event has grown above perf buffer size")) |
20ab4425a tracing: Allocate... |
555 |
return; |
97d5a2200 perf: Drop the ob... |
556 |
rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size, |
ff5f149b6 Merge branch 'per... |
557 |
sys_data->exit_event->event.type, regs, &rctx); |
430ad5a60 perf: Factorize t... |
558 559 |
if (!rec) return; |
20ab4425a tracing: Allocate... |
560 |
|
20ab4425a tracing: Allocate... |
561 562 |
rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); |
3771f0771 perf_events, trac... |
563 |
head = this_cpu_ptr(sys_data->exit_event->perf_events); |
1c024eca5 perf, trace: Opti... |
564 |
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); |
f4b5ffccc tracing: Add perf... |
565 |
} |
97d5a2200 perf: Drop the ob... |
566 |
int perf_sysexit_enable(struct ftrace_event_call *call) |
f4b5ffccc tracing: Add perf... |
567 568 569 |
{ int ret = 0; int num; |
3bbe84e9d trace_syscalls: S... |
570 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
f4b5ffccc tracing: Add perf... |
571 572 |
mutex_lock(&syscall_trace_lock); |
97d5a2200 perf: Drop the ob... |
573 |
if (!sys_perf_refcount_exit) |
38516ab59 tracing: Let trac... |
574 |
ret = register_trace_sys_exit(perf_syscall_exit, NULL); |
f4b5ffccc tracing: Add perf... |
575 576 |
if (ret) { pr_info("event trace: Could not activate" |
6574658b3 tracing: Fix typo... |
577 |
"syscall exit trace point"); |
f4b5ffccc tracing: Add perf... |
578 |
} else { |
97d5a2200 perf: Drop the ob... |
579 580 |
set_bit(num, enabled_perf_exit_syscalls); sys_perf_refcount_exit++; |
f4b5ffccc tracing: Add perf... |
581 582 583 584 |
} mutex_unlock(&syscall_trace_lock); return ret; } |
97d5a2200 perf: Drop the ob... |
585 |
void perf_sysexit_disable(struct ftrace_event_call *call) |
f4b5ffccc tracing: Add perf... |
586 587 |
{ int num; |
3bbe84e9d trace_syscalls: S... |
588 |
num = ((struct syscall_metadata *)call->data)->syscall_nr; |
f4b5ffccc tracing: Add perf... |
589 590 |
mutex_lock(&syscall_trace_lock); |
97d5a2200 perf: Drop the ob... |
591 592 593 |
sys_perf_refcount_exit--; clear_bit(num, enabled_perf_exit_syscalls); if (!sys_perf_refcount_exit) |
38516ab59 tracing: Let trac... |
594 |
unregister_trace_sys_exit(perf_syscall_exit, NULL); |
f4b5ffccc tracing: Add perf... |
595 596 |
mutex_unlock(&syscall_trace_lock); } |
07b139c8c perf events: Remo... |
597 |
#endif /* CONFIG_PERF_EVENTS */ |
f4b5ffccc tracing: Add perf... |
598 |
|
2239291ae tracing: Remove p... |
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 |
static int syscall_enter_register(struct ftrace_event_call *event, enum trace_reg type) { switch (type) { case TRACE_REG_REGISTER: return reg_event_syscall_enter(event); case TRACE_REG_UNREGISTER: unreg_event_syscall_enter(event); return 0; #ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: return perf_sysenter_enable(event); case TRACE_REG_PERF_UNREGISTER: perf_sysenter_disable(event); return 0; #endif } return 0; } static int syscall_exit_register(struct ftrace_event_call *event, enum trace_reg type) { switch (type) { case TRACE_REG_REGISTER: return reg_event_syscall_exit(event); case TRACE_REG_UNREGISTER: unreg_event_syscall_exit(event); return 0; #ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: return perf_sysexit_enable(event); case TRACE_REG_PERF_UNREGISTER: perf_sysexit_disable(event); return 0; #endif } return 0; } |