From 77aa5901fd3f09001fb7e78f3533cf58c6d345e5 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 25 Mar 2013 22:36:22 -0400 Subject: [PATCH] Implement per-context filtering Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-events.h | 9 +++ liblttng-ust/filter-bytecode.h | 9 ++- liblttng-ust/lttng-context-procname.c | 11 +++ liblttng-ust/lttng-context-pthread-id.c | 11 +++ liblttng-ust/lttng-context-vpid.c | 11 +++ liblttng-ust/lttng-context-vtid.c | 10 +++ liblttng-ust/lttng-context.c | 21 +++++ liblttng-ust/lttng-filter-interpreter.c | 76 +++++++++++++++++- liblttng-ust/lttng-filter-specialize.c | 14 +++- liblttng-ust/lttng-filter-validator.c | 65 ++++++++++++++- liblttng-ust/lttng-filter.c | 100 +++++++++++++++++++++--- 11 files changed, 320 insertions(+), 17 deletions(-) diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 2b960305..c79bbed6 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -205,6 +205,12 @@ struct lttng_event_field { char padding[LTTNG_UST_EVENT_FIELD_PADDING]; }; +union lttng_ctx_value { + int64_t s64; + const char *str; + double d; +}; + #define LTTNG_UST_CTX_FIELD_PADDING 40 struct lttng_ctx_field { struct lttng_event_field event_field; @@ -212,6 +218,8 @@ struct lttng_ctx_field { void (*record)(struct lttng_ctx_field *field, struct lttng_ust_lib_ring_buffer_ctx *ctx, struct lttng_channel *chan); + void (*get_value)(struct lttng_ctx_field *field, + union lttng_ctx_value *value); union { char padding[LTTNG_UST_CTX_FIELD_PADDING]; } u; @@ -520,6 +528,7 @@ int lttng_fix_pending_event_desc(const struct lttng_event_desc *desc); int lttng_probes_init(void); void lttng_probes_exit(void); int lttng_find_context(struct lttng_ctx *ctx, const char *name); +int lttng_get_context_index(struct lttng_ctx *ctx, const char *name); struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p); void lttng_remove_context_field(struct lttng_ctx **ctx_p, struct lttng_ctx_field *field); diff --git a/liblttng-ust/filter-bytecode.h b/liblttng-ust/filter-bytecode.h index 3358a2fd..ce2dbc73 100644 --- a/liblttng-ust/filter-bytecode.h +++ b/liblttng-ust/filter-bytecode.h @@ -124,13 +124,14 @@ enum filter_op { FILTER_OP_AND, FILTER_OP_OR, - /* load */ + /* load field ref */ FILTER_OP_LOAD_FIELD_REF, FILTER_OP_LOAD_FIELD_REF_STRING, FILTER_OP_LOAD_FIELD_REF_SEQUENCE, FILTER_OP_LOAD_FIELD_REF_S64, FILTER_OP_LOAD_FIELD_REF_DOUBLE, + /* load immediate from operand */ FILTER_OP_LOAD_STRING, FILTER_OP_LOAD_S64, FILTER_OP_LOAD_DOUBLE, @@ -140,6 +141,12 @@ enum filter_op { FILTER_OP_CAST_DOUBLE_TO_S64, FILTER_OP_CAST_NOP, + /* get context ref */ + FILTER_OP_GET_CONTEXT_REF, + FILTER_OP_GET_CONTEXT_REF_STRING, + FILTER_OP_GET_CONTEXT_REF_S64, + FILTER_OP_GET_CONTEXT_REF_DOUBLE, + NR_FILTER_OPS, }; diff --git a/liblttng-ust/lttng-context-procname.c b/liblttng-ust/lttng-context-procname.c index 0e7bf1ce..c76d8ba3 100644 --- a/liblttng-ust/lttng-context-procname.c +++ b/liblttng-ust/lttng-context-procname.c @@ -74,6 +74,16 @@ void procname_record(struct lttng_ctx_field *field, chan->ops->event_write(ctx, procname, LTTNG_UST_PROCNAME_LEN); } +static +void procname_get_value(struct lttng_ctx_field *field, + union lttng_ctx_value *value) +{ + char *procname; + + procname = wrapper_getprocname(); + value->str = procname; +} + int lttng_add_procname_to_ctx(struct lttng_ctx **ctx) { struct lttng_ctx_field *field; @@ -97,6 +107,7 @@ int lttng_add_procname_to_ctx(struct lttng_ctx **ctx) field->event_field.type.u.array.length = LTTNG_UST_PROCNAME_LEN; field->get_size = procname_get_size; field->record = procname_record; + field->get_value = procname_get_value; return 0; } diff --git a/liblttng-ust/lttng-context-pthread-id.c b/liblttng-ust/lttng-context-pthread-id.c index e0f662f2..bf20c695 100644 --- a/liblttng-ust/lttng-context-pthread-id.c +++ b/liblttng-ust/lttng-context-pthread-id.c @@ -47,6 +47,16 @@ void pthread_id_record(struct lttng_ctx_field *field, chan->ops->event_write(ctx, &pthread_id, sizeof(pthread_id)); } +static +void pthread_id_get_value(struct lttng_ctx_field *field, + union lttng_ctx_value *value) +{ + unsigned long pthread_id; + + pthread_id = (unsigned long) pthread_self(); + value->s64 = pthread_id; +} + int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx) { struct lttng_ctx_field *field; @@ -68,5 +78,6 @@ int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx) field->event_field.type.u.basic.integer.encoding = lttng_encode_none; field->get_size = pthread_id_get_size; field->record = pthread_id_record; + field->get_value = pthread_id_get_value; return 0; } diff --git a/liblttng-ust/lttng-context-vpid.c b/liblttng-ust/lttng-context-vpid.c index 3ab786f4..949529c6 100644 --- a/liblttng-ust/lttng-context-vpid.c +++ b/liblttng-ust/lttng-context-vpid.c @@ -83,6 +83,16 @@ void vpid_record(struct lttng_ctx_field *field, chan->ops->event_write(ctx, &pid, sizeof(pid)); } +static +void vpid_get_value(struct lttng_ctx_field *field, + union lttng_ctx_value *value) +{ + pid_t pid; + + pid = wrapper_getpid(); + value->s64 = pid; +} + int lttng_add_vpid_to_ctx(struct lttng_ctx **ctx) { struct lttng_ctx_field *field; @@ -104,5 +114,6 @@ int lttng_add_vpid_to_ctx(struct lttng_ctx **ctx) field->event_field.type.u.basic.integer.encoding = lttng_encode_none; field->get_size = vpid_get_size; field->record = vpid_record; + field->get_value = vpid_get_value; return 0; } diff --git a/liblttng-ust/lttng-context-vtid.c b/liblttng-ust/lttng-context-vtid.c index 4b1da4f8..7d83b87c 100644 --- a/liblttng-ust/lttng-context-vtid.c +++ b/liblttng-ust/lttng-context-vtid.c @@ -67,6 +67,15 @@ void vtid_record(struct lttng_ctx_field *field, sizeof(URCU_TLS(cached_vtid))); } +static +void vtid_get_value(struct lttng_ctx_field *field, + union lttng_ctx_value *value) +{ + if (caa_unlikely(!URCU_TLS(cached_vtid))) + URCU_TLS(cached_vtid) = gettid(); + value->s64 = URCU_TLS(cached_vtid); +} + int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx) { struct lttng_ctx_field *field; @@ -88,6 +97,7 @@ int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx) field->event_field.type.u.basic.integer.encoding = lttng_encode_none; field->get_size = vtid_get_size; field->record = vtid_record; + field->get_value = vtid_get_value; return 0; } diff --git a/liblttng-ust/lttng-context.c b/liblttng-ust/lttng-context.c index 16894ec1..fc2ab4f5 100644 --- a/liblttng-ust/lttng-context.c +++ b/liblttng-ust/lttng-context.c @@ -27,6 +27,11 @@ #include #include +/* + * The filter implementation requires that two consecutive "get" for the + * same context performed by the same thread return the same result. + */ + int lttng_find_context(struct lttng_ctx *ctx, const char *name) { unsigned int i; @@ -41,6 +46,22 @@ int lttng_find_context(struct lttng_ctx *ctx, const char *name) return 0; } +int lttng_get_context_index(struct lttng_ctx *ctx, const char *name) +{ + unsigned int i; + + if (!ctx) + return -1; + for (i = 0; i < ctx->nr_fields; i++) { + /* Skip allocated (but non-initialized) contexts */ + if (!ctx->fields[i].event_field.name) + continue; + if (!strcmp(ctx->fields[i].event_field.name, name)) + return i; + } + return -1; +} + /* * Note: as we append context information, the pointer location may change. */ diff --git a/liblttng-ust/lttng-filter-interpreter.c b/liblttng-ust/lttng-filter-interpreter.c index 86409608..1f43dece 100644 --- a/liblttng-ust/lttng-filter-interpreter.c +++ b/liblttng-ust/lttng-filter-interpreter.c @@ -176,6 +176,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, const char *filter_stack_data) { struct bytecode_runtime *bytecode = filter_data; + struct lttng_ctx *ctx = bytecode->p.bc->enabler->chan->ctx; void *pc, *next_pc, *start_pc; int ret = -EINVAL; uint64_t retval = 0; @@ -263,13 +264,14 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_AND ] = &&LABEL_FILTER_OP_AND, [ FILTER_OP_OR ] = &&LABEL_FILTER_OP_OR, - /* load */ + /* load field ref */ [ FILTER_OP_LOAD_FIELD_REF ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF, [ FILTER_OP_LOAD_FIELD_REF_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_STRING, [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_SEQUENCE, [ FILTER_OP_LOAD_FIELD_REF_S64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_S64, [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_DOUBLE, + /* load from immediate operand */ [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, @@ -278,6 +280,12 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_CAST_TO_S64 ] = &&LABEL_FILTER_OP_CAST_TO_S64, [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = &&LABEL_FILTER_OP_CAST_DOUBLE_TO_S64, [ FILTER_OP_CAST_NOP ] = &&LABEL_FILTER_OP_CAST_NOP, + + /* get context ref */ + [ FILTER_OP_GET_CONTEXT_REF ] = &&LABEL_FILTER_OP_GET_CONTEXT_REF, + [ FILTER_OP_GET_CONTEXT_REF_STRING ] = &&LABEL_FILTER_OP_GET_CONTEXT_REF_STRING, + [ FILTER_OP_GET_CONTEXT_REF_S64 ] = &&LABEL_FILTER_OP_GET_CONTEXT_REF_S64, + [ FILTER_OP_GET_CONTEXT_REF_DOUBLE ] = &&LABEL_FILTER_OP_GET_CONTEXT_REF_DOUBLE, }; #endif /* #ifndef INTERPRETER_USE_SWITCH */ @@ -285,6 +293,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNKNOWN): OP(FILTER_OP_LOAD_FIELD_REF): + OP(FILTER_OP_GET_CONTEXT_REF): #ifdef INTERPRETER_USE_SWITCH default: #endif /* INTERPRETER_USE_SWITCH */ @@ -710,7 +719,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, } - /* load */ + /* load field ref */ OP(FILTER_OP_LOAD_FIELD_REF_STRING): { struct load_op *insn = (struct load_op *) pc; @@ -786,6 +795,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, PO; } + /* load from immediate operand */ OP(FILTER_OP_LOAD_STRING): { struct load_op *insn = (struct load_op *) pc; @@ -844,6 +854,68 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, PO; } + /* get context ref */ + OP(FILTER_OP_GET_CONTEXT_REF_STRING): + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + struct lttng_ctx_field *ctx_field; + union lttng_ctx_value v; + + dbg_printf("get context ref offset %u type string\n", + ref->offset); + ctx_field = &ctx->fields[ref->offset]; + ctx_field->get_value(ctx_field, &v); + estack_push(stack, top, ax, bx); + estack_ax(stack, top)->u.s.str = v.str; + if (unlikely(!estack_ax(stack, top)->u.s.str)) { + dbg_printf("Filter warning: loading a NULL string.\n"); + ret = -EINVAL; + goto end; + } + estack_ax(stack, top)->u.s.seq_len = UINT_MAX; + estack_ax(stack, top)->u.s.literal = 0; + dbg_printf("ref get context string %s\n", estack_ax(stack, top)->u.s.str); + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + PO; + } + + OP(FILTER_OP_GET_CONTEXT_REF_S64): + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + struct lttng_ctx_field *ctx_field; + union lttng_ctx_value v; + + dbg_printf("get context ref offset %u type s64\n", + ref->offset); + ctx_field = &ctx->fields[ref->offset]; + ctx_field->get_value(ctx_field, &v); + estack_push(stack, top, ax, bx); + estack_ax_v = v.s64; + dbg_printf("ref get context s64 %" PRIi64 "\n", estack_ax_v); + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + PO; + } + + OP(FILTER_OP_GET_CONTEXT_REF_DOUBLE): + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + struct lttng_ctx_field *ctx_field; + union lttng_ctx_value v; + + dbg_printf("get context ref offset %u type double\n", + ref->offset); + ctx_field = &ctx->fields[ref->offset]; + ctx_field->get_value(ctx_field, &v); + estack_push(stack, top, ax, bx); + memcpy(&estack_ax(stack, top)->u.d, &v.d, sizeof(struct literal_double)); + dbg_printf("ref get context double %g\n", estack_ax(stack, top)->u.d); + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + PO; + } + END_OP end: /* return 0 (discard) on error */ diff --git a/liblttng-ust/lttng-filter-specialize.c b/liblttng-ust/lttng-filter-specialize.c index 66e3db6f..a729e427 100644 --- a/liblttng-ust/lttng-filter-specialize.c +++ b/liblttng-ust/lttng-filter-specialize.c @@ -406,15 +406,23 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } - /* load */ + /* load field ref */ case FILTER_OP_LOAD_FIELD_REF: { ERR("Unknown field ref type\n"); ret = -EINVAL; goto end; } + /* get context ref */ + case FILTER_OP_GET_CONTEXT_REF: + { + ERR("Unknown get context ref type\n"); + ret = -EINVAL; + goto end; + } case FILTER_OP_LOAD_FIELD_REF_STRING: case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: + case FILTER_OP_GET_CONTEXT_REF_STRING: { if (vstack_push(stack)) { ret = -EINVAL; @@ -425,6 +433,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } case FILTER_OP_LOAD_FIELD_REF_S64: + case FILTER_OP_GET_CONTEXT_REF_S64: { if (vstack_push(stack)) { ret = -EINVAL; @@ -435,6 +444,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + case FILTER_OP_GET_CONTEXT_REF_DOUBLE: { if (vstack_push(stack)) { ret = -EINVAL; @@ -445,6 +455,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } + /* load from immediate operand */ case FILTER_OP_LOAD_STRING: { struct load_op *insn = (struct load_op *) pc; @@ -522,7 +533,6 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } - } } end: diff --git a/liblttng-ust/lttng-filter-validator.c b/liblttng-ust/lttng-filter-validator.c index 456407ff..6cdfd8c1 100644 --- a/liblttng-ust/lttng-filter-validator.c +++ b/liblttng-ust/lttng-filter-validator.c @@ -286,17 +286,27 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, break; } - /* load */ + /* load field ref */ case FILTER_OP_LOAD_FIELD_REF: { ERR("Unknown field ref type\n"); ret = -EINVAL; break; } + /* get context ref */ + case FILTER_OP_GET_CONTEXT_REF: + { + ERR("Unknown field ref type\n"); + ret = -EINVAL; + break; + } case FILTER_OP_LOAD_FIELD_REF_STRING: case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: case FILTER_OP_LOAD_FIELD_REF_S64: case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + case FILTER_OP_GET_CONTEXT_REF_STRING: + case FILTER_OP_GET_CONTEXT_REF_S64: + case FILTER_OP_GET_CONTEXT_REF_DOUBLE: { if (unlikely(pc + sizeof(struct load_op) + sizeof(struct field_ref) > start_pc + bytecode->len)) { @@ -305,6 +315,7 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, break; } + /* load from immediate operand */ case FILTER_OP_LOAD_STRING: { struct load_op *insn = (struct load_op *) pc; @@ -353,6 +364,7 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, } break; } + } return ret; @@ -657,7 +669,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } - /* load */ + /* load field ref */ case FILTER_OP_LOAD_FIELD_REF: { ERR("Unknown field ref type\n"); @@ -693,6 +705,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } + /* load from immediate operand */ case FILTER_OP_LOAD_STRING: { break; @@ -747,6 +760,41 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } + /* get context ref */ + case FILTER_OP_GET_CONTEXT_REF: + { + ERR("Unknown get context ref type\n"); + ret = -EINVAL; + goto end; + } + case FILTER_OP_GET_CONTEXT_REF_STRING: + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + + dbg_printf("Validate get context ref offset %u type string\n", + ref->offset); + break; + } + case FILTER_OP_GET_CONTEXT_REF_S64: + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + + dbg_printf("Validate get context ref offset %u type s64\n", + ref->offset); + break; + } + case FILTER_OP_GET_CONTEXT_REF_DOUBLE: + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + + dbg_printf("Validate get context ref offset %u type double\n", + ref->offset); + break; + } + } end: return ret; @@ -966,15 +1014,23 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } - /* load */ + /* load field ref */ case FILTER_OP_LOAD_FIELD_REF: { ERR("Unknown field ref type\n"); ret = -EINVAL; goto end; } + /* get context ref */ + case FILTER_OP_GET_CONTEXT_REF: + { + ERR("Unknown get context ref type\n"); + ret = -EINVAL; + goto end; + } case FILTER_OP_LOAD_FIELD_REF_STRING: case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: + case FILTER_OP_GET_CONTEXT_REF_STRING: { if (vstack_push(stack)) { ret = -EINVAL; @@ -985,6 +1041,7 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } case FILTER_OP_LOAD_FIELD_REF_S64: + case FILTER_OP_GET_CONTEXT_REF_S64: { if (vstack_push(stack)) { ret = -EINVAL; @@ -995,6 +1052,7 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + case FILTER_OP_GET_CONTEXT_REF_DOUBLE: { if (vstack_push(stack)) { ret = -EINVAL; @@ -1005,6 +1063,7 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } + /* load from immediate operand */ case FILTER_OP_LOAD_STRING: { struct load_op *insn = (struct load_op *) pc; diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index 11e7e376..4bb7d4dc 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -102,13 +102,14 @@ static const char *opnames[] = { [ FILTER_OP_AND ] = "AND", [ FILTER_OP_OR ] = "OR", - /* load */ + /* load field ref */ [ FILTER_OP_LOAD_FIELD_REF ] = "LOAD_FIELD_REF", [ FILTER_OP_LOAD_FIELD_REF_STRING ] = "LOAD_FIELD_REF_STRING", [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = "LOAD_FIELD_REF_SEQUENCE", [ FILTER_OP_LOAD_FIELD_REF_S64 ] = "LOAD_FIELD_REF_S64", [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = "LOAD_FIELD_REF_DOUBLE", + /* load from immediate operand */ [ FILTER_OP_LOAD_STRING ] = "LOAD_STRING", [ FILTER_OP_LOAD_S64 ] = "LOAD_S64", [ FILTER_OP_LOAD_DOUBLE ] = "LOAD_DOUBLE", @@ -117,6 +118,12 @@ static const char *opnames[] = { [ FILTER_OP_CAST_TO_S64 ] = "CAST_TO_S64", [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = "CAST_DOUBLE_TO_S64", [ FILTER_OP_CAST_NOP ] = "CAST_NOP", + + /* get context ref */ + [ FILTER_OP_GET_CONTEXT_REF ] = "GET_CONTEXT_REF", + [ FILTER_OP_GET_CONTEXT_REF_STRING ] = "GET_CONTEXT_REF_STRING", + [ FILTER_OP_GET_CONTEXT_REF_S64 ] = "GET_CONTEXT_REF_S64", + [ FILTER_OP_GET_CONTEXT_REF_DOUBLE ] = "GET_CONTEXT_REF_DOUBLE", }; const char *print_op(enum filter_op op) @@ -141,11 +148,7 @@ int apply_field_reloc(struct lttng_event *event, struct load_op *op; uint32_t field_offset = 0; - dbg_printf("Apply reloc: %u %s\n", reloc_offset, field_name); - - /* Ensure that the reloc is within the code */ - if (runtime_len - reloc_offset < sizeof(uint16_t)) - return -EINVAL; + dbg_printf("Apply field reloc: %u %s\n", reloc_offset, field_name); /* Lookup event by name */ desc = event->desc; @@ -214,6 +217,85 @@ int apply_field_reloc(struct lttng_event *event, return 0; } +static +int apply_context_reloc(struct lttng_event *event, + struct bytecode_runtime *runtime, + uint32_t runtime_len, + uint32_t reloc_offset, + const char *context_name) +{ + struct field_ref *field_ref; + struct load_op *op; + struct lttng_ctx_field *ctx_field; + int idx; + + dbg_printf("Apply context reloc: %u %s\n", reloc_offset, context_name); + + /* Get context index */ + idx = lttng_get_context_index(event->chan->ctx, context_name); + if (idx < 0) + return -ENOENT; + + /* Check if idx is too large for 16-bit offset */ + if (idx > FILTER_BYTECODE_MAX_LEN - 1) + return -EINVAL; + + /* Get context return type */ + ctx_field = &event->chan->ctx->fields[idx]; + op = (struct load_op *) &runtime->data[reloc_offset]; + field_ref = (struct field_ref *) op->data; + switch (ctx_field->event_field.type.atype) { + case atype_integer: + case atype_enum: + op->op = FILTER_OP_GET_CONTEXT_REF_S64; + break; + /* Sequence and array supported as string */ + case atype_string: + case atype_array: + case atype_sequence: + op->op = FILTER_OP_GET_CONTEXT_REF_STRING; + break; + case atype_float: + op->op = FILTER_OP_GET_CONTEXT_REF_DOUBLE; + break; + default: + return -EINVAL; + } + /* set offset to context index within channel contexts */ + field_ref->offset = (uint16_t) idx; + return 0; +} + +static +int apply_reloc(struct lttng_event *event, + struct bytecode_runtime *runtime, + uint32_t runtime_len, + uint32_t reloc_offset, + const char *name) +{ + struct load_op *op; + + dbg_printf("Apply reloc: %u %s\n", reloc_offset, name); + + /* Ensure that the reloc is within the code */ + if (runtime_len - reloc_offset < sizeof(uint16_t)) + return -EINVAL; + + op = (struct load_op *) &runtime->data[reloc_offset]; + switch (op->op) { + case FILTER_OP_LOAD_FIELD_REF: + return apply_field_reloc(event, runtime, runtime_len, + reloc_offset, name); + case FILTER_OP_GET_CONTEXT_REF: + return apply_context_reloc(event, runtime, runtime_len, + reloc_offset, name); + default: + ERR("Unknown reloc op type %u\n", op->op); + return -EINVAL; + } + return 0; +} + static int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode, struct lttng_event *event) @@ -269,14 +351,14 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event, offset = next_offset) { uint16_t reloc_offset = *(uint16_t *) &filter_bytecode->bc.data[offset]; - const char *field_name = + const char *name = (const char *) &filter_bytecode->bc.data[offset + sizeof(uint16_t)]; - ret = apply_field_reloc(event, runtime, runtime->len, reloc_offset, field_name); + ret = apply_reloc(event, runtime, runtime->len, reloc_offset, name); if (ret) { goto link_error; } - next_offset = offset + sizeof(uint16_t) + strlen(field_name) + 1; + next_offset = offset + sizeof(uint16_t) + strlen(name) + 1; } /* Validate bytecode */ ret = lttng_filter_validate_bytecode(runtime); -- 2.34.1