Fix: adding a user space probe fails on thumb functions
[lttng-tools.git] / src / bin / lttng-sessiond / kernel.c
index 03a358a0d3f1da9478ef220c3e93309298b469f7..4c5227189612d8d02c1a858e8c8308d452025035 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
  *
  * SPDX-License-Identifier: GPL-2.0-only
  *
 
 #include <lttng/userspace-probe.h>
 #include <lttng/userspace-probe-internal.h>
-#include <lttng/condition/on-event.h>
-#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/event-rule-matches.h>
+#include <lttng/condition/event-rule-matches-internal.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/userspace-probe-internal.h>
+#include <lttng/event-rule/kernel-uprobe-internal.h>
 
+#include "event-notifier-error-accounting.h"
 #include "lttng-sessiond.h"
 #include "lttng-syscall.h"
 #include "condition-internal.h"
@@ -41,6 +42,7 @@
 #include "kernel.h"
 #include "kernel-consumer.h"
 #include "kern-modules.h"
+#include "sessiond-config.h"
 #include "utils.h"
 #include "rotate.h"
 #include "modprobe.h"
@@ -60,6 +62,30 @@ static int kernel_tracer_event_notifier_group_fd = -1;
 static int kernel_tracer_event_notifier_group_notification_fd = -1;
 static struct cds_lfht *kernel_token_to_event_notifier_rule_ht;
 
+/*
+ * On some architectures, calling convention details are embedded in the symbol
+ * addresses. Uprobe requires a "clean" symbol offset (or at least, an address
+ * where an instruction boundary would be legal) to add
+ * instrumentation. sanitize_uprobe_offset implements that sanitization logic on
+ * a per-architecture basis.
+ */
+#if defined(__arm__) || defined(__aarch64__)
+static inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset)
+{
+       /*
+        * The least significant bit is used when branching to switch to thumb
+        * ISA. However, it's an invalid address for us; mask the least
+        * significant bit.
+        */
+       return raw_offset &= ~0b1;
+}
+#else /* defined(__arm__) || defined(__aarch64__) */
+static inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset)
+{
+       return raw_offset;
+}
+#endif
+
 /*
  * Add context on a kernel channel.
  *
@@ -434,7 +460,7 @@ int userspace_probe_add_callsite(
        switch (type) {
        case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
        {
-               struct lttng_kernel_event_callsite callsite;
+               struct lttng_kernel_abi_event_callsite callsite;
                uint64_t offset;
 
                ret = extract_userspace_probe_offset_function_elf(location,
@@ -444,7 +470,7 @@ int userspace_probe_add_callsite(
                        goto end;
                }
 
-               callsite.u.uprobe.offset = offset;
+               callsite.u.uprobe.offset = sanitize_uprobe_offset(offset);
                ret = kernctl_add_callsite(fd, &callsite);
                if (ret) {
                        WARN("Failed to add callsite to ELF userspace probe.");
@@ -458,7 +484,7 @@ int userspace_probe_add_callsite(
                int i;
                uint64_t *offsets = NULL;
                uint32_t offsets_count;
-               struct lttng_kernel_event_callsite callsite;
+               struct lttng_kernel_abi_event_callsite callsite;
 
                /*
                 * This call allocates the offsets buffer. This buffer must be freed
@@ -471,7 +497,7 @@ int userspace_probe_add_callsite(
                        goto end;
                }
                for (i = 0; i < offsets_count; i++) {
-                       callsite.u.uprobe.offset = offsets[i];
+                       callsite.u.uprobe.offset = sanitize_uprobe_offset(offsets[i]);
                        ret = kernctl_add_callsite(fd, &callsite);
                        if (ret) {
                                WARN("Failed to add callsite to SDT userspace probe");
@@ -540,9 +566,9 @@ static int userspace_probe_event_rule_add_callsites(
        assert(creds);
 
        event_rule_type = lttng_event_rule_get_type(rule);
-       assert(event_rule_type == LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE);
+       assert(event_rule_type == LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
 
-       status = lttng_event_rule_userspace_probe_get_location(rule, &location);
+       status = lttng_event_rule_kernel_uprobe_get_location(rule, &location);
        if (status != LTTNG_EVENT_RULE_STATUS_OK || !location) {
                ret = -1;
                goto end;
@@ -767,14 +793,8 @@ int kernel_disable_event(struct ltt_kernel_event *event)
 
        ret = kernctl_disable(event->fd);
        if (ret < 0) {
-               switch (-ret) {
-               case EEXIST:
-                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
-                       break;
-               default:
-                       PERROR("disable kernel event");
-                       break;
-               }
+               PERROR("Failed to disable kernel event: name = '%s', fd = %d",
+                               event->event->name, event->fd);
                goto error;
        }
 
@@ -803,15 +823,8 @@ int kernel_disable_event_notifier_rule(struct ltt_kernel_event_notifier_rule *ev
 
        ret = kernctl_disable(event->fd);
        if (ret < 0) {
-               switch (-ret) {
-               case EEXIST:
-                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
-                       break;
-               default:
-                       PERROR("Failed to disable kernel event notifier: fd = %d, token = %" PRIu64,
-                                       event->fd, event->token);
-                       break;
-               }
+               PERROR("Failed to disable kernel event notifier: fd = %d, token = %" PRIu64,
+                               event->fd, event->token);
                goto error;
        }
 
@@ -1504,8 +1517,8 @@ error:
 /*
  * Get kernel version and validate it.
  */
-int kernel_validate_version(struct lttng_kernel_tracer_version *version,
-               struct lttng_kernel_tracer_abi_version *abi_version)
+int kernel_validate_version(struct lttng_kernel_abi_tracer_version *version,
+               struct lttng_kernel_abi_tracer_abi_version *abi_version)
 {
        int ret;
 
@@ -1526,10 +1539,10 @@ int kernel_validate_version(struct lttng_kernel_tracer_version *version,
                ERR("Failed to retrieve lttng-modules ABI version");
                goto error;
        }
-       if (abi_version->major != LTTNG_MODULES_ABI_MAJOR_VERSION) {
+       if (abi_version->major != LTTNG_KERNEL_ABI_MAJOR_VERSION) {
                ERR("Kernel tracer ABI version (%d.%d) does not match the expected ABI major version (%d.*)",
                        abi_version->major, abi_version->minor,
-                       LTTNG_MODULES_ABI_MAJOR_VERSION);
+                       LTTNG_KERNEL_ABI_MAJOR_VERSION);
                goto error;
        }
        DBG2("Kernel tracer version validated (%d.%d, ABI %d.%d)",
@@ -1710,7 +1723,7 @@ enum lttng_error_code kernel_snapshot_record(
        }
 
        trace_path = setup_channel_trace_path(ksess->consumer,
-                       DEFAULT_KERNEL_TRACE_DIR, &consumer_path_offset);
+                       "", &consumer_path_offset);
        if (!trace_path) {
                status = LTTNG_ERR_INVALID;
                goto error;
@@ -1793,7 +1806,7 @@ static
 int kernel_tracer_abi_greater_or_equal(unsigned int major, unsigned int minor)
 {
        int ret;
-       struct lttng_kernel_tracer_abi_version abi;
+       struct lttng_kernel_abi_tracer_abi_version abi;
 
        ret = kernctl_tracer_abi_version(kernel_tracer_fd, &abi);
        if (ret < 0) {
@@ -1957,8 +1970,8 @@ int init_kernel_tracer(void)
        }
 
        /* Validate kernel version */
-       ret = kernel_validate_version(&kernel_tracer_version,
-                       &kernel_tracer_abi_version);
+       ret = kernel_validate_version(&the_kernel_tracer_version,
+                       &the_kernel_tracer_abi_version);
        if (ret < 0) {
                goto error_version;
        }
@@ -1989,7 +2002,8 @@ int init_kernel_tracer(void)
                WARN("Failed to create kernel event notifier group");
                kernel_tracer_event_notifier_group_fd = -1;
        } else {
-               const enum lttng_error_code error_code_ret =
+               enum event_notifier_error_accounting_status error_accounting_status;
+               enum lttng_error_code error_code_ret =
                                kernel_create_event_notifier_group_notification_fd(
                                                &kernel_tracer_event_notifier_group_notification_fd);
 
@@ -1997,6 +2011,14 @@ int init_kernel_tracer(void)
                        goto error_modules;
                }
 
+               error_accounting_status = event_notifier_error_accounting_register_kernel(
+                               kernel_tracer_event_notifier_group_fd);
+               if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+                       ERR("Failed to initialize event notifier error accounting for kernel tracer");
+                       error_code_ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING;
+                       goto error_modules;
+               }
+
                kernel_token_to_event_notifier_rule_ht = cds_lfht_new(
                                DEFAULT_HT_SIZE, 1, 0,
                                CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
@@ -2025,6 +2047,7 @@ error_version:
                PERROR("Failed to close kernel tracer file descriptor: fd = %d",
                                kernel_tracer_fd);
        }
+
        kernel_tracer_fd = -1;
        return LTTNG_ERR_KERN_VERSION;
 
@@ -2036,6 +2059,8 @@ error_token_ht:
                                kernel_tracer_event_notifier_group_notification_fd);
        }
 
+       kernel_tracer_event_notifier_group_notification_fd = -1;
+
 error_modules:
        ret = close(kernel_tracer_event_notifier_group_fd);
        if (ret) {
@@ -2043,12 +2068,16 @@ error_modules:
                                kernel_tracer_event_notifier_group_fd);
        }
 
+       kernel_tracer_event_notifier_group_fd = -1;
+
        ret = close(kernel_tracer_fd);
        if (ret) {
                PERROR("Failed to close kernel tracer file descriptor: fd = %d",
                                kernel_tracer_fd);
        }
 
+       kernel_tracer_fd = -1;
+
 error_open:
        modprobe_remove_lttng_control();
 
@@ -2068,7 +2097,7 @@ void cleanup_kernel_tracer(void)
        DBG2("Closing kernel event notifier group notification file descriptor");
        if (kernel_tracer_event_notifier_group_notification_fd >= 0) {
                int ret = notification_thread_command_remove_tracer_event_source(
-                               notification_thread_handle,
+                               the_notification_thread_handle,
                                kernel_tracer_event_notifier_group_notification_fd);
                if (ret != LTTNG_OK) {
                        ERR("Failed to remove kernel event notifier notification from notification thread");
@@ -2113,8 +2142,6 @@ void cleanup_kernel_tracer(void)
                kernel_tracer_fd = -1;
        }
 
-       DBG("Unloading kernel modules");
-       modprobe_remove_lttng_all();
        free(syscall_table);
 }
 
@@ -2298,7 +2325,7 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        enum lttng_condition_type condition_type;
        enum lttng_event_rule_type event_rule_type;
        struct ltt_kernel_event_notifier_rule *event_notifier_rule;
-       struct lttng_kernel_event_notifier kernel_event_notifier = {};
+       struct lttng_kernel_abi_event_notifier kernel_event_notifier = {};
        unsigned int capture_bytecode_count = 0, i;
        const struct lttng_condition *condition = NULL;
        const struct lttng_event_rule *event_rule = NULL;
@@ -2310,10 +2337,10 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        assert(condition);
 
        condition_type = lttng_condition_get_type(condition);
-       assert(condition_type == LTTNG_CONDITION_TYPE_ON_EVENT);
+       assert(condition_type == LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
 
        /* Does not acquire a reference. */
-       condition_status = lttng_condition_on_event_get_rule(
+       condition_status = lttng_condition_event_rule_matches_get_rule(
                        condition, &event_rule);
        assert(condition_status == LTTNG_CONDITION_STATUS_OK);
        assert(event_rule);
@@ -2322,6 +2349,8 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        assert(event_rule_type != LTTNG_EVENT_RULE_TYPE_UNKNOWN);
 
        error_code_ret = trace_kernel_create_event_notifier_rule(trigger, token,
+                       lttng_condition_event_rule_matches_get_error_counter_index(
+                                       condition),
                        &event_notifier_rule);
        if (error_code_ret != LTTNG_OK) {
                goto error;
@@ -2334,6 +2363,9 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        }
 
        kernel_event_notifier.event.token = event_notifier_rule->token;
+       kernel_event_notifier.error_counter_idx =
+                       lttng_condition_event_rule_matches_get_error_counter_index(
+                                       condition);
 
        fd = kernctl_create_event_notifier(
                        kernel_tracer_event_notifier_group_fd,
@@ -2386,7 +2418,7 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        }
 
        if (lttng_event_rule_get_type(event_rule) ==
-                       LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE) {
+                       LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE) {
                ret = userspace_probe_event_rule_add_callsites(
                                event_rule, creds, event_notifier_rule->fd);
                if (ret) {
@@ -2396,13 +2428,13 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        }
 
        /* Set the capture bytecode if any. */
-       cond_status = lttng_condition_on_event_get_capture_descriptor_count(
+       cond_status = lttng_condition_event_rule_matches_get_capture_descriptor_count(
                        condition, &capture_bytecode_count);
        assert(cond_status == LTTNG_CONDITION_STATUS_OK);
 
        for (i = 0; i < capture_bytecode_count; i++) {
                const struct lttng_bytecode *capture_bytecode =
-                               lttng_condition_on_event_get_capture_bytecode_at_index(
+                               lttng_condition_event_rule_matches_get_capture_bytecode_at_index(
                                                condition, i);
 
                if (capture_bytecode == NULL) {
@@ -2480,7 +2512,7 @@ enum lttng_error_code kernel_register_event_notifier(
        assert(condition);
 
        /* Does not acquire a reference to the event rule. */
-       status = lttng_condition_on_event_get_rule(
+       status = lttng_condition_event_rule_matches_get_rule(
                        condition, &event_rule);
        assert(status == LTTNG_CONDITION_STATUS_OK);
 
This page took 0.028608 seconds and 4 git commands to generate.