Skip to content

Commit

Permalink
Add support for UST dynamic instrumentation
Browse files Browse the repository at this point in the history
Most parts of code are to deal with passing a varlen payload between
the sessiond, tracer application and lttng command, inspired by how
the filter feature are implemented.
  • Loading branch information
5kg committed Sep 4, 2013
1 parent d86b2ae commit fc2ca02
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 11 deletions.
2 changes: 2 additions & 0 deletions include/lttng/lttng-error.h
Expand Up @@ -140,6 +140,8 @@ enum lttng_error_code {
LTTNG_ERR_FILTER_NOMEM = 107, /* Lack of memory for filter bytecode */
LTTNG_ERR_FILTER_EXIST = 108, /* Filter already exist */
LTTNG_ERR_NO_CONSUMER = 109, /* No consumer exist for the session */
LTTNG_ERR_TARGET_INVAL = 110, /* Invalid instrument target */
LTTNG_ERR_TARGET_NOMEM = 111, /* Lack of memory for instrument target */

/* MUST be last element */
LTTNG_ERR_NR, /* Last element */
Expand Down
19 changes: 18 additions & 1 deletion include/lttng/lttng.h
Expand Up @@ -230,12 +230,28 @@ struct lttng_event_function_attr {
char padding[LTTNG_EVENT_FUNCTION_PADDING1];
};

/*
* Instrument target
*
* The structures should be initialized to zero before use.
*/
#define LTTNG_EVENT_TARGET_PADDING 32
struct lttng_event_target_attr {
int path_len;

char padding[LTTNG_EVENT_TARGET_PADDING];

/* This varlen field should always be the last element */
char path[0];
};

/*
* Generic lttng event
*
* The structures should be initialized to zero before use.
*/
#define LTTNG_EVENT_PADDING1 15
#define LTTNG_EVENT_PADDING1 \
(15 - sizeof(struct lttng_event_target_attr *))
#define LTTNG_EVENT_PADDING2 LTTNG_SYMBOL_NAME_LEN + 32
struct lttng_event {
enum lttng_event_type type;
Expand All @@ -247,6 +263,7 @@ struct lttng_event {
int32_t enabled; /* Does not apply: -1 */
pid_t pid;
unsigned char filter; /* filter enabled ? */
struct lttng_event_target_attr *target;

char padding[LTTNG_EVENT_PADDING1];

Expand Down
1 change: 1 addition & 0 deletions src/bin/lttng-sessiond/Makefile.am
Expand Up @@ -11,6 +11,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \
kernel.c kernel.h \
ust-ctl.h ust-app.h trace-ust.h ust-thread.h \
ust-registry.h \
ust-instrument.h \
context.c context.h \
channel.c channel.h \
event.c event.h \
Expand Down
6 changes: 6 additions & 0 deletions src/bin/lttng-sessiond/cmd.c
Expand Up @@ -235,9 +235,15 @@ static int list_lttng_ust_global_events(char *channel_name,
break;
case LTTNG_UST_PROBE:
tmp[i].type = LTTNG_EVENT_PROBE;
memcpy(&tmp[i].attr.probe, &uevent->attr.u.probe,
sizeof(struct lttng_ust_probe));
/* TODO: List instrument target information */
break;
case LTTNG_UST_FUNCTION:
tmp[i].type = LTTNG_EVENT_FUNCTION;
memcpy(&tmp[i].attr.probe, &uevent->attr.u.probe,
sizeof(struct lttng_ust_probe));
/* TODO: List instrument target information */
break;
}

Expand Down
30 changes: 29 additions & 1 deletion src/bin/lttng-sessiond/lttng-ust-abi.h
Expand Up @@ -100,18 +100,45 @@ struct lttng_ust_stream {
*/
} LTTNG_PACKED;

#define LTTNG_UST_EVENT_PADDING1 16
/*
* Either addr is used, or symbol_name and offset.
*/
#define LTTNG_UST_PROBE_PADDING 16
struct lttng_ust_probe {
uint64_t addr;

uint64_t offset;
char symbol_name[LTTNG_UST_SYM_NAME_LEN];

char padding[LTTNG_UST_PROBE_PADDING];
} LTTNG_PACKED;

/*
* Instrument target
*/
#define LTTNG_UST_TARGET_PADDING 32
struct lttng_ust_target {
uint32_t path_len;

char padding[LTTNG_UST_TARGET_PADDING];

char path[0];
} LTTNG_PACKED;

#define LTTNG_UST_EVENT_PADDING1 (16 - sizeof(struct lttng_ust_target *))
#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_event {
enum lttng_ust_instrumentation instrumentation;
char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */

enum lttng_ust_loglevel_type loglevel_type;
int loglevel; /* value, -1: all */
struct lttng_ust_target *target;
char padding[LTTNG_UST_EVENT_PADDING1];

/* Per instrumentation type configuration */
union {
struct lttng_ust_probe probe;
char padding[LTTNG_UST_EVENT_PADDING2];
} u;
} LTTNG_PACKED;
Expand Down Expand Up @@ -275,6 +302,7 @@ struct lttng_ust_filter_bytecode {

/* Event FD commands */
#define LTTNG_UST_FILTER _UST_CMD(0xA0)
#define LTTNG_UST_TARGET _UST_CMD(0xA1)

#define LTTNG_UST_ROOT_HANDLE 0

Expand Down
38 changes: 38 additions & 0 deletions src/bin/lttng-sessiond/main.c
Expand Up @@ -2876,6 +2876,44 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
}
case LTTNG_ENABLE_EVENT:
{
/* TODO: Handle dynamic instrumentation with filter */
struct lttng_event_target_attr *target;

if (cmd_ctx->lsm->u.enable.event.target) {
if (cmd_ctx->lsm->u.enable.target_len
< sizeof(struct lttng_event_target_attr)) {
ret = LTTNG_ERR_TARGET_INVAL;
goto error;
}

target = zmalloc(cmd_ctx->lsm->u.enable.target_len);
if (!target) {
ret = LTTNG_ERR_TARGET_NOMEM;
goto error;
}

/* Receive var. len. data */
DBG("Receiving var len data target from client ...");
ret = lttcomm_recv_unix_sock(sock, target,
cmd_ctx->lsm->u.enable.target_len);
if (ret <= 0) {
DBG("Nothing recv() from client var len data... continuing");
*sock_error = 1;
free(target);
ret = LTTNG_ERR_TARGET_INVAL;
goto error;
}

if ((sizeof(struct lttng_event_target_attr) + target->path_len)
!= cmd_ctx->lsm->u.enable.target_len) {
free(target);
ret = LTTNG_ERR_TARGET_INVAL;
goto error;
}

cmd_ctx->lsm->u.enable.event.target = target;
}

ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
cmd_ctx->lsm->u.enable.channel_name,
&cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]);
Expand Down
19 changes: 16 additions & 3 deletions src/bin/lttng-sessiond/trace-ust.c
Expand Up @@ -324,12 +324,23 @@ struct ltt_ust_event *trace_ust_create_event(struct lttng_event *ev,
switch (ev->type) {
case LTTNG_EVENT_PROBE:
lue->attr.instrumentation = LTTNG_UST_PROBE;
lue->attr.u.probe.addr = ev->attr.probe.addr;
lue->attr.u.probe.offset = ev->attr.probe.offset;
strncpy(lue->attr.u.probe.symbol_name,
ev->attr.probe.symbol_name, LTTNG_UST_SYM_NAME_LEN);
lue->attr.u.probe.symbol_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
/* Same layout. */
lue->attr.target = (struct lttng_ust_target *) ev->target;
break;
case LTTNG_EVENT_FUNCTION:
lue->attr.instrumentation = LTTNG_UST_FUNCTION;
break;
case LTTNG_EVENT_FUNCTION_ENTRY:
lue->attr.instrumentation = LTTNG_UST_FUNCTION;
lue->attr.u.probe.addr = ev->attr.probe.addr;
lue->attr.u.probe.offset = ev->attr.probe.offset;
strncpy(lue->attr.u.probe.symbol_name,
ev->attr.probe.symbol_name, LTTNG_UST_SYM_NAME_LEN);
lue->attr.u.probe.symbol_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
/* Same layout. */
lue->attr.target = (struct lttng_ust_target *) ev->target;
break;
case LTTNG_EVENT_TRACEPOINT:
lue->attr.instrumentation = LTTNG_UST_TRACEPOINT;
Expand Down Expand Up @@ -514,6 +525,8 @@ void trace_ust_destroy_event(struct ltt_ust_event *event)
assert(event);

DBG2("Trace destroy UST event %s", event->attr.name);

free(event->attr.target);
free(event->filter);
free(event);
}
Expand Down
126 changes: 126 additions & 0 deletions src/bin/lttng-sessiond/ust-app.c
Expand Up @@ -38,6 +38,7 @@
#include "ust-app.h"
#include "ust-consumer.h"
#include "ust-ctl.h"
#include "ust-instrument.h"
#include "utils.h"

/* Next available channel key. Access under next_channel_key_lock. */
Expand Down Expand Up @@ -270,6 +271,7 @@ void delete_ust_app_event(int sock, struct ust_app_event *ua_event)

assert(ua_event);

free(ua_event->attr.target);
free(ua_event->filter);

if (ua_event->obj != NULL) {
Expand Down Expand Up @@ -926,6 +928,28 @@ struct ust_app_ctx *alloc_ust_app_ctx(struct lttng_ust_context *uctx)
return ua_ctx;
}

/*
* Allocate a instrument target and copy the given original one.
*
* Return allocated instrument target or NULL on error.
*/
static struct lttng_ust_target *alloc_copy_ust_app_target(
struct lttng_ust_target *orig_t)
{
struct lttng_ust_target *target = NULL;

target = zmalloc(sizeof(*target) + orig_t->path_len);
if (!target) {
PERROR("zmalloc alloc ust app instrument target");
goto error;
}

memcpy(target, orig_t, sizeof(*target) + orig_t->path_len);

error:
return target;
}

/*
* Allocate a filter and copy the given original filter.
*
Expand Down Expand Up @@ -1066,6 +1090,41 @@ int create_ust_channel_context(struct ust_app_channel *ua_chan,
return ret;
}

/*
* Set the target on the tracer.
*/
static
int set_ust_event_target(struct ust_app_event *ua_event,
struct ust_app *app)
{
int ret;

health_code_update();

if (!ua_event->attr.target) {
ret = 0;
goto error;
}

ret = ustctl_set_target(app->sock, ua_event->attr.target,
ua_event->obj);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
ERR("UST app event %s set instrument target failed for app (pid: %d) "
"with ret %d", ua_event->attr.name, app->pid, ret);
} else {
DBG3("UST app set instrument target failed. Application is dead.");
}
goto error;
}

DBG2("UST instrument target set successfully for event %s", ua_event->name);

error:
health_code_update();
return ret;
}

/*
* Set the filter on the tracer.
*/
Expand Down Expand Up @@ -1302,6 +1361,14 @@ int create_ust_event(struct ust_app *app, struct ust_app_session *ua_sess,

health_code_update();

/* Set instrument target if one is present. */
if (ua_event->attr.target) {
ret = set_ust_event_target(ua_event, app);
if (ret < 0) {
goto error;
}
}

/* Set filter if one is present. */
if (ua_event->filter) {
ret = set_ust_event_filter(ua_event, app);
Expand Down Expand Up @@ -1353,6 +1420,13 @@ static void shadow_copy_event(struct ust_app_event *ua_event,
/* Copy event attributes */
memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr));

/* Copy instrument target */
if (uevent->attr.target) {
ua_event->attr.target =
alloc_copy_ust_app_target(uevent->attr.target);
/* Target might be NULL here in case of ENONEM. */
}

/* Copy filter bytecode */
if (uevent->filter) {
ua_event->filter = alloc_copy_ust_app_filter(uevent->filter);
Expand Down Expand Up @@ -4775,6 +4849,58 @@ int ust_app_recv_notify(int sock)

break;
}
case USTCTL_NOTIFY_CMD_INSTRUMENT:
{
enum lttng_ust_instrumentation instrumentation;
char name[LTTNG_UST_SYM_NAME_LEN], symbol[LTTNG_UST_SYM_NAME_LEN];
char object_path[PATH_MAX];
uint64_t addr, offset;
struct ust_app *app;

DBG2("UST app ustctl instrument probe received");

ret = ustctl_recv_instrument_probe(sock, object_path, name,
&instrumentation, &addr, symbol, &offset);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
ERR("UST app recv instrument failed with ret %d", ret);
} else {
DBG3("UST app recv instrument failed. Application died");
}
goto error;
}

rcu_read_lock();

app = find_app_by_notify_sock(sock);
if (app == NULL) {
DBG3("UST app instrument failed to find app sock %d", sock);
goto error;
}

if (!app->compatible) {
goto error;
}

rcu_read_unlock();

ret = ust_instrument_probe(app, object_path, name, instrumentation,
addr, symbol, offset);

DBG3("UST app replying to instrument probe with pid %u, ret: %d",
app->pid, ret);

ret = ustctl_reply_instrument_probe(sock, ret);
if (ret < 0) {
if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
ERR("UST app reply instrument failed with ret %d", ret);
} else {
DBG3("UST app reply instrument failed. Application died");
}
goto error;
}
break;
}
default:
/* Should NEVER happen. */
assert(0);
Expand Down

0 comments on commit fc2ca02

Please sign in to comment.