X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.c;h=8e972b0693cc28362fe36e9a80b040d128bed62c;hp=8a4652aecf4f548658f716d63aa0a71b0e1e3661;hb=c8a9de5a85fb150d3ceaa5ca1a8b1b2b91d050d5;hpb=71a3bb01e288ad6e611be0501a4444375c4124a7 diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index 8a4652aec..8e972b069 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,236 @@ 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( + const struct lttng_userspace_probe_location *probe_location, + struct ltt_kernel_session *session, uint64_t *offset) +{ + int fd; + int ret = 0; + const char *symbol = NULL; + const 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( + const 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; + const 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) +{ + const struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL; + enum lttng_userspace_probe_location_lookup_method_type type; + const 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. @@ -259,6 +491,13 @@ int kernel_create_event(struct lttng_event *ev, } } + if (ev->type == LTTNG_EVENT_USERSPACE_PROBE) { + ret = userspace_probe_add_callsites(ev, channel->session, event->fd); + if (ret) { + goto add_callsite_error; + } + } + err = kernctl_enable(event->fd); if (err < 0) { switch (-err) { @@ -281,6 +520,7 @@ int kernel_create_event(struct lttng_event *ev, return 0; +add_callsite_error: enable_error: filter_error: { @@ -993,17 +1233,18 @@ void kernel_destroy_channel(struct ltt_kernel_channel *kchan) /* * Take a snapshot for a given kernel session. * - * Return 0 on success or else return a LTTNG_ERR code. + * Return LTTNG_OK on success or else return a LTTNG_ERR code. */ -int kernel_snapshot_record(struct ltt_kernel_session *ksess, +enum lttng_error_code kernel_snapshot_record(struct ltt_kernel_session *ksess, struct snapshot_output *output, int wait, uint64_t nb_packets_per_stream) { int err, ret, saved_metadata_fd; + enum lttng_error_code status = LTTNG_OK; struct consumer_socket *socket; struct lttng_ht_iter iter; struct ltt_kernel_metadata *saved_metadata; - struct ltt_session *session; + struct ltt_session *session = NULL; uint64_t trace_archive_id; assert(ksess); @@ -1026,13 +1267,13 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, ret = kernel_open_metadata(ksess); if (ret < 0) { - ret = LTTNG_ERR_KERN_META_FAIL; + status = LTTNG_ERR_KERN_META_FAIL; goto error; } ret = kernel_open_metadata_stream(ksess); if (ret < 0) { - ret = LTTNG_ERR_KERN_META_FAIL; + status = LTTNG_ERR_KERN_META_FAIL; goto error_open_stream; } @@ -1056,19 +1297,18 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, /* Put back the saved consumer output into the session. */ ksess->consumer = saved_output; if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + status = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error_consumer; } /* For each channel, ask the consumer to snapshot it. */ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { - ret = consumer_snapshot_channel(socket, chan->key, output, 0, + status = consumer_snapshot_channel(socket, chan->key, output, 0, ksess->uid, ksess->gid, DEFAULT_KERNEL_TRACE_DIR, wait, nb_packets_per_stream, trace_archive_id); - if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + if (status != LTTNG_OK) { (void) kernel_consumer_destroy_metadata(socket, ksess->metadata); goto error_consumer; @@ -1076,12 +1316,11 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, } /* Snapshot metadata, */ - ret = consumer_snapshot_channel(socket, ksess->metadata->key, output, + status = consumer_snapshot_channel(socket, ksess->metadata->key, output, 1, ksess->uid, ksess->gid, DEFAULT_KERNEL_TRACE_DIR, wait, 0, trace_archive_id); - if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + if (status != LTTNG_OK) { goto error_consumer; } @@ -1092,8 +1331,6 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, (void) kernel_consumer_destroy_metadata(socket, ksess->metadata); } - ret = LTTNG_OK; - error_consumer: /* Close newly opened metadata stream. It's now on the consumer side. */ err = close(ksess->metadata_stream_fd); @@ -1107,9 +1344,11 @@ error: /* Restore metadata state.*/ ksess->metadata = saved_metadata; ksess->metadata_stream_fd = saved_metadata_fd; - + if (session) { + session_put(session); + } rcu_read_unlock(); - return ret; + return status; } /* @@ -1161,11 +1400,12 @@ error: /* * Rotate a kernel session. * - * Return 0 on success or else return a LTTNG_ERR code. + * Return LTTNG_OK on success or else an LTTng error code. */ -int kernel_rotate_session(struct ltt_session *session) +enum lttng_error_code kernel_rotate_session(struct ltt_session *session) { int ret; + enum lttng_error_code status = LTTNG_OK; struct consumer_socket *socket; struct lttng_ht_iter iter; struct ltt_kernel_session *ksess = session->kernel_session; @@ -1186,37 +1426,17 @@ int kernel_rotate_session(struct ltt_session *session) socket, node.node) { struct ltt_kernel_channel *chan; - /* - * Account the metadata channel first to make sure the - * number of channels waiting for a rotation cannot - * reach 0 before we complete the iteration over all - * the channels. - */ - ret = rotate_add_channel_pending(ksess->metadata->key, - LTTNG_DOMAIN_KERNEL, session); - if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; - goto error; - } - /* For each channel, ask the consumer to rotate it. */ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { - ret = rotate_add_channel_pending(chan->key, - LTTNG_DOMAIN_KERNEL, session); - if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; - goto error; - } - - DBG("Rotate channel %" PRIu64 ", session %s", chan->key, session->name); + DBG("Rotate kernel channel %" PRIu64 ", session %s", + chan->key, session->name); ret = consumer_rotate_channel(socket, chan->key, ksess->uid, ksess->gid, ksess->consumer, ksess->consumer->subdir, /* is_metadata_channel */ false, - session->current_archive_id, - &session->rotate_pending_relay); + session->current_archive_id); if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + status = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error; } } @@ -1228,17 +1448,14 @@ int kernel_rotate_session(struct ltt_session *session) ksess->uid, ksess->gid, ksess->consumer, ksess->consumer->subdir, /* is_metadata_channel */ true, - session->current_archive_id, - &session->rotate_pending_relay); + session->current_archive_id); if (ret < 0) { - ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + status = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error; } } - ret = LTTNG_OK; - error: rcu_read_unlock(); - return ret; + return status; }