X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=lttng-syscalls.c;h=b43dd570a029d1d5b1a4f6160765ae31668a6003;hb=31f8bf794172102e9758928b481856c4a8800a7f;hp=1fc86c8eed5a84502d05b0efd893b052975d06ca;hpb=082d4946ed719b3c73759ae88753c511624af952;p=lttng-modules.git diff --git a/lttng-syscalls.c b/lttng-syscalls.c index 1fc86c8e..b43dd570 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,9 +21,12 @@ #include #include -#include "lib/bitfield.h" -#include "wrapper/tracepoint.h" -#include "lttng-events.h" +#include +#include +#include +#include +#include +#include #ifndef CONFIG_COMPAT # ifndef is_compat_task @@ -44,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, @@ -75,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 (LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)) +typedef __kernel_old_time_t time_t; +#endif #ifdef IA32_NR_syscalls #define NR_compat_syscalls IA32_NR_syscalls @@ -88,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 @@ -112,29 +121,32 @@ struct mmap_arg_struct; /* Hijack probe callback for system call enter */ #undef TP_PROBE_CB #define TP_PROBE_CB(_template) &syscall_entry_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_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(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_struct), PARAMS(_assign), \ - PARAMS(_printk)) + 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 @@ -145,30 +157,31 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call enter */ #define TP_PROBE_CB(_template) &syscall_entry_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#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(_struct), PARAMS(_assign), \ - PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_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(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + 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 @@ -176,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 @@ -192,29 +206,30 @@ struct mmap_arg_struct; /* Hijack probe callback for system call exit */ #define TP_PROBE_CB(_template) &syscall_exit_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \ LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \ - PARAMS(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_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(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + 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 @@ -226,29 +241,31 @@ struct mmap_arg_struct; /* Hijack probe callback for compat system call exit */ #define TP_PROBE_CB(_template) &syscall_exit_probe -#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \ +#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(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \ + PARAMS(_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(_struct), PARAMS(_assign), PARAMS(_printk)) -#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \ - LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \ - PARAMS(_assign), PARAMS(_printk)) + 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 @@ -256,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 @@ -288,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 @@ -303,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 @@ -325,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 @@ -340,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 @@ -349,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); @@ -372,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 = 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 = 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); @@ -405,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]; @@ -427,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; } @@ -438,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; } @@ -450,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; } @@ -463,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; } @@ -477,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; } @@ -492,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; @@ -507,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 @@ -526,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 = 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 = 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); @@ -559,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]; @@ -583,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; } @@ -595,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; } @@ -608,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; } @@ -622,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; } @@ -637,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; } @@ -653,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; @@ -665,7 +673,10 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) } } -/* noinline to diminish caller stack size */ +/* + * noinline to diminish caller stack size. + * Should be called with sessions lock held. + */ static int fill_table(const struct trace_syscall_entry *table, size_t table_len, struct lttng_event **chan_table, struct lttng_channel *chan, @@ -692,31 +703,27 @@ 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_NOOP; - chan_table[i] = lttng_event_create(chan, &ev, filter, - desc); + ev.instrumentation = LTTNG_KERNEL_SYSCALL; + chan_table[i] = _lttng_event_create(chan, &ev, filter, + desc, ev.instrumentation); WARN_ON_ONCE(!chan_table[i]); if (IS_ERR(chan_table[i])) { /* @@ -731,12 +738,15 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, return 0; } +/* + * Should be called with sessions lock held. + */ 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 */ @@ -778,9 +788,12 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_unknown = lttng_event_create(chan, &ev, filter, - desc); + 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); WARN_ON_ONCE(!chan->sc_unknown); if (IS_ERR(chan->sc_unknown)) { return PTR_ERR(chan->sc_unknown); @@ -794,9 +807,12 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter, - desc); + 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); WARN_ON_ONCE(!chan->sc_unknown); if (IS_ERR(chan->sc_compat_unknown)) { return PTR_ERR(chan->sc_compat_unknown); @@ -810,9 +826,12 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->compat_sc_exit_unknown = lttng_event_create(chan, &ev, - filter, desc); + 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); WARN_ON_ONCE(!chan->compat_sc_exit_unknown); if (IS_ERR(chan->compat_sc_exit_unknown)) { return PTR_ERR(chan->compat_sc_exit_unknown); @@ -826,9 +845,11 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) memset(&ev, 0, sizeof(ev)); strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; - ev.instrumentation = LTTNG_KERNEL_NOOP; - chan->sc_exit_unknown = lttng_event_create(chan, &ev, filter, - desc); + 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); if (IS_ERR(chan->sc_exit_unknown)) { return PTR_ERR(chan->sc_exit_unknown); @@ -856,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); @@ -890,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 @@ -966,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 @@ -1209,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) { @@ -1232,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 { @@ -1245,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 { @@ -1269,7 +1328,7 @@ int lttng_abi_syscall_list(void) struct file *syscall_list_file; int file_fd, ret; - file_fd = get_unused_fd(); + file_fd = lttng_get_unused_fd(); if (file_fd < 0) { ret = file_fd; goto fd_error; @@ -1286,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: