From 56a9a0b750db49640129cb9b13cf384e9e82284c Mon Sep 17 00:00:00 2001 From: Olivier Dion Date: Wed, 22 Feb 2023 15:19:14 -0500 Subject: [PATCH] Fix: adding a user space probe fails on thumb functions MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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. 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. We were not masking the thumb bit, thus using the wrong address offset by one. Change-Id: Iaff8ccea3a319f9d9ad80501f1beccd74d1ef56d Signed-off-by: Olivier Dion Signed-off-by: Jérémie Galarneau --- src/bin/lttng-sessiond/kernel.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/bin/lttng-sessiond/kernel.cpp b/src/bin/lttng-sessiond/kernel.cpp index 5b4fc086b..6e2bdb4c6 100644 --- a/src/bin/lttng-sessiond/kernel.cpp +++ b/src/bin/lttng-sessiond/kernel.cpp @@ -63,6 +63,32 @@ 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; +namespace { +/* + * 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. * @@ -452,7 +478,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 +505,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"); -- 2.34.1