X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Ftrace-kernel.c;h=b9d03a72e002ca0042764a877f0ae556e87f1faa;hp=7748b891faef7b35add6d9c6e8e2da2e52f24f96;hb=87597c2c3bbaa1502ad2025cbf16704829f3b464;hpb=a4b92340642035d1eafeb1eead0ad01f64d2007d diff --git a/src/bin/lttng-sessiond/trace-kernel.c b/src/bin/lttng-sessiond/trace-kernel.c index 7748b891f..b9d03a72e 100644 --- a/src/bin/lttng-sessiond/trace-kernel.c +++ b/src/bin/lttng-sessiond/trace-kernel.c @@ -15,17 +15,24 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include #include +#include +#include +#include +#include + #include #include #include "consumer.h" #include "trace-kernel.h" +#include "lttng-sessiond.h" +#include "notification-thread-commands.h" /* * Find the channel name for the given kernel session. @@ -35,10 +42,15 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name( { struct ltt_kernel_channel *chan; - if (session == NULL) { - ERR("Undefine session"); - goto error; - } + assert(session); + assert(name); + + /* + * If we receive an empty string for channel name, it means the + * default channel name is requested. + */ + if (name[0] == '\0') + name = DEFAULT_CHANNEL_NAME; DBG("Trying to find channel %s", name); @@ -49,33 +61,82 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name( } } -error: return NULL; } +/* + * Find the event for the given channel. + */ +struct ltt_kernel_event *trace_kernel_find_event( + char *name, struct ltt_kernel_channel *channel, + enum lttng_event_type type, + struct lttng_filter_bytecode *filter) +{ + struct ltt_kernel_event *ev; + int found = 0; + + assert(name); + assert(channel); + + cds_list_for_each_entry(ev, &channel->events_list.head, list) { + if (type != LTTNG_EVENT_ALL && ev->type != type) { + continue; + } + if (strcmp(name, ev->event->name)) { + continue; + } + if ((ev->filter && !filter) || (!ev->filter && filter)) { + continue; + } + if (ev->filter && filter) { + if (ev->filter->len != filter->len || + memcmp(ev->filter->data, filter->data, + filter->len) != 0) { + continue; + } + } + found = 1; + break; + } + if (found) { + DBG("Found event %s for channel %s", name, + channel->channel->name); + return ev; + } else { + return NULL; + } +} + /* * Find the event name for the given channel. */ struct ltt_kernel_event *trace_kernel_get_event_by_name( - char *name, struct ltt_kernel_channel *channel) + char *name, struct ltt_kernel_channel *channel, + enum lttng_event_type type) { struct ltt_kernel_event *ev; + int found = 0; - if (channel == NULL) { - ERR("Undefine channel"); - goto error; - } + assert(name); + assert(channel); cds_list_for_each_entry(ev, &channel->events_list.head, list) { - if (strcmp(name, ev->event->name) == 0) { - DBG("Found event by name %s for channel %s", name, - channel->channel->name); - return ev; + if (type != LTTNG_EVENT_ALL && ev->type != type) { + continue; + } + if (strcmp(name, ev->event->name)) { + continue; } + found = 1; + break; + } + if (found) { + DBG("Found event %s for channel %s", name, + channel->channel->name); + return ev; + } else { + return NULL; } - -error: - return NULL; } /* @@ -83,9 +144,8 @@ error: * * Return pointer to structure or NULL. */ -struct ltt_kernel_session *trace_kernel_create_session(char *path) +struct ltt_kernel_session *trace_kernel_create_session(void) { - int ret; struct ltt_kernel_session *lks = NULL; /* Allocate a new ltt kernel session */ @@ -108,31 +168,6 @@ struct ltt_kernel_session *trace_kernel_create_session(char *path) goto error; } - /* - * The tmp_consumer stays NULL until a set_consumer_uri command is - * executed. At this point, the consumer should be nullify until an - * enable_consumer command. This assignment is symbolic since we've zmalloc - * the struct. - */ - lks->tmp_consumer = NULL; - - if (path && strlen(path) > 0) { - /* Use the default consumer output which is the tracing session path. */ - ret = snprintf(lks->consumer->dst.trace_path, PATH_MAX, - "%s" DEFAULT_KERNEL_TRACE_DIR, path); - if (ret < 0) { - PERROR("snprintf consumer trace path"); - goto error; - } - - /* Set session path */ - ret = asprintf(&lks->trace_path, "%s" DEFAULT_KERNEL_TRACE_DIR, path); - if (ret < 0) { - PERROR("asprintf kernel traces path"); - goto error; - } - } - return lks; error: @@ -148,9 +183,12 @@ alloc_error: * Return pointer to structure or NULL. */ struct ltt_kernel_channel *trace_kernel_create_channel( - struct lttng_channel *chan, char *path) + struct lttng_channel *chan) { struct ltt_kernel_channel *lkc; + struct lttng_channel_extended *extended = NULL; + + assert(chan); lkc = zmalloc(sizeof(struct ltt_kernel_channel)); if (lkc == NULL) { @@ -163,37 +201,119 @@ struct ltt_kernel_channel *trace_kernel_create_channel( PERROR("lttng_channel zmalloc"); goto error; } + + extended = zmalloc(sizeof(struct lttng_channel_extended)); + if (!extended) { + PERROR("lttng_channel_channel zmalloc"); + goto error; + } memcpy(lkc->channel, chan, sizeof(struct lttng_channel)); + memcpy(extended, chan->attr.extended.ptr, sizeof(struct lttng_channel_extended)); + lkc->channel->attr.extended.ptr = extended; + extended = NULL; + + /* + * If we receive an empty string for channel name, it means the + * default channel name is requested. + */ + if (chan->name[0] == '\0') { + strncpy(lkc->channel->name, DEFAULT_CHANNEL_NAME, + sizeof(lkc->channel->name)); + } + lkc->channel->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; lkc->fd = -1; lkc->stream_count = 0; lkc->event_count = 0; lkc->enabled = 1; - lkc->ctx = NULL; + lkc->published_to_notification_thread = false; /* Init linked list */ CDS_INIT_LIST_HEAD(&lkc->events_list.head); CDS_INIT_LIST_HEAD(&lkc->stream_list.head); + CDS_INIT_LIST_HEAD(&lkc->ctx_list); return lkc; error: + if (lkc) { + free(lkc->channel); + } + free(extended); + free(lkc); return NULL; } +/* + * Allocate and init a kernel context object. + * + * Return the allocated object or NULL on error. + */ +struct ltt_kernel_context *trace_kernel_create_context( + struct lttng_kernel_context *ctx) +{ + struct ltt_kernel_context *kctx; + + kctx = zmalloc(sizeof(*kctx)); + if (!kctx) { + PERROR("zmalloc kernel context"); + goto error; + } + + if (ctx) { + memcpy(&kctx->ctx, ctx, sizeof(kctx->ctx)); + } +error: + return kctx; +} + +/* + * Allocate and init a kernel context object from an existing kernel context + * object. + * + * Return the allocated object or NULL on error. + */ +struct ltt_kernel_context *trace_kernel_copy_context( + struct ltt_kernel_context *kctx) +{ + struct ltt_kernel_context *kctx_copy; + + assert(kctx); + kctx_copy = zmalloc(sizeof(*kctx_copy)); + if (!kctx_copy) { + PERROR("zmalloc ltt_kernel_context"); + goto error; + } + + memcpy(kctx_copy, kctx, sizeof(*kctx_copy)); + memset(&kctx_copy->list, 0, sizeof(kctx_copy->list)); + +error: + return kctx_copy; +} + /* * Allocate and initialize a kernel event. Set name and event type. + * We own filter_expression, and filter. * * Return pointer to structure or NULL. */ -struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) +enum lttng_error_code trace_kernel_create_event( + struct lttng_event *ev, char *filter_expression, + struct lttng_filter_bytecode *filter, + struct ltt_kernel_event **kernel_event) { - struct ltt_kernel_event *lke; + enum lttng_error_code ret; struct lttng_kernel_event *attr; + struct ltt_kernel_event *local_kernel_event; + struct lttng_userspace_probe_location *userspace_probe_location = NULL; + + assert(ev); - lke = zmalloc(sizeof(struct ltt_kernel_event)); + local_kernel_event = zmalloc(sizeof(struct ltt_kernel_event)); attr = zmalloc(sizeof(struct lttng_kernel_event)); - if (lke == NULL || attr == NULL) { + if (local_kernel_event == NULL || attr == NULL) { PERROR("kernel event zmalloc"); + ret = LTTNG_ERR_NOMEM; goto error; } @@ -206,11 +326,88 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) ev->attr.probe.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); attr->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; + case LTTNG_EVENT_USERSPACE_PROBE: + { + const struct lttng_userspace_probe_location* location = NULL; + const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + + location = lttng_event_get_userspace_probe_location(ev); + if (!location) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From this point on, the specific term 'uprobe' is used + * instead of the generic 'userspace probe' because it's the + * technology used at the moment for this instrumentation. + * LTTng currently implements userspace probes using uprobes. + * In the interactions with the kernel tracer, we use the + * uprobe term. + */ + attr->instrumentation = LTTNG_KERNEL_UPROBE; + + /* + * Only the elf lookup method is supported at the moment. + */ + lookup = lttng_userspace_probe_location_get_lookup_method( + location); + if (!lookup) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From the kernel tracer's perspective, all userspace probe + * event types are all the same: a file and an offset. + */ + switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: + /* Get the file descriptor on the target binary. */ + attr->u.uprobe.fd = + lttng_userspace_probe_location_function_get_binary_fd(location); + + /* + * Save a reference to the probe location used during + * the listing of events. Close its FD since it won't + * be needed for listing. + */ + userspace_probe_location = + lttng_userspace_probe_location_copy(location); + ret = lttng_userspace_probe_location_function_set_binary_fd( + userspace_probe_location, -1); + if (ret) { + goto error; + } + break; + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + /* Get the file descriptor on the target binary. */ + attr->u.uprobe.fd = + lttng_userspace_probe_location_tracepoint_get_binary_fd(location); + + /* + * Save a reference to the probe location used during the listing of + * events. Close its FD since it won't be needed for listing. + */ + userspace_probe_location = + lttng_userspace_probe_location_copy(location); + ret = lttng_userspace_probe_location_tracepoint_set_binary_fd( + userspace_probe_location, -1); + if (ret) { + goto error; + } + break; + default: + DBG("Unsupported lookup method type"); + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + break; + } case LTTNG_EVENT_FUNCTION: attr->instrumentation = LTTNG_KERNEL_KRETPROBE; attr->u.kretprobe.addr = ev->attr.probe.addr; attr->u.kretprobe.offset = ev->attr.probe.offset; - attr->u.kretprobe.offset = ev->attr.probe.offset; strncpy(attr->u.kretprobe.symbol_name, ev->attr.probe.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); attr->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; @@ -232,6 +429,7 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) break; default: ERR("Unknown kernel instrumentation type (%d)", ev->type); + ret = LTTNG_ERR_INVALID; goto error; } @@ -240,17 +438,23 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) attr->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; /* Setting up a kernel event */ - lke->fd = -1; - lke->event = attr; - lke->enabled = 1; - lke->ctx = NULL; + local_kernel_event->fd = -1; + local_kernel_event->event = attr; + local_kernel_event->enabled = 1; + local_kernel_event->filter_expression = filter_expression; + local_kernel_event->filter = filter; + local_kernel_event->userspace_probe_location = userspace_probe_location; - return lke; + *kernel_event = local_kernel_event; + + return LTTNG_OK; error: - free(lke); + free(filter_expression); + free(filter); + free(local_kernel_event); free(attr); - return NULL; + return ret; } /* @@ -272,10 +476,10 @@ struct ltt_kernel_metadata *trace_kernel_create_metadata(void) /* Set default attributes */ chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; - chan->attr.subbuf_size = DEFAULT_METADATA_SUBBUF_SIZE; + chan->attr.subbuf_size = default_get_metadata_subbuf_size(); chan->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; - chan->attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; - chan->attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; + chan->attr.switch_timer_interval = DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER; + chan->attr.read_timer_interval = DEFAULT_KERNEL_CHANNEL_READ_TIMER; chan->attr.output = DEFAULT_KERNEL_CHANNEL_OUTPUT; /* Init metadata */ @@ -302,6 +506,8 @@ struct ltt_kernel_stream *trace_kernel_create_stream(const char *name, int ret; struct ltt_kernel_stream *lks; + assert(name); + lks = zmalloc(sizeof(struct ltt_kernel_stream)); if (lks == NULL) { PERROR("kernel stream zmalloc"); @@ -309,7 +515,7 @@ struct ltt_kernel_stream *trace_kernel_create_stream(const char *name, } /* Set name */ - ret = snprintf(lks->name, sizeof(lks->name), "%s_%d", name, count); + ret = snprintf(lks->name, sizeof(lks->name), "%s_%u", name, count); if (ret < 0) { PERROR("snprintf stream name"); goto error; @@ -319,6 +525,7 @@ struct ltt_kernel_stream *trace_kernel_create_stream(const char *name, /* Init stream */ lks->fd = -1; lks->state = 0; + lks->cpu = count; return lks; @@ -331,11 +538,13 @@ error: */ void trace_kernel_destroy_stream(struct ltt_kernel_stream *stream) { - int ret; + assert(stream); DBG("[trace] Closing stream fd %d", stream->fd); /* Close kernel fd */ if (stream->fd >= 0) { + int ret; + ret = close(stream->fd); if (ret) { PERROR("close"); @@ -352,9 +561,11 @@ void trace_kernel_destroy_stream(struct ltt_kernel_stream *stream) */ void trace_kernel_destroy_event(struct ltt_kernel_event *event) { - int ret; + assert(event); if (event->fd >= 0) { + int ret; + DBG("[trace] Closing event fd %d", event->fd); /* Close kernel fd */ ret = close(event->fd); @@ -368,11 +579,26 @@ void trace_kernel_destroy_event(struct ltt_kernel_event *event) /* Remove from event list */ cds_list_del(&event->list); + free(event->filter_expression); + free(event->filter); + free(event->event); - free(event->ctx); free(event); } +/* + * Cleanup kernel context structure. + */ +void trace_kernel_destroy_context(struct ltt_kernel_context *ctx) +{ + assert(ctx); + + if (ctx->in_list) { + cds_list_del(&ctx->list); + } + free(ctx); +} + /* * Cleanup kernel channel structure. */ @@ -380,7 +606,11 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) { struct ltt_kernel_stream *stream, *stmp; struct ltt_kernel_event *event, *etmp; + struct ltt_kernel_context *ctx, *ctmp; int ret; + enum lttng_error_code status; + + assert(channel); DBG("[trace] Closing channel fd %d", channel->fd); /* Close kernel fd */ @@ -401,11 +631,23 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) trace_kernel_destroy_event(event); } + /* For each context in the channel list */ + cds_list_for_each_entry_safe(ctx, ctmp, &channel->ctx_list, list) { + trace_kernel_destroy_context(ctx); + } + /* Remove from channel list */ cds_list_del(&channel->list); + if (notification_thread_handle + && channel->published_to_notification_thread) { + status = notification_thread_command_remove_channel( + notification_thread_handle, + channel->key, LTTNG_DOMAIN_KERNEL); + assert(status == LTTNG_OK); + } + free(channel->channel->attr.extended.ptr); free(channel->channel); - free(channel->ctx); free(channel); } @@ -414,11 +656,13 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) */ void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata) { - int ret; + assert(metadata); DBG("[trace] Closing metadata fd %d", metadata->fd); /* Close kernel fd */ if (metadata->fd >= 0) { + int ret; + ret = close(metadata->fd); if (ret) { PERROR("close"); @@ -431,12 +675,16 @@ void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata) /* * Cleanup kernel session structure + * + * Should *NOT* be called with RCU read-side lock held. */ void trace_kernel_destroy_session(struct ltt_kernel_session *session) { struct ltt_kernel_channel *channel, *ctmp; int ret; + assert(session); + DBG("[trace] Closing session fd %d", session->fd); /* Close kernel fds */ if (session->fd >= 0) { @@ -463,9 +711,7 @@ void trace_kernel_destroy_session(struct ltt_kernel_session *session) } /* Wipe consumer output object */ - consumer_destroy_output(session->consumer); - consumer_destroy_output(session->tmp_consumer); + consumer_output_put(session->consumer); - free(session->trace_path); free(session); }