#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"
#include <common/hashtable/utils.hpp>
#include <common/kernel-ctl/kernel-ctl.hpp>
#include <common/kernel-ctl/kernel-ioctl.hpp>
+#include <common/scope-exit.hpp>
#include <common/sessiond-comm/sessiond-comm.hpp>
#include <common/trace-chunk.hpp>
#include <common/tracker.hpp>
#include <sys/types.h>
#include <unistd.h>
+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<enum lttng_kernel_tracer_status> 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.
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.");
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");
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<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING);
+ break;
+ }
+ case ENOKEY:
+ case EKEYEXPIRED:
+ case EKEYREVOKED:
+ case EKEYREJECTED:
+ {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE);
+ break;
+ }
+ default:
+ {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN);
+ break;
+ }
+ }
+}
+
/*
* Setup necessary data for kernel tracer action.
*/
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;
}
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<enum lttng_kernel_tracer_status>(
+ 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<enum lttng_kernel_tracer_status>(
+ 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;
}
ret = kernel_supports_event_notifiers();
if (ret < 0) {
ERR("Failed to check for kernel tracer event notifier support");
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_modules;
}
ret = kernel_create_event_notifier_group(&kernel_tracer_event_notifier_group_fd);
&kernel_tracer_event_notifier_group_notification_fd);
if (error_code_ret != LTTNG_OK) {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_modules;
}
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<enum lttng_kernel_tracer_status>(
+ 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<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_token_ht;
}
}
"work for this session daemon.");
}
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(LTTNG_KERNEL_TRACER_STATUS_INITIALIZED);
return 0;
error_version:
WARN("No kernel tracer available");
kernel_tracer_fd = -1;
if (!is_root) {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT);
return LTTNG_ERR_NEED_ROOT_SESSIOND;
} else {
return LTTNG_ERR_KERN_NA;
kernel_tracer_fd = -1;
}
+ kernel_tracer_status = nonstd::nullopt;
free(syscall_table);
}