X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttng-syscalls.c;h=4596ccfc1280f82eaefdd0b5b6462bceffee0f8f;hb=1a228b02e01297f749be52a09ece0b16e3840c2d;hp=4d8490e97889dcb3ed5463d34f806a899bf378c1;hpb=49e2f4c4735fb9a6b039c842bb1238b8ca64d062;p=lttng-modules.git diff --git a/lttng-syscalls.c b/lttng-syscalls.c index 4d8490e9..4596ccfc 100644 --- a/lttng-syscalls.c +++ b/lttng-syscalls.c @@ -1,23 +1,10 @@ -/* +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * * lttng-syscalls.c * * LTTng syscall probes. * * Copyright (C) 2010-2012 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include @@ -34,11 +21,12 @@ #include #include -#include "lib/bitfield.h" -#include "wrapper/tracepoint.h" -#include "wrapper/file.h" -#include "wrapper/rcu.h" -#include "lttng-events.h" +#include +#include +#include +#include +#include +#include #ifndef CONFIG_COMPAT # ifndef is_compat_task @@ -46,6 +34,11 @@ # endif #endif +/* in_compat_syscall appears in kernel 4.6. */ +#ifndef in_compat_syscall + #define in_compat_syscall() is_compat_task() +#endif + enum sc_type { SC_TYPE_ENTRY, SC_TYPE_EXIT, @@ -77,6 +70,20 @@ struct oldold_utsname; struct old_utsname; struct sel_arg_struct; struct mmap_arg_struct; +struct file_handle; +struct user_msghdr; + +/* + * Forward declaration for kernels >= 5.6 + */ +struct timex; +struct timeval; +struct itimerval; +struct itimerspec; + +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0)) +typedef __kernel_old_time_t time_t; +#endif #ifdef IA32_NR_syscalls #define NR_compat_syscalls IA32_NR_syscalls @@ -90,14 +97,14 @@ struct mmap_arg_struct; #define LTTNG_PACKAGE_BUILD #define CREATE_TRACE_POINTS #define TP_MODULE_NOINIT -#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers +#define TRACE_INCLUDE_PATH instrumentation/syscalls/headers #define PARAMS(args...) args /* Handle unknown syscalls */ #undef TRACE_SYSTEM #define TRACE_SYSTEM syscalls_unknown -#include "instrumentation/syscalls/headers/syscalls_unknown.h" +#include #undef TRACE_SYSTEM #define SC_ENTER @@ -117,25 +124,29 @@ struct mmap_arg_struct; #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ PARAMS(_fields)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \ LTTNG_TRACEPOINT_EVENT_CODE(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), \ - PARAMS(_fields)) + PARAMS(_locvar), PARAMS(_code_pre), \ + PARAMS(_fields), PARAMS(_code_post)) #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_entry_##_template, syscall_entry_##_name) +/* Enumerations only defined at first inclusion. */ +#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values) \ + LTTNG_TRACEPOINT_ENUM(_name, PARAMS(_values)) #undef TRACE_SYSTEM #define TRACE_SYSTEM syscall_entry_integers #define TRACE_INCLUDE_FILE syscalls_integers -#include "instrumentation/syscalls/headers/syscalls_integers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM #define TRACE_SYSTEM syscall_entry_pointers #define TRACE_INCLUDE_FILE syscalls_pointers -#include "instrumentation/syscalls/headers/syscalls_pointers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM +#undef SC_LTTNG_TRACEPOINT_ENUM #undef SC_LTTNG_TRACEPOINT_EVENT_CODE #undef SC_LTTNG_TRACEPOINT_EVENT #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS @@ -146,27 +157,31 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call enter */ #define TP_PROBE_CB(_template) &syscall_entry_probe +#define LTTNG_SC_COMPAT #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ PARAMS(_fields)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \ LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) + PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post)) #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_entry_##_template, \ compat_syscall_entry_##_name) +/* Enumerations only defined at inital inclusion (not here). */ +#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values) #define TRACE_SYSTEM compat_syscall_entry_integers #define TRACE_INCLUDE_FILE compat_syscalls_integers -#include "instrumentation/syscalls/headers/compat_syscalls_integers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM #define TRACE_SYSTEM compat_syscall_entry_pointers #define TRACE_INCLUDE_FILE compat_syscalls_pointers -#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM +#undef SC_LTTNG_TRACEPOINT_ENUM #undef SC_LTTNG_TRACEPOINT_EVENT_CODE #undef SC_LTTNG_TRACEPOINT_EVENT #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS @@ -174,6 +189,7 @@ struct mmap_arg_struct; #undef TP_PROBE_CB #undef _TRACE_SYSCALLS_INTEGERS_H #undef _TRACE_SYSCALLS_POINTERS_H +#undef LTTNG_SC_COMPAT #undef SC_ENTER @@ -193,24 +209,27 @@ struct mmap_arg_struct; #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ PARAMS(_fields)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \ LTTNG_TRACEPOINT_EVENT_CODE(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) + PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post)) #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_exit_##_template, \ syscall_exit_##_name) +/* Enumerations only defined at inital inclusion (not here). */ +#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values) #define TRACE_SYSTEM syscall_exit_integers #define TRACE_INCLUDE_FILE syscalls_integers -#include "instrumentation/syscalls/headers/syscalls_integers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM #define TRACE_SYSTEM syscall_exit_pointers #define TRACE_INCLUDE_FILE syscalls_pointers -#include "instrumentation/syscalls/headers/syscalls_pointers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM +#undef SC_LTTNG_TRACEPOINT_ENUM #undef SC_LTTNG_TRACEPOINT_EVENT_CODE #undef SC_LTTNG_TRACEPOINT_EVENT #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS @@ -222,27 +241,31 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call exit */ #define TP_PROBE_CB(_template) &syscall_exit_probe +#define LTTNG_SC_COMPAT #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ PARAMS(_fields)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _fields) \ +#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \ LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_locvar), PARAMS(_code), PARAMS(_fields)) + PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post)) #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \ LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_fields)) #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \ LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_exit_##_template, \ compat_syscall_exit_##_name) +/* Enumerations only defined at inital inclusion (not here). */ +#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values) #define TRACE_SYSTEM compat_syscall_exit_integers #define TRACE_INCLUDE_FILE compat_syscalls_integers -#include "instrumentation/syscalls/headers/compat_syscalls_integers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM #define TRACE_SYSTEM compat_syscall_exit_pointers #define TRACE_INCLUDE_FILE compat_syscalls_pointers -#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h" +#include #undef TRACE_INCLUDE_FILE #undef TRACE_SYSTEM +#undef SC_LTTNG_TRACEPOINT_ENUM #undef SC_LTTNG_TRACEPOINT_EVENT_CODE #undef SC_LTTNG_TRACEPOINT_EVENT #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS @@ -250,6 +273,7 @@ struct mmap_arg_struct; #undef TP_PROBE_CB #undef _TRACE_SYSCALLS_INTEGERS_H #undef _TRACE_SYSCALLS_POINTERS_H +#undef LTTNG_SC_COMPAT #undef SC_EXIT @@ -282,8 +306,8 @@ struct trace_syscall_entry { /* Syscall enter tracing table */ static const struct trace_syscall_entry sc_table[] = { -#include "instrumentation/syscalls/headers/syscalls_integers.h" -#include "instrumentation/syscalls/headers/syscalls_pointers.h" +#include +#include }; #undef TRACE_SYSCALL_TABLE @@ -297,8 +321,8 @@ static const struct trace_syscall_entry sc_table[] = { /* Compat syscall enter table */ const struct trace_syscall_entry compat_sc_table[] = { -#include "instrumentation/syscalls/headers/compat_syscalls_integers.h" -#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h" +#include +#include }; #undef SC_ENTER @@ -319,8 +343,8 @@ const struct trace_syscall_entry compat_sc_table[] = { /* Syscall exit table */ static const struct trace_syscall_entry sc_exit_table[] = { -#include "instrumentation/syscalls/headers/syscalls_integers.h" -#include "instrumentation/syscalls/headers/syscalls_pointers.h" +#include +#include }; #undef TRACE_SYSCALL_TABLE @@ -334,8 +358,8 @@ static const struct trace_syscall_entry sc_exit_table[] = { /* Compat syscall exit table */ const struct trace_syscall_entry compat_sc_exit_table[] = { -#include "instrumentation/syscalls/headers/compat_syscalls_integers.h" -#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h" +#include +#include }; #undef SC_EXIT @@ -343,17 +367,19 @@ const struct trace_syscall_entry compat_sc_exit_table[] = { #undef CREATE_SYSCALL_TABLE struct lttng_syscall_filter { - DECLARE_BITMAP(sc, NR_syscalls); - DECLARE_BITMAP(sc_compat, NR_compat_syscalls); + DECLARE_BITMAP(sc_entry, NR_syscalls); + DECLARE_BITMAP(sc_exit, NR_syscalls); + DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls); + DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls); }; static void syscall_entry_unknown(struct lttng_event *event, struct pt_regs *regs, unsigned int id) { - unsigned long args[UNKNOWN_SYSCALL_NRARGS]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); - if (unlikely(is_compat_task())) + lttng_syscall_get_arguments(current, regs, args); + if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_entry_unknown(event, id, args); else __event_probe__syscall_entry_unknown(event, id, args); @@ -366,30 +392,24 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) const struct trace_syscall_entry *table, *entry; size_t table_len; - if (unlikely(is_compat_task())) { - struct lttng_syscall_filter *filter; + if (unlikely(in_compat_syscall())) { + struct lttng_syscall_filter *filter = chan->sc_filter; - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_compat_syscalls - || !test_bit(id, filter->sc_compat)) { - /* System call filtered out. */ - return; - } + if (id < 0 || id >= NR_compat_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_entry))) { + /* System call filtered out. */ + return; } table = compat_sc_table; table_len = ARRAY_SIZE(compat_sc_table); unknown_event = chan->sc_compat_unknown; } else { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_syscalls - || !test_bit(id, filter->sc)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_entry))) { + /* System call filtered out. */ + return; } table = sc_table; table_len = ARRAY_SIZE(sc_table); @@ -399,7 +419,7 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) syscall_entry_unknown(unknown_event, regs, id); return; } - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) event = chan->compat_sc_table[id]; else event = chan->sc_table[id]; @@ -421,9 +441,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) case 1: { void (*fptr)(void *__data, unsigned long arg0) = entry->func; - unsigned long args[1]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0]); break; } @@ -432,9 +452,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) void (*fptr)(void *__data, unsigned long arg0, unsigned long arg1) = entry->func; - unsigned long args[2]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1]); break; } @@ -444,9 +464,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg0, unsigned long arg1, unsigned long arg2) = entry->func; - unsigned long args[3]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2]); break; } @@ -457,9 +477,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg1, unsigned long arg2, unsigned long arg3) = entry->func; - unsigned long args[4]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3]); break; } @@ -471,9 +491,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg2, unsigned long arg3, unsigned long arg4) = entry->func; - unsigned long args[5]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3], args[4]); break; } @@ -486,9 +506,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg3, unsigned long arg4, unsigned long arg5) = entry->func; - unsigned long args[6]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3], args[4], args[5]); break; @@ -501,10 +521,10 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) static void syscall_exit_unknown(struct lttng_event *event, struct pt_regs *regs, int id, long ret) { - unsigned long args[UNKNOWN_SYSCALL_NRARGS]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); - if (unlikely(is_compat_task())) + lttng_syscall_get_arguments(current, regs, args); + if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_exit_unknown(event, id, ret, args); else @@ -520,30 +540,24 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) long id; id = syscall_get_nr(current, regs); - if (unlikely(is_compat_task())) { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_compat_syscalls - || !test_bit(id, filter->sc_compat)) { - /* System call filtered out. */ - return; - } + if (unlikely(in_compat_syscall())) { + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_compat_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_exit))) { + /* System call filtered out. */ + return; } table = compat_sc_exit_table; table_len = ARRAY_SIZE(compat_sc_exit_table); unknown_event = chan->compat_sc_exit_unknown; } else { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_syscalls - || !test_bit(id, filter->sc)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_exit))) { + /* System call filtered out. */ + return; } table = sc_exit_table; table_len = ARRAY_SIZE(sc_exit_table); @@ -553,7 +567,7 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) syscall_exit_unknown(unknown_event, regs, id, ret); return; } - if (unlikely(is_compat_task())) + if (unlikely(in_compat_syscall())) event = chan->compat_sc_exit_table[id]; else event = chan->sc_exit_table[id]; @@ -577,9 +591,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) void (*fptr)(void *__data, long ret, unsigned long arg0) = entry->func; - unsigned long args[1]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0]); break; } @@ -589,9 +603,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) long ret, unsigned long arg0, unsigned long arg1) = entry->func; - unsigned long args[2]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1]); break; } @@ -602,9 +616,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg0, unsigned long arg1, unsigned long arg2) = entry->func; - unsigned long args[3]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2]); break; } @@ -616,9 +630,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg1, unsigned long arg2, unsigned long arg3) = entry->func; - unsigned long args[4]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3]); break; } @@ -631,9 +645,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg2, unsigned long arg3, unsigned long arg4) = entry->func; - unsigned long args[5]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3], args[4]); break; } @@ -647,9 +661,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg3, unsigned long arg4, unsigned long arg5) = entry->func; - unsigned long args[6]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3], args[4], args[5]); break; @@ -689,27 +703,23 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, memset(&ev, 0, sizeof(ev)); switch (type) { case SC_TYPE_ENTRY: - strncpy(ev.name, SYSCALL_ENTRY_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; break; case SC_TYPE_EXIT: - strncpy(ev.name, SYSCALL_EXIT_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; break; case SC_TYPE_COMPAT_ENTRY: - strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; break; case SC_TYPE_COMPAT_EXIT: - strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR, - LTTNG_KERNEL_SYM_NAME_LEN); - break; - default: - BUG_ON(1); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; break; } - strncat(ev.name, desc->name, - LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1); + strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN - 1); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; chan_table[i] = _lttng_event_create(chan, &ev, filter, @@ -736,7 +746,7 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) struct lttng_kernel_event ev; int ret; - wrapper_vmalloc_sync_all(); + wrapper_vmalloc_sync_mappings(); if (!chan->sc_table) { /* create syscall table mapping syscall to events */ @@ -779,6 +789,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; chan->sc_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -796,6 +808,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -813,6 +827,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -830,6 +846,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); WARN_ON_ONCE(!chan->sc_exit_unknown); @@ -859,6 +877,14 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) if (ret) return ret; #endif + + if (!chan->sc_filter) { + chan->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter), + GFP_KERNEL); + if (!chan->sc_filter) + return -ENOMEM; + } + if (!chan->sys_enter_registered) { ret = lttng_wrapper_tracepoint_probe_register("sys_enter", (void *) syscall_entry_probe, chan); @@ -893,20 +919,24 @@ int lttng_syscalls_unregister(struct lttng_channel *chan) if (!chan->sc_table) return 0; if (chan->sys_enter_registered) { - ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit", - (void *) syscall_exit_probe, chan); + ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter", + (void *) syscall_entry_probe, chan); if (ret) return ret; chan->sys_enter_registered = 0; } if (chan->sys_exit_registered) { - ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter", - (void *) syscall_entry_probe, chan); + ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit", + (void *) syscall_exit_probe, chan); if (ret) return ret; chan->sys_exit_registered = 0; } - /* lttng_event destroy will be performed by lttng_session_destroy() */ + return 0; +} + +int lttng_syscalls_destroy(struct lttng_channel *chan) +{ kfree(chan->sc_table); kfree(chan->sc_exit_table); #ifdef CONFIG_COMPAT @@ -969,136 +999,156 @@ uint32_t get_sc_tables_len(void) return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table); } -int lttng_syscall_filter_enable(struct lttng_channel *chan, - const char *name) +static +const char *get_syscall_name(struct lttng_event *event) { - int syscall_nr, compat_syscall_nr, ret; - struct lttng_syscall_filter *filter; + size_t prefix_len = 0; - WARN_ON_ONCE(!chan->sc_table); + WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL); - if (!name) { - /* Enable all system calls by removing filter */ - if (chan->sc_filter) { - filter = chan->sc_filter; - rcu_assign_pointer(chan->sc_filter, NULL); - synchronize_trace(); - kfree(filter); + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + prefix_len = strlen(SYSCALL_ENTRY_STR); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR); + break; } - chan->syscall_all = 1; - return 0; - } - - if (!chan->sc_filter) { - if (chan->syscall_all) { - /* - * All syscalls are already enabled. - */ - return -EEXIST; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + prefix_len = strlen(SYSCALL_EXIT_STR); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR); + break; } - filter = kzalloc(sizeof(struct lttng_syscall_filter), - GFP_KERNEL); - if (!filter) - return -ENOMEM; - } else { - filter = chan->sc_filter; + break; } - syscall_nr = get_syscall_nr(name); - compat_syscall_nr = get_compat_syscall_nr(name); - if (syscall_nr < 0 && compat_syscall_nr < 0) { - ret = -ENOENT; - goto error; + WARN_ON_ONCE(prefix_len == 0); + return event->desc->name + prefix_len; +} + +int lttng_syscall_filter_enable(struct lttng_channel *chan, + struct lttng_event *event) +{ + struct lttng_syscall_filter *filter = chan->sc_filter; + const char *syscall_name; + unsigned long *bitmap; + int syscall_nr; + + WARN_ON_ONCE(!chan->sc_table); + + syscall_name = get_syscall_name(event); + + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + syscall_nr = get_syscall_nr(syscall_name); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + syscall_nr = get_compat_syscall_nr(syscall_name); + break; + default: + return -EINVAL; } - if (syscall_nr >= 0) { - if (test_bit(syscall_nr, filter->sc)) { - ret = -EEXIST; - goto error; + if (syscall_nr < 0) + return -ENOENT; + + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_entry; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_entry; + break; + default: + return -EINVAL; } - bitmap_set(filter->sc, syscall_nr, 1); - } - if (compat_syscall_nr >= 0) { - if (test_bit(compat_syscall_nr, filter->sc_compat)) { - ret = -EEXIST; - goto error; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_exit; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_exit; + break; + default: + return -EINVAL; } - bitmap_set(filter->sc_compat, compat_syscall_nr, 1); + break; + default: + return -EINVAL; } - if (!chan->sc_filter) - rcu_assign_pointer(chan->sc_filter, filter); + if (test_bit(syscall_nr, bitmap)) + return -EEXIST; + bitmap_set(bitmap, syscall_nr, 1); return 0; - -error: - if (!chan->sc_filter) - kfree(filter); - return ret; } int lttng_syscall_filter_disable(struct lttng_channel *chan, - const char *name) + struct lttng_event *event) { - int syscall_nr, compat_syscall_nr, ret; - struct lttng_syscall_filter *filter; + struct lttng_syscall_filter *filter = chan->sc_filter; + const char *syscall_name; + unsigned long *bitmap; + int syscall_nr; WARN_ON_ONCE(!chan->sc_table); - if (!chan->sc_filter) { - if (!chan->syscall_all) - return -EEXIST; - filter = kzalloc(sizeof(struct lttng_syscall_filter), - GFP_KERNEL); - if (!filter) - return -ENOMEM; - /* Trace all system calls, then apply disable. */ - bitmap_set(filter->sc, 0, NR_syscalls); - bitmap_set(filter->sc_compat, 0, NR_compat_syscalls); - } else { - filter = chan->sc_filter; - } - - if (!name) { - /* Fail if all syscalls are already disabled. */ - if (bitmap_empty(filter->sc, NR_syscalls) - && bitmap_empty(filter->sc_compat, - NR_compat_syscalls)) { - ret = -EEXIST; - goto error; - } + syscall_name = get_syscall_name(event); - /* Disable all system calls */ - bitmap_clear(filter->sc, 0, NR_syscalls); - bitmap_clear(filter->sc_compat, 0, NR_compat_syscalls); - goto apply_filter; - } - syscall_nr = get_syscall_nr(name); - compat_syscall_nr = get_compat_syscall_nr(name); - if (syscall_nr < 0 && compat_syscall_nr < 0) { - ret = -ENOENT; - goto error; + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + syscall_nr = get_syscall_nr(syscall_name); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + syscall_nr = get_compat_syscall_nr(syscall_name); + break; + default: + return -EINVAL; } - if (syscall_nr >= 0) { - if (!test_bit(syscall_nr, filter->sc)) { - ret = -EEXIST; - goto error; + if (syscall_nr < 0) + return -ENOENT; + + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_entry; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_entry; + break; + default: + return -EINVAL; } - bitmap_clear(filter->sc, syscall_nr, 1); - } - if (compat_syscall_nr >= 0) { - if (!test_bit(compat_syscall_nr, filter->sc_compat)) { - ret = -EEXIST; - goto error; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_exit; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_exit; + break; + default: + return -EINVAL; } - bitmap_clear(filter->sc_compat, compat_syscall_nr, 1); + break; + default: + return -EINVAL; } -apply_filter: - if (!chan->sc_filter) - rcu_assign_pointer(chan->sc_filter, filter); - chan->syscall_all = 0; - return 0; + if (!test_bit(syscall_nr, bitmap)) + return -EEXIST; + bitmap_clear(bitmap, syscall_nr, 1); -error: - if (!chan->sc_filter) - kfree(filter); - return ret; + return 0; } static @@ -1212,6 +1262,9 @@ const struct file_operations lttng_syscall_list_fops = { .release = seq_release, }; +/* + * A syscall is enabled if it is traced for either entry or exit. + */ long lttng_channel_syscall_mask(struct lttng_channel *channel, struct lttng_kernel_syscall_mask __user *usyscall_mask) { @@ -1235,11 +1288,12 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, filter = channel->sc_filter; for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) { - bool state; + char state; if (channel->sc_table) { - if (filter) - state = test_bit(bit, filter->sc); + if (!READ_ONCE(channel->syscall_all) && filter) + state = test_bit(bit, filter->sc_entry) + || test_bit(bit, filter->sc_exit); else state = 1; } else { @@ -1248,12 +1302,14 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, bt_bitfield_write_be(tmp_mask, char, bit, 1, state); } for (; bit < sc_tables_len; bit++) { - bool state; + char state; if (channel->compat_sc_table) { - if (filter) + if (!READ_ONCE(channel->syscall_all) && filter) state = test_bit(bit - ARRAY_SIZE(sc_table), - filter->sc_compat); + filter->sc_compat_entry) + || test_bit(bit - ARRAY_SIZE(sc_table), + filter->sc_compat_exit); else state = 1; } else { @@ -1289,10 +1345,6 @@ int lttng_abi_syscall_list(void) if (ret < 0) goto open_error; fd_install(file_fd, syscall_list_file); - if (file_fd < 0) { - ret = file_fd; - goto fd_error; - } return file_fd; open_error: