Fix: adding a user space probe fails on thumb functions
authorOlivier Dion <odion@efficios.com>
Wed, 22 Feb 2023 20:19:14 +0000 (15:19 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 6 Jun 2023 18:47:12 +0000 (14:47 -0400)
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 <odion@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-sessiond/kernel.c

index 1839256ac0b9998ca272253ca5f72572d9a1e361..d8613deaca3bca892e389cbfa12b81fe480c0275 100644 (file)
@@ -48,6 +48,30 @@ static int kernel_tracer_fd = -1;
 
 #include <lttng/userspace-probe.h>
 #include <lttng/userspace-probe-internal.h>
+/*
+ * 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.
  *
@@ -400,7 +424,7 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                        goto end;
                }
 
-               callsite.u.uprobe.offset = offset;
+               callsite.u.uprobe.offset = sanitize_uprobe_offset(offset);
                ret = kernctl_add_callsite(fd, &callsite);
                if (ret) {
                        WARN("Adding callsite to userspace probe "
@@ -428,7 +452,7 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                        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("Adding callsite to userspace probe "
This page took 0.026073 seconds and 4 git commands to generate.