Fix unknown syscall support
[lttng-modules.git] / lttng-syscalls.c
index 28348abe350a7e3de15f2d0824745d6a11e42963..48eaf16027074108a83abcf21116ec08f7499291 100644 (file)
 
 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
 
+/*
+ * Take care of NOARGS not supported by mainline.
+ */
+#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
+#define DEFINE_EVENT_NOARGS(template, name)
+#define TRACE_EVENT_NOARGS(name, struct, assign, print)
+
 /*
  * Create LTTng tracepoint probes.
  */
@@ -28,8 +35,9 @@ static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
 #define TP_MODULE_OVERRIDE
 
 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
-
-#include "instrumentation/syscalls/headers/syscalls.h"
+#include "instrumentation/syscalls/headers/syscalls_integers.h"
+#include "instrumentation/syscalls/headers/syscalls_pointers.h"
+#include "instrumentation/syscalls/headers/syscalls_unknown.h"
 
 #undef TP_MODULE_OVERRIDE
 #undef TP_PROBE_CB
@@ -38,42 +46,59 @@ static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
 
 struct trace_syscall_entry {
        void *func;
-       const struct lttng_event_desc *desc;    /* Set dynamically */
+       const struct lttng_event_desc *desc;
        const struct lttng_event_field *fields;
        unsigned int nrargs;
 };
 
-static int sc_table_desc_filled;
-
 #define CREATE_SYSCALL_TABLE
 
 #undef TRACE_SYSCALL_TABLE
-#define TRACE_SYSCALL_TABLE(_name, _nr, _nrargs)               \
+#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs)    \
        [ _nr ] = {                                             \
-               .func = __event_probe__##_name,                 \
+               .func = __event_probe__##_template,             \
                .nrargs = (_nrargs),                            \
-               .fields = __event_fields___##_name,             \
+               .fields = __event_fields___##_template,         \
+               .desc = &__event_desc___##_name,                \
        },
 
 static struct trace_syscall_entry sc_table[] = {
-#include "instrumentation/syscalls/headers/syscalls.h"
+#include "instrumentation/syscalls/headers/syscalls_integers.h"
+#include "instrumentation/syscalls/headers/syscalls_pointers.h"
 };
 
+static int sc_table_filled;
+
 #undef CREATE_SYSCALL_TABLE
 
+static void syscall_entry_unknown(struct ltt_channel *chan,
+       struct pt_regs *regs, unsigned int id)
+{
+       unsigned long args[UNKNOWN_SYSCALL_NRARGS];
+       struct ltt_event *event;
+
+       event = chan->sc_unknown;
+       syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
+       __event_probe__sys_unknown(event, id, args);
+}
+
 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
 {
        struct trace_syscall_entry *entry;
        struct ltt_channel *chan = __data;
        struct ltt_event *event;
 
-       if (unlikely(id >= ARRAY_SIZE(sc_table)))
-               return;
-       entry = &sc_table[id];
-       if (unlikely(!entry->func))
+       if (unlikely(id >= ARRAY_SIZE(sc_table))) {
+               syscall_entry_unknown(chan, regs, id);
                return;
+       }
        event = chan->sc_table[id];
-       WARN_ON_ONCE(!event);
+       if (unlikely(!event)) {
+               syscall_entry_unknown(chan, regs, id);
+               return;
+       }
+       entry = &sc_table[id];
+       WARN_ON_ONCE(!entry);
 
        switch (entry->nrargs) {
        case 0:
@@ -163,47 +188,12 @@ static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
        }
 }
 
-static const struct lttng_event_desc *find_syscall_desc(unsigned int id)
-{
-       unsigned int i;
-
-       for (i = 0; i < __probe_desc___syscalls.nr_events; i++) {
-               if (__probe_desc___syscalls.event_desc[i].fields
-                               == sc_table[id].fields)
-                       return &__probe_desc___syscalls.event_desc[i];
-       }
-       WARN_ON_ONCE(1);
-       return NULL;
-}
-
-static void fill_sc_table_desc(void)
-{
-       unsigned int i;
-
-       if (sc_table_desc_filled)
-               return;
-       /*
-        * This is O(n^2), but rare. Eventually get the TRACE_EVENT code
-        * to emit per-event symbols to skip this.
-        */
-       for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
-               const struct lttng_event_desc **desc = &sc_table[i].desc;
-
-               if (!sc_table[i].func)
-                       continue;
-               (*desc) = find_syscall_desc(i);
-       }
-       sc_table_desc_filled = 1;
-}
-
-
 int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
 {
        unsigned int i;
        int ret;
 
        wrapper_vmalloc_sync_all();
-       fill_sc_table_desc();
 
        if (!chan->sc_table) {
                /* create syscall table mapping syscall to events */
@@ -213,13 +203,31 @@ int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
                        return -ENOMEM;
        }
 
+       if (!chan->sc_unknown) {
+               struct lttng_kernel_event ev;
+
+               const struct lttng_event_desc *desc =
+                       &__event_desc___sys_unknown;
+               memset(&ev, 0, sizeof(ev));
+               strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
+               ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
+               ev.instrumentation = LTTNG_KERNEL_NOOP;
+               chan->sc_unknown = ltt_event_create(chan, &ev, filter,
+                                                   desc);
+               if (!chan->sc_unknown) {
+                       return -EINVAL;
+               }
+       }
+
        /* Allocate events for each syscall, insert into table */
        for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
                struct lttng_kernel_event ev;
                const struct lttng_event_desc *desc = sc_table[i].desc;
 
-               if (!desc)
+               if (!desc) {
+                       /* Unknown syscall */
                        continue;
+               }
                /*
                 * Skip those already populated by previous failed
                 * register for this channel.
@@ -244,6 +252,18 @@ int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
        }
        ret = tracepoint_probe_register("sys_enter",
                        (void *) syscall_entry_probe, chan);
+       if (ret)
+               return ret;
+       /*
+        * We change the name of sys_exit tracepoint due to namespace
+        * conflict with sys_exit syscall entry.
+        */
+       ret = tracepoint_probe_register("sys_exit",
+                       (void *) __event_probe__exit_syscall, chan);
+       if (ret) {
+               WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
+                       (void *) syscall_entry_probe, chan));
+       }
        return ret;
 }
 
@@ -256,6 +276,10 @@ int lttng_syscalls_unregister(struct ltt_channel *chan)
 
        if (!chan->sc_table)
                return 0;
+       ret = tracepoint_probe_unregister("sys_exit",
+                       (void *) __event_probe__exit_syscall, chan);
+       if (ret)
+               return ret;
        ret = tracepoint_probe_unregister("sys_enter",
                        (void *) syscall_entry_probe, chan);
        if (ret)
This page took 0.027561 seconds and 4 git commands to generate.