From ce7352a2d029c4cad9fed5e8288568225366152e Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 9 Mar 2016 20:05:53 -0500 Subject: [PATCH] Fix: handle backward probe compatibility for application contexts Fix segmentation fault of applications built against lttng-ust 2.7, linked against lttng-ust 2.8-pre when tracing is active. We need to consider backward ABI compability here, which can be done by using a dummy context in place of an application context when recording an event. Basically, application contexts won't be saved into events generated by a lttng-ust 2.7 probe provider: those will appear as empty contexts. Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-context-provider.c | 18 +++-- liblttng-ust/lttng-ring-buffer-client.h | 94 +++++++++++++++++++++---- liblttng-ust/lttng-tracer-core.h | 11 +++ 3 files changed, 100 insertions(+), 23 deletions(-) diff --git a/liblttng-ust/lttng-context-provider.c b/liblttng-ust/lttng-context-provider.c index e7462cda..b5ae3075 100644 --- a/liblttng-ust/lttng-context-provider.c +++ b/liblttng-ust/lttng-context-provider.c @@ -92,8 +92,7 @@ end: return ret; } -static -size_t dummy_get_size(struct lttng_ctx_field *field, size_t offset) +size_t lttng_ust_dummy_get_size(struct lttng_ctx_field *field, size_t offset) { size_t size = 0; @@ -102,8 +101,7 @@ size_t dummy_get_size(struct lttng_ctx_field *field, size_t offset) return size; } -static -void dummy_record(struct lttng_ctx_field *field, +void lttng_ust_dummy_record(struct lttng_ctx_field *field, struct lttng_ust_lib_ring_buffer_ctx *ctx, struct lttng_channel *chan) { @@ -113,8 +111,7 @@ void dummy_record(struct lttng_ctx_field *field, chan->ops->event_write(ctx, &sel_char, sizeof(sel_char)); } -static -void dummy_get_value(struct lttng_ctx_field *field, +void lttng_ust_dummy_get_value(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; @@ -125,7 +122,8 @@ void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *pr if (ust_lock()) goto end; lttng_ust_context_set_session_provider(provider->name, - dummy_get_size, dummy_record, dummy_get_value); + lttng_ust_dummy_get_size, lttng_ust_dummy_record, + lttng_ust_dummy_get_value); cds_hlist_del(&provider->node); end: ust_unlock(); @@ -168,9 +166,9 @@ int lttng_ust_add_app_context_to_ctx_rcu(const char *name, new_field.record = provider->record; new_field.get_value = provider->get_value; } else { - new_field.get_size = dummy_get_size; - new_field.record = dummy_record; - new_field.get_value = dummy_get_value; + new_field.get_size = lttng_ust_dummy_get_size; + new_field.record = lttng_ust_dummy_record; + new_field.get_value = lttng_ust_dummy_get_value; } ret = lttng_context_add_rcu(ctx, &new_field); if (ret) { diff --git a/liblttng-ust/lttng-ring-buffer-client.h b/liblttng-ust/lttng-ring-buffer-client.h index 1ebb14e4..e5640b2e 100644 --- a/liblttng-ust/lttng-ring-buffer-client.h +++ b/liblttng-ust/lttng-ring-buffer-client.h @@ -30,6 +30,11 @@ #define LTTNG_COMPACT_EVENT_BITS 5 #define LTTNG_COMPACT_TSC_BITS 27 +enum app_ctx_mode { + APP_CTX_DISABLED, + APP_CTX_ENABLED, +}; + /* * Keep the natural field alignment for _each field_ within this structure if * you ever add/remove a field from this header. Packed attribute is not used @@ -71,7 +76,8 @@ static inline uint64_t lib_ring_buffer_clock_read(struct channel *chan) } static inline -size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx) +size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx, + enum app_ctx_mode mode) { int i; size_t orig_offset = offset; @@ -79,23 +85,62 @@ size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx) if (caa_likely(!ctx)) return 0; offset += lib_ring_buffer_align(offset, ctx->largest_align); - for (i = 0; i < ctx->nr_fields; i++) - offset += ctx->fields[i].get_size(&ctx->fields[i], offset); + for (i = 0; i < ctx->nr_fields; i++) { + if (mode == APP_CTX_ENABLED) { + offset += ctx->fields[i].get_size(&ctx->fields[i], offset); + } else { + if (lttng_context_is_app(ctx->fields[i].event_field.name)) { + /* + * Before UST 2.8, we cannot use the + * application context, because we + * cannot trust that the handler used + * for get_size is the same used for + * ctx_record, which would result in + * corrupted traces when tracing + * concurrently with application context + * register/unregister. + */ + offset += lttng_ust_dummy_get_size(&ctx->fields[i], offset); + } else { + offset += ctx->fields[i].get_size(&ctx->fields[i], offset); + } + } + } return offset - orig_offset; } static inline void ctx_record(struct lttng_ust_lib_ring_buffer_ctx *bufctx, struct lttng_channel *chan, - struct lttng_ctx *ctx) + struct lttng_ctx *ctx, + enum app_ctx_mode mode) { int i; if (caa_likely(!ctx)) return; lib_ring_buffer_align_ctx(bufctx, ctx->largest_align); - for (i = 0; i < ctx->nr_fields; i++) - ctx->fields[i].record(&ctx->fields[i], bufctx, chan); + for (i = 0; i < ctx->nr_fields; i++) { + if (mode == APP_CTX_ENABLED) { + ctx->fields[i].record(&ctx->fields[i], bufctx, chan); + } else { + if (lttng_context_is_app(ctx->fields[i].event_field.name)) { + /* + * Before UST 2.8, we cannot use the + * application context, because we + * cannot trust that the handler used + * for get_size is the same used for + * ctx_record, which would result in + * corrupted traces when tracing + * concurrently with application context + * register/unregister. + */ + lttng_ust_dummy_record(&ctx->fields[i], bufctx, chan); + } else { + ctx->fields[i].record(&ctx->fields[i], bufctx, chan); + } + } + } } /* @@ -118,6 +163,7 @@ size_t record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, struct lttng_ust_lib_ring_buffer_ctx *ctx) { struct lttng_channel *lttng_chan = channel_get_private(chan); + struct lttng_event *event = ctx->priv; struct lttng_stack_ctx *lttng_ctx = ctx->priv2; size_t orig_offset = offset; size_t padding; @@ -157,9 +203,15 @@ size_t record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, padding = 0; WARN_ON_ONCE(1); } - offset += ctx_get_size(offset, lttng_ctx->chan_ctx); - offset += ctx_get_size(offset, lttng_ctx->event_ctx); - + if (lttng_ctx) { + /* 2.8+ probe ABI. */ + offset += ctx_get_size(offset, lttng_ctx->chan_ctx, APP_CTX_ENABLED); + offset += ctx_get_size(offset, lttng_ctx->event_ctx, APP_CTX_ENABLED); + } else { + /* Pre 2.8 probe ABI. */ + offset += ctx_get_size(offset, lttng_chan->ctx, APP_CTX_DISABLED); + offset += ctx_get_size(offset, event->ctx, APP_CTX_DISABLED); + } *pre_header_padding = padding; return offset - orig_offset; } @@ -187,6 +239,7 @@ void lttng_write_event_header(const struct lttng_ust_lib_ring_buffer_config *con uint32_t event_id) { struct lttng_channel *lttng_chan = channel_get_private(ctx->chan); + struct lttng_event *event = ctx->priv; struct lttng_stack_ctx *lttng_ctx = ctx->priv2; if (caa_unlikely(ctx->rflags)) @@ -222,8 +275,15 @@ void lttng_write_event_header(const struct lttng_ust_lib_ring_buffer_config *con WARN_ON_ONCE(1); } - ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx); - ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx); + if (lttng_ctx) { + /* 2.8+ probe ABI. */ + ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx, APP_CTX_ENABLED); + ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx, APP_CTX_ENABLED); + } else { + /* Pre 2.8 probe ABI. */ + ctx_record(ctx, lttng_chan, lttng_chan->ctx, APP_CTX_DISABLED); + ctx_record(ctx, lttng_chan, event->ctx, APP_CTX_DISABLED); + } lib_ring_buffer_align_ctx(ctx, ctx->largest_align); return; @@ -238,6 +298,7 @@ void lttng_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config uint32_t event_id) { struct lttng_channel *lttng_chan = channel_get_private(ctx->chan); + struct lttng_event *event = ctx->priv; struct lttng_stack_ctx *lttng_ctx = ctx->priv2; switch (lttng_chan->header_type) { @@ -295,8 +356,15 @@ void lttng_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config default: WARN_ON_ONCE(1); } - ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx); - ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx); + if (lttng_ctx) { + /* 2.8+ probe ABI. */ + ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx, APP_CTX_ENABLED); + ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx, APP_CTX_ENABLED); + } else { + /* Pre 2.8 probe ABI. */ + ctx_record(ctx, lttng_chan, lttng_chan->ctx, APP_CTX_DISABLED); + ctx_record(ctx, lttng_chan, event->ctx, APP_CTX_DISABLED); + } lib_ring_buffer_align_ctx(ctx, ctx->largest_align); } diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index 7d9beaaf..44aca749 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -33,6 +33,9 @@ struct lttng_session; struct lttng_channel; struct lttng_event; +struct lttng_ctx_field; +struct lttng_ust_lib_ring_buffer_ctx; +struct lttng_ctx_value; int ust_lock(void) __attribute__ ((warn_unused_result)); void ust_lock_nocheck(void); @@ -52,4 +55,12 @@ void lttng_ust_malloc_wrapper_init(void); ssize_t lttng_ust_read(int fd, void *buf, size_t len); +size_t lttng_ust_dummy_get_size(struct lttng_ctx_field *field, size_t offset); +void lttng_ust_dummy_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan); +void lttng_ust_dummy_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value); +int lttng_context_is_app(const char *name); + #endif /* _LTTNG_TRACER_CORE_H */ -- 2.34.1