X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.cpp;h=f7d232ffc01aadb346b5fdf6d8c4928ea5163727;hp=5b4fc086bde52ce333f8cf72cf9f3d627b0cc000;hb=HEAD;hpb=56047f5a23df5c2c583a102b8015bbec5a7da9f1 diff --git a/src/bin/lttng-sessiond/kernel.cpp b/src/bin/lttng-sessiond/kernel.cpp index 5b4fc086b..4cc51a279 100644 --- a/src/bin/lttng-sessiond/kernel.cpp +++ b/src/bin/lttng-sessiond/kernel.cpp @@ -16,7 +16,6 @@ #include "lttng-syscall.hpp" #include "modprobe.hpp" #include "notification-thread-commands.hpp" -#include "rotate.hpp" #include "sessiond-config.hpp" #include "tracker.hpp" #include "utils.hpp" @@ -25,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -50,18 +50,71 @@ #include #include +namespace { /* * Key used to reference a channel between the sessiond and the consumer. This * is only read and updated with the session_list lock held. */ -static uint64_t next_kernel_channel_key; +uint64_t next_kernel_channel_key; -static const char *module_proc_lttng = "/proc/lttng"; +const char *module_proc_lttng = "/proc/lttng"; -static int kernel_tracer_fd = -1; -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; +int kernel_tracer_fd = -1; +nonstd::optional kernel_tracer_status = nonstd::nullopt; +int kernel_tracer_event_notifier_group_fd = -1; +int kernel_tracer_event_notifier_group_notification_fd = -1; +struct cds_lfht *kernel_token_to_event_notifier_rule_ht; + +const char *kernel_tracer_status_to_str(lttng_kernel_tracer_status status) +{ + switch (status) { + case LTTNG_KERNEL_TRACER_STATUS_INITIALIZED: + return "LTTNG_KERNEL_TRACER_STATUS_INITIALIZED"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE"; + } + + abort(); +} + +/* + * 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 +} /* namespace */ /* * Add context on a kernel channel. @@ -452,7 +505,7 @@ static int userspace_probe_add_callsite(const struct lttng_userspace_probe_locat 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."); @@ -479,7 +532,7 @@ static int userspace_probe_add_callsite(const struct lttng_userspace_probe_locat 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"); @@ -1924,6 +1977,48 @@ error: return ret; } +/* + * Get current kernel tracer status + */ +enum lttng_kernel_tracer_status get_kernel_tracer_status() +{ + if (!kernel_tracer_status) { + return LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN; + } + + return *kernel_tracer_status; +} + +/* + * Sets the kernel tracer status based on the positive errno code + */ +void set_kernel_tracer_status_from_modules_ret(int code) +{ + switch (code) { + case ENOENT: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING); + break; + } + case ENOKEY: + case EKEYEXPIRED: + case EKEYREVOKED: + case EKEYREJECTED: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE); + break; + } + default: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN); + break; + } + } +} + /* * Setup necessary data for kernel tracer action. */ @@ -1932,9 +2027,15 @@ int init_kernel_tracer() int ret; bool is_root = !getuid(); + const auto log_status_on_exit = lttng::make_scope_exit([]() noexcept { + DBG_FMT("Kernel tracer status set to `{}`", + kernel_tracer_status_to_str(*kernel_tracer_status)); + }); + /* Modprobe lttng kernel modules */ ret = modprobe_lttng_control(); if (ret < 0) { + set_kernel_tracer_status_from_modules_ret(-ret); goto error; } @@ -1942,17 +2043,22 @@ int init_kernel_tracer() kernel_tracer_fd = open(module_proc_lttng, O_RDWR); if (kernel_tracer_fd < 0) { DBG("Failed to open %s", module_proc_lttng); + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG); goto error_open; } /* Validate kernel version */ ret = kernel_validate_version(&the_kernel_tracer_version, &the_kernel_tracer_abi_version); if (ret < 0) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH); goto error_version; } ret = modprobe_lttng_data(); if (ret < 0) { + set_kernel_tracer_status_from_modules_ret(-ret); goto error_modules; } @@ -1969,6 +2075,8 @@ int init_kernel_tracer() ret = kernel_supports_event_notifiers(); if (ret < 0) { ERR("Failed to check for kernel tracer event notifier support"); + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_modules; } ret = kernel_create_event_notifier_group(&kernel_tracer_event_notifier_group_fd); @@ -1983,6 +2091,8 @@ int init_kernel_tracer() &kernel_tracer_event_notifier_group_notification_fd); if (error_code_ret != LTTNG_OK) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_modules; } @@ -1991,12 +2101,16 @@ int init_kernel_tracer() 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; + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); 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, nullptr); if (!kernel_token_to_event_notifier_rule_ht) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_token_ht; } } @@ -2012,6 +2126,8 @@ int init_kernel_tracer() "work for this session daemon."); } + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_INITIALIZED); return 0; error_version: @@ -2056,6 +2172,8 @@ error: WARN("No kernel tracer available"); kernel_tracer_fd = -1; if (!is_root) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT); return LTTNG_ERR_NEED_ROOT_SESSIOND; } else { return LTTNG_ERR_KERN_NA; @@ -2111,6 +2229,7 @@ void cleanup_kernel_tracer() kernel_tracer_fd = -1; } + kernel_tracer_status = nonstd::nullopt; free(syscall_table); }