From 410b78a0be5045a1e0d85bdf3b3e0f2288825f0d Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Fri, 29 Jun 2018 14:33:37 -0400 Subject: [PATCH] Implement userspace probe location extraction and registration MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit These functions use run_as commands to extract the offsets in the binary where the instrumentation should be placed and pass these offsets to the kernel tracer along with the FD to complete the registration of userspace probe events using the two-step registration process. Signed-off-by: Francis Deslauriers Signed-off-by: Jérémie Galarneau --- include/lttng/event.h | 1 + src/bin/lttng-sessiond/kernel.c | 233 ++++++++++++++++++++++++++++++++ src/bin/lttng/commands/list.c | 2 + 3 files changed, 236 insertions(+) diff --git a/include/lttng/event.h b/include/lttng/event.h index 548ec2a46..630d6c118 100644 --- a/include/lttng/event.h +++ b/include/lttng/event.h @@ -37,6 +37,7 @@ enum lttng_event_type { LTTNG_EVENT_FUNCTION_ENTRY = 3, LTTNG_EVENT_NOOP = 4, LTTNG_EVENT_SYSCALL = 5, + LTTNG_EVENT_USERSPACE_PROBE = 6, }; /* diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index 8a4652aec..e13925e27 100644 --- a/src/bin/lttng-sessiond/kernel.c +++ b/src/bin/lttng-sessiond/kernel.c @@ -41,6 +41,8 @@ */ static uint64_t next_kernel_channel_key; +#include +#include /* * Add context on a kernel channel. * @@ -191,6 +193,237 @@ error: return -1; } +/* + * Compute the offset of the instrumentation byte in the binary based on the + * function probe location using the ELF lookup method. + * + * Returns 0 on success and set the offset out parameter to the offset of the + * elf symbol + * Returns -1 on error + */ +static +int extract_userspace_probe_offset_function_elf( + struct lttng_userspace_probe_location *probe_location, + struct ltt_kernel_session *session, uint64_t *offset) +{ + int fd; + int ret = 0; + const char *symbol = NULL; + struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + enum lttng_userspace_probe_location_lookup_method_type lookup_method_type; + + + assert(lttng_userspace_probe_location_get_type(probe_location) == + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION); + + lookup = lttng_userspace_probe_location_get_lookup_method( + probe_location); + if (!lookup) { + ret = -1; + goto end; + } + + lookup_method_type = + lttng_userspace_probe_location_lookup_method_get_type(lookup); + + assert(lookup_method_type == + LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF); + + symbol = lttng_userspace_probe_location_function_get_function_name( + probe_location); + if (!symbol) { + ret = -1; + goto end; + } + + fd = lttng_userspace_probe_location_function_get_binary_fd(probe_location); + if (fd < 0) { + ret = -1; + goto end; + } + + ret = run_as_extract_elf_symbol_offset(fd, symbol, session->uid, + session->gid, offset); + if (ret < 0) { + DBG("userspace probe offset calculation failed for " + "function %s", symbol); + goto end; + } + + DBG("userspace probe elf offset for %s is 0x%jd", symbol, (intmax_t)(*offset)); +end: + return ret; +} + +/* + * Compute the offsets of the instrumentation bytes in the binary based on the + * tracepoint probe location using the SDT lookup method. This function + * allocates the offsets buffer, the caller must free it. + * + * Returns 0 on success and set the offset out parameter to the offsets of the + * SDT tracepoint. + * Returns -1 on error. + */ +static +int extract_userspace_probe_offset_tracepoint_sdt( + struct lttng_userspace_probe_location *probe_location, + struct ltt_kernel_session *session, uint64_t **offsets, + uint32_t *offsets_count) +{ + enum lttng_userspace_probe_location_lookup_method_type lookup_method_type; + struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + const char *probe_name = NULL, *provider_name = NULL; + int ret = 0; + int fd, i; + + assert(lttng_userspace_probe_location_get_type(probe_location) == + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT); + + lookup = lttng_userspace_probe_location_get_lookup_method(probe_location); + if (!lookup) { + ret = -1; + goto end; + } + + lookup_method_type = + lttng_userspace_probe_location_lookup_method_get_type(lookup); + + assert(lookup_method_type == + LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT); + + + probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name( + probe_location); + if (!probe_name) { + ret = -1; + goto end; + } + + provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name( + probe_location); + if (!provider_name) { + ret = -1; + goto end; + } + + fd = lttng_userspace_probe_location_tracepoint_get_binary_fd(probe_location); + if (fd < 0) { + ret = -1; + goto end; + } + + ret = run_as_extract_sdt_probe_offsets(fd, provider_name, probe_name, + session->uid, session->gid, offsets, offsets_count); + if (ret < 0) { + DBG("userspace probe offset calculation failed for sdt " + "probe %s:%s", provider_name, probe_name); + goto end; + } + + if (*offsets_count == 0) { + DBG("no userspace probe offset found"); + goto end; + } + + DBG("%u userspace probe SDT offsets found for %s:%s at:", + *offsets_count, provider_name, probe_name); + for (i = 0; i < *offsets_count; i++) { + DBG("\t0x%jd", (intmax_t)((*offsets)[i])); + } +end: + return ret; +} + +/* + * Extract the offsets of the instrumentation point for the different lookup + * methods. + */ +static +int userspace_probe_add_callsites(struct lttng_event *ev, + struct ltt_kernel_session *session, int fd) +{ + struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL; + enum lttng_userspace_probe_location_lookup_method_type type; + struct lttng_userspace_probe_location *location = NULL; + int ret; + + assert(ev); + assert(ev->type == LTTNG_EVENT_USERSPACE_PROBE); + + location = lttng_event_get_userspace_probe_location(ev); + if (!location) { + ret = -1; + goto end; + } + lookup_method = + lttng_userspace_probe_location_get_lookup_method(location); + if (!lookup_method) { + ret = -1; + goto end; + } + + type = lttng_userspace_probe_location_lookup_method_get_type(lookup_method); + switch (type) { + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: + { + struct lttng_kernel_event_callsite callsite; + uint64_t offset; + + ret = extract_userspace_probe_offset_function_elf(location, session, &offset); + if (ret) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto end; + } + + callsite.u.uprobe.offset = offset; + ret = kernctl_add_callsite(fd, &callsite); + if (ret) { + WARN("Adding callsite to userspace probe " + "event %s failed.", ev->name); + ret = LTTNG_ERR_KERN_ENABLE_FAIL; + goto end; + } + break; + } + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + { + int i; + uint64_t *offsets = NULL; + uint32_t offsets_count; + struct lttng_kernel_event_callsite callsite; + + /* + * This call allocates the offsets buffer. This buffer must be freed + * by the caller + */ + ret = extract_userspace_probe_offset_tracepoint_sdt(location, session, + &offsets, &offsets_count); + if (ret) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto end; + } + for (i = 0; i < offsets_count; i++) { + callsite.u.uprobe.offset = offsets[i]; + ret = kernctl_add_callsite(fd, &callsite); + if (ret) { + WARN("Adding callsite to userspace probe " + "event %s failed.", ev->name); + ret = LTTNG_ERR_KERN_ENABLE_FAIL; + free(offsets); + goto end; + } + } + free(offsets); + break; + } + default: + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto end; + } +end: + return ret; +} + /* * Create a kernel event, enable it to the kernel tracer and add it to the * channel event list of the kernel session. diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c index 5816a05de..4a94690b0 100644 --- a/src/bin/lttng/commands/list.c +++ b/src/bin/lttng/commands/list.c @@ -343,6 +343,8 @@ static void print_events(struct lttng_event *event) safe_string(filter_msg)); break; case LTTNG_EVENT_ALL: + /* Fall-through. */ + default: /* We should never have "all" events in list. */ assert(0); break; -- 2.34.1