/* * AUTOFILLER * In simple cases in which extracting an event is just a matter of moving the * arguments to the buffer, this filler can be used instead of writing a * filler function. * The arguments to extract are be specified in g_ppm_events. */ int f_sys_autofill(struct event_filler_arguments *args, const struct ppm_event_entry *evinfo) { int res; unsigned long val; u32 j; int64_t retval; ASSERT(evinfo->n_autofill_args <= PPM_MAX_AUTOFILL_ARGS); for (j = 0; j < evinfo->n_autofill_args; j++) { if (evinfo->autofill_args[j].id >= 0) { #ifndef __NR_socketcall /* * Regular argument */ syscall_get_arguments(current, args->regs, evinfo->autofill_args[j].id, 1, &val); #else if (evinfo->paramtype == APT_SOCK) { val = args->socketcall_args[evinfo->autofill_args[j].id]; } else { /* * Regular argument */ syscall_get_arguments(current, args->regs, evinfo->autofill_args[j].id, 1, &val); } #endif res = val_to_ring(args, val, 0, true); if (unlikely(res != PPM_SUCCESS)) return res; } else if (evinfo->autofill_args[j].id == AF_ID_RETVAL) { /* * Return value */ retval = (int64_t)(long)syscall_get_return_value(current, args->regs); res = val_to_ring(args, retval, 0, false); if (unlikely(res != PPM_SUCCESS)) return res; } else if (evinfo->autofill_args[j].id == AF_ID_USEDEFAULT) { /* * Default Value */ res = val_to_ring(args, evinfo->autofill_args[j].default_val, 0, false); if (unlikely(res != PPM_SUCCESS)) return res; } else { ASSERT(false); } } return add_sentinel(args); }
void ftrace_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; struct ring_buffer *buffer; int syscall_nr; syscall_nr = syscall_get_nr(current, regs); if (syscall_nr < 0) return; if (!test_bit(syscall_nr, enabled_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; event = trace_current_buffer_lock_reserve(&buffer, sys_data->exit_id, sizeof(*entry), 0, 0); if (!event) return; entry = ring_buffer_event_data(event); entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); if (!filter_current_check_discard(buffer, sys_data->exit_event, entry, event)) trace_current_buffer_unlock_commit(buffer, event, 0, 0); }
/* Log a fork system call. * * This will log the return value, but only if it's not 0 (i.e., is in * the parent). */ static void handle_fork(struct filemon *fm, char op, is_at_enum is_at __maybe_unused, struct pt_regs *regs) { #ifndef FILEMON_PERFORMANCE_NO_FORK_FM struct pid *pid; #endif int scrv; scrv = syscall_get_return_value(current, regs); if (scrv == 0) /* The < 0 case was already handled. */ return; filemon_log(fm, op, "%i", scrv); #ifndef FILEMON_PERFORMANCE_NO_FORK_FM /* List is already locked */ pid = find_get_pid(scrv); if (pid >= 0) { struct fm_pids *s; s = kmalloc(sizeof(struct fm_pids), GFP_KERNEL); if (s) { s->pid = pid; LIST_ADD(&s->list, &fm->shead->list); } } #endif }
static void prof_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; struct syscall_trace_exit *rec; unsigned long flags; int syscall_nr; char *raw_data; int size; int cpu; syscall_nr = syscall_get_nr(current, regs); if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; /* We can probably do that at build time */ size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); size -= sizeof(u32); /* * Impossible, but be paranoid with the future * How to put this check outside runtime? */ if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, "exit event has grown above profile buffer size")) return; /* Protect the per cpu buffer, begin the rcu read side */ local_irq_save(flags); cpu = smp_processor_id(); if (in_nmi()) raw_data = rcu_dereference(trace_profile_buf_nmi); else raw_data = rcu_dereference(trace_profile_buf); if (!raw_data) goto end; raw_data = per_cpu_ptr(raw_data, cpu); /* zero the dead bytes from align to not leak stack to user */ *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; rec = (struct syscall_trace_exit *)raw_data; tracing_generic_entry_update(&rec->ent, 0, 0); rec->ent.type = sys_data->exit_id; rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); perf_tp_event(sys_data->exit_id, 0, 1, rec, size); end: local_irq_restore(flags); }
asmlinkage void syscall_trace_exit(struct pt_regs *regs) { audit_syscall_exit(regs); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_exit(regs, syscall_get_return_value(current, regs)); }
static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) { struct trace_array *tr = data; struct ftrace_event_file *ftrace_file; struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; struct ring_buffer *buffer; unsigned long irq_flags; int pc; int syscall_nr; syscall_nr = trace_get_syscall_nr(current, regs); if (syscall_nr < 0 || syscall_nr >= NR_syscalls) return; /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */ ftrace_file = rcu_dereference_sched(tr->exit_syscall_files[syscall_nr]); if (!ftrace_file) return; if (ftrace_trigger_soft_disabled(ftrace_file)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; local_save_flags(irq_flags); pc = preempt_count(); buffer = tr->trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, sys_data->exit_event->event.type, sizeof(*entry), irq_flags, pc); if (!event) return; entry = ring_buffer_event_data(event); entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); event_trigger_unlock_commit(ftrace_file, buffer, event, entry, irq_flags, pc); }
static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; struct syscall_trace_exit *rec; struct hlist_head *head; int syscall_nr; int rctx; int size; syscall_nr = trace_get_syscall_nr(current, regs); if (syscall_nr < 0) return; if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; /* We can probably do that at build time */ size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); size -= sizeof(u32); /* * Impossible, but be paranoid with the future * How to put this check outside runtime? */ if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "exit event has grown above perf buffer size")) return; rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size, sys_data->exit_event->event.type, regs, &rctx); if (!rec) return; rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); head = this_cpu_ptr(sys_data->exit_event->perf_events); perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); }
static void prof_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; struct syscall_trace_exit rec; int syscall_nr; syscall_nr = syscall_get_nr(current, regs); if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; tracing_generic_entry_update(&rec.ent, 0, 0); rec.ent.type = sys_data->exit_id; rec.nr = syscall_nr; rec.ret = syscall_get_return_value(current, regs); perf_tpcounter_event(sys_data->exit_id, 0, 1, &rec, sizeof(rec)); }
static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) { struct trace_array *tr = data; struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; struct ring_buffer *buffer; unsigned long irq_flags; int pc; int syscall_nr; syscall_nr = trace_get_syscall_nr(current, regs); if (syscall_nr < 0 || syscall_nr >= NR_syscalls) return; if (!test_bit(syscall_nr, tr->enabled_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; local_save_flags(irq_flags); pc = preempt_count(); buffer = tr->trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, sys_data->exit_event->event.type, sizeof(*entry), irq_flags, pc); if (!event) return; entry = ring_buffer_event_data(event); entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); if (!filter_current_check_discard(buffer, sys_data->exit_event, entry, event)) trace_current_buffer_unlock_commit(buffer, event, irq_flags, pc); }
static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; struct syscall_trace_exit *rec; struct hlist_head *head; int syscall_nr; int rctx; int size; syscall_nr = trace_get_syscall_nr(current, regs); if (syscall_nr < 0 || syscall_nr >= NR_syscalls) return; if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) return; head = this_cpu_ptr(sys_data->exit_event->perf_events); if (hlist_empty(head)) return; /* We can probably do that at build time */ size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); size -= sizeof(u32); rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size, sys_data->exit_event->event.type, NULL, &rctx); if (!rec) return; rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); }