/*
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 only,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _LGPL_SOURCE
#include <string.h>
#include <unistd.h>
+#include <lttng/event.h>
+#include <lttng/lttng-error.h>
+#include <lttng/userspace-probe.h>
+#include <lttng/userspace-probe-internal.h>
+
#include <common/common.h>
#include <common/defaults.h>
+#include <common/trace-chunk.h>
+#include <common/macros.h>
#include "consumer.h"
#include "trace-kernel.h"
* Find the channel name for the given kernel session.
*/
struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
- char *name, struct ltt_kernel_session *session)
+ const char *name, struct ltt_kernel_session *session)
{
struct ltt_kernel_channel *chan;
lks->metadata = NULL;
CDS_INIT_LIST_HEAD(&lks->channel_list.head);
+ lks->tracker_pid = process_attr_tracker_create();
+ if (!lks->tracker_pid) {
+ goto error;
+ }
+ lks->tracker_vpid = process_attr_tracker_create();
+ if (!lks->tracker_vpid) {
+ goto error;
+ }
+ lks->tracker_uid = process_attr_tracker_create();
+ if (!lks->tracker_uid) {
+ goto error;
+ }
+ lks->tracker_vuid = process_attr_tracker_create();
+ if (!lks->tracker_vuid) {
+ goto error;
+ }
+ lks->tracker_gid = process_attr_tracker_create();
+ if (!lks->tracker_gid) {
+ goto error;
+ }
+ lks->tracker_vgid = process_attr_tracker_create();
+ if (!lks->tracker_vgid) {
+ goto error;
+ }
lks->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
if (lks->consumer == NULL) {
goto error;
return lks;
error:
+ process_attr_tracker_destroy(lks->tracker_pid);
+ process_attr_tracker_destroy(lks->tracker_vpid);
+ process_attr_tracker_destroy(lks->tracker_uid);
+ process_attr_tracker_destroy(lks->tracker_vuid);
+ process_attr_tracker_destroy(lks->tracker_gid);
+ process_attr_tracker_destroy(lks->tracker_vgid);
free(lks);
alloc_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;
+ }
- CDS_INIT_LIST_HEAD(&kctx->list);
+ memcpy(kctx_copy, kctx, sizeof(*kctx_copy));
+ memset(&kctx_copy->list, 0, sizeof(kctx_copy->list));
error:
- return kctx;
+ return kctx_copy;
}
/*
*
* Return pointer to structure or NULL.
*/
-struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev,
- char *filter_expression, struct lttng_filter_bytecode *filter)
+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;
}
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.
+ */
+ userspace_probe_location =
+ lttng_userspace_probe_location_copy(location);
+ 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.
+ */
+ userspace_probe_location =
+ lttng_userspace_probe_location_copy(location);
+ 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;
break;
case LTTNG_EVENT_SYSCALL:
attr->instrumentation = LTTNG_KERNEL_SYSCALL;
+ attr->u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_ALL;
+ attr->u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRYEXIT;
+ attr->u.syscall.match = LTTNG_KERNEL_SYSCALL_MATCH_NAME;
break;
case LTTNG_EVENT_ALL:
attr->instrumentation = LTTNG_KERNEL_ALL;
break;
default:
ERR("Unknown kernel instrumentation type (%d)", ev->type);
+ ret = LTTNG_ERR_INVALID;
goto error;
}
attr->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
/* Setting up a kernel event */
- lke->fd = -1;
- lke->event = attr;
- lke->enabled = 1;
- lke->filter_expression = filter_expression;
- lke->filter = filter;
+ 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;
+
+ *kernel_event = local_kernel_event;
- return lke;
+ return LTTNG_OK;
error:
free(filter_expression);
free(filter);
- free(lke);
+ free(local_kernel_event);
free(attr);
- return NULL;
+ return ret;
}
/*
*/
struct ltt_kernel_metadata *trace_kernel_create_metadata(void)
{
+ int ret;
struct ltt_kernel_metadata *lkm;
struct lttng_channel *chan;
goto error;
}
+ ret = lttng_strncpy(
+ chan->name, DEFAULT_METADATA_NAME, sizeof(chan->name));
+ if (ret) {
+ ERR("Failed to initialize metadata channel name to `%s`",
+ DEFAULT_METADATA_NAME);
+ goto error;
+ }
+
/* Set default attributes */
- chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE;
+ chan->attr.overwrite = DEFAULT_METADATA_OVERWRITE;
chan->attr.subbuf_size = default_get_metadata_subbuf_size();
chan->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM;
- 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;
+ chan->attr.switch_timer_interval = DEFAULT_METADATA_SWITCH_TIMER;
+ chan->attr.read_timer_interval = DEFAULT_METADATA_READ_TIMER;;
+
+
+ /*
+ * The metadata channel of kernel sessions must use the "mmap"
+ * back-end since the consumer daemon accumulates complete
+ * metadata units before sending them to the relay daemon in
+ * live mode. The consumer daemon also needs to extract the contents
+ * of the metadata cache when computing a rotation position.
+ *
+ * In both cases, it is not possible to rely on the splice
+ * back-end as the consumer daemon may need to accumulate more
+ * content than can be backed by the ring buffer's underlying
+ * pages.
+ */
+ chan->attr.output = LTTNG_EVENT_MMAP;
+ chan->attr.tracefile_size = 0;
+ chan->attr.tracefile_count = 0;
+ chan->attr.live_timer_interval = 0;
/* Init metadata */
lkm->fd = -1;
{
assert(ctx);
- cds_list_del(&ctx->list);
+ if (ctx->in_list) {
+ cds_list_del(&ctx->list);
+ }
free(ctx);
}
&& channel->published_to_notification_thread) {
status = notification_thread_command_remove_channel(
notification_thread_handle,
- channel->fd, LTTNG_DOMAIN_KERNEL);
+ channel->key, LTTNG_DOMAIN_KERNEL);
assert(status == LTTNG_OK);
}
free(channel->channel->attr.extended.ptr);
cds_list_for_each_entry_safe(channel, ctmp, &session->channel_list.head, list) {
trace_kernel_destroy_channel(channel);
}
+}
+/* Free elements needed by destroy notifiers. */
+void trace_kernel_free_session(struct ltt_kernel_session *session)
+{
/* Wipe consumer output object */
consumer_output_put(session->consumer);
+ process_attr_tracker_destroy(session->tracker_pid);
+ process_attr_tracker_destroy(session->tracker_vpid);
+ process_attr_tracker_destroy(session->tracker_uid);
+ process_attr_tracker_destroy(session->tracker_vuid);
+ process_attr_tracker_destroy(session->tracker_gid);
+ process_attr_tracker_destroy(session->tracker_vgid);
+
free(session);
}