X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fevent-expr%2Fevent-expr.c;h=c3709c882cfc72c2b7efcd3518ae414be686bc26;hb=6a751b953a43c566b74818ec6325db0978e16c66;hp=c0ec2571baa15c9ff2621e4bc3027b650168be57;hpb=6cacd9175901ed12659d1e042343da3321b004d5;p=lttng-tools.git diff --git a/src/common/event-expr/event-expr.c b/src/common/event-expr/event-expr.c index c0ec2571b..c3709c882 100644 --- a/src/common/event-expr/event-expr.c +++ b/src/common/event-expr/event-expr.c @@ -11,9 +11,13 @@ #include #include +#include #include #include +#include #include +#include +#include enum lttng_event_expr_type lttng_event_expr_get_type( const struct lttng_event_expr *expr) @@ -440,3 +444,481 @@ void lttng_event_expr_destroy(struct lttng_event_expr *expr) end: return; } + +static int event_expr_to_bytecode_recursive(const struct lttng_event_expr *expr, + struct lttng_bytecode_alloc **bytecode, + struct lttng_bytecode_alloc **bytecode_reloc) +{ + int status; + enum lttng_event_expr_status event_expr_status; + + switch (lttng_event_expr_get_type(expr)) { + case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: + { + const char *name; + + status = bytecode_push_get_payload_root(bytecode); + if (status) { + ERR("Failed to get payload root from bytecode"); + goto end; + } + + name = lttng_event_expr_event_payload_field_get_name(expr); + if (!name) { + ERR("Failed to get payload field name from event expression"); + status = -1; + goto end; + } + + status = bytecode_push_get_symbol( + bytecode, bytecode_reloc, name); + if (status) { + ERR("Failed to push 'get symbol %s' in bytecode", name); + goto end; + } + + break; + } + case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: + { + const char *name; + + status = bytecode_push_get_context_root(bytecode); + if (status) { + ERR("Failed to get context root from bytecode"); + goto end; + } + + name = lttng_event_expr_channel_context_field_get_name(expr); + if (!name) { + ERR("Failed to get channel context field name from event expression"); + status = -1; + goto end; + } + + status = bytecode_push_get_symbol( + bytecode, bytecode_reloc, name); + if (status) { + ERR("Failed to push 'get symbol %s' in bytecode", name); + goto end; + } + + break; + } + case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: + { + int ret; + char *name = NULL; + const char *provider_name, *type_name; + + status = bytecode_push_get_app_context_root(bytecode); + if (status) { + ERR("Failed to get application context root from bytecode"); + goto end; + } + + provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( + expr); + if (!provider_name) { + ERR("Failed to get application context provider name from event expression"); + status = -1; + goto end; + } + + type_name = lttng_event_expr_app_specific_context_field_get_type_name( + expr); + if (!type_name) { + ERR("Failed to get application context type name from event expression"); + status = -1; + goto end; + } + + /* + * Reconstitute the app context field name from its two parts. + */ + ret = asprintf(&name, "%s:%s", provider_name, type_name); + if (ret < 0) { + PERROR("Failed to format application specific context: provider_name = '%s', type_name = '%s'", + provider_name, type_name); + status = -1; + goto end; + } + + status = bytecode_push_get_symbol( + bytecode, bytecode_reloc, name); + free(name); + if (status) { + ERR("Failed to push 'get symbol %s:%s' in bytecode", + provider_name, type_name); + goto end; + } + + break; + } + case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: + { + unsigned int index; + const struct lttng_event_expr *parent; + + parent = lttng_event_expr_array_field_element_get_parent_expr( + expr); + if (!parent) { + ERR("Failed to get parent expression from array event expression"); + status = -1; + goto end; + } + + status = event_expr_to_bytecode_recursive( + parent, bytecode, bytecode_reloc); + if (status) { + goto end; + } + + event_expr_status = + lttng_event_expr_array_field_element_get_index( + expr, &index); + if (event_expr_status != LTTNG_EVENT_EXPR_STATUS_OK) { + ERR("Failed to get array field element index from event expression"); + status = -1; + goto end; + } + + status = bytecode_push_get_index_u64(bytecode, index); + if (status) { + ERR("Failed to push 'get index %u' in bytecode", index); + goto end; + } + + break; + } + default: + abort(); + } + + status = 0; +end: + return status; +} + +LTTNG_HIDDEN +int lttng_event_expr_to_bytecode(const struct lttng_event_expr *expr, + struct lttng_bytecode **bytecode_out) +{ + int status; + struct return_op ret_insn; + struct lttng_bytecode_alloc *bytecode = NULL; + struct lttng_bytecode_alloc *bytecode_reloc = NULL; + + status = bytecode_init(&bytecode); + if (status) { + ERR("Failed to initialize bytecode"); + goto end; + } + + status = bytecode_init(&bytecode_reloc); + if (status) { + ERR("Failed to initialize relocation bytecode"); + goto end; + } + + status = event_expr_to_bytecode_recursive( + expr, &bytecode, &bytecode_reloc); + if (status) { + /* Errors already logged. */ + goto end; + } + + ret_insn.op = BYTECODE_OP_RETURN; + bytecode_push(&bytecode, &ret_insn, 1, sizeof(ret_insn)); + + /* Append symbol table to bytecode. */ + bytecode->b.reloc_table_offset = bytecode_get_len(&bytecode->b); + status = bytecode_push(&bytecode, bytecode_reloc->b.data, 1, + bytecode_get_len(&bytecode_reloc->b)); + if (status) { + ERR("Failed to push symbol table to bytecode"); + goto end; + } + + /* Copy the `lttng_bytecode` out of the `lttng_bytecode_alloc`. */ + *bytecode_out = lttng_bytecode_copy(&bytecode->b); + if (!*bytecode_out) { + status = -1; + goto end; + } + +end: + if (bytecode) { + free(bytecode); + } + + if (bytecode_reloc) { + free(bytecode_reloc); + } + + return status; +} + +static +enum lttng_error_code lttng_event_expr_event_payload_field_mi_serialize( + const struct lttng_event_expr *expression, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + const char *name = NULL; + + assert(expression); + assert(writer); + assert(expression->type == LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD); + + name = lttng_event_expr_event_payload_field_get_name(expression); + assert(name); + + /* Open event expr payload field element. */ + ret = mi_lttng_writer_open_element( + writer, mi_lttng_element_event_expr_payload_field); + if (ret) { + goto mi_error; + } + + /* Name. */ + ret = mi_lttng_writer_write_element_string( + writer, config_element_name, name); + if (ret) { + goto mi_error; + } + + /* Close event expr payload field element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; +end: + return ret_code; +} + +static +enum lttng_error_code lttng_event_expr_channel_context_field_mi_serialize( + const struct lttng_event_expr *expression, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + const char *name = NULL; + + assert(expression); + assert(writer); + assert(expression->type == LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD); + + name = lttng_event_expr_channel_context_field_get_name(expression); + assert(name); + + /* Open event expr channel context field element. */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_event_expr_channel_context_field); + if (ret) { + goto mi_error; + } + + /* Name. */ + ret = mi_lttng_writer_write_element_string( + writer, config_element_name, name); + if (ret) { + goto mi_error; + } + + /* Close event expr channel context field element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; +end: + return ret_code; +} + +static +enum lttng_error_code lttng_event_expr_app_specific_context_field_mi_serialize( + const struct lttng_event_expr *expression, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + const char *provider_name = NULL; + const char *type_name = NULL; + + assert(expression); + assert(writer); + assert(expression->type == + LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD); + + provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( + expression); + assert(provider_name); + + type_name = lttng_event_expr_app_specific_context_field_get_type_name( + expression); + assert(provider_name); + + /* Open event expr app specific context field element. */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_event_expr_app_specific_context_field); + if (ret) { + goto mi_error; + } + + /* Provider name. */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_event_expr_provider_name, + provider_name); + if (ret) { + goto mi_error; + } + + /* Type name. */ + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_event_expr_type_name, type_name); + if (ret) { + goto mi_error; + } + + /* Close event expr app specific context field element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; +end: + return ret_code; +} + +static +enum lttng_error_code lttng_event_expr_array_field_element_mi_serialize( + const struct lttng_event_expr *expression, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + enum lttng_event_expr_status status; + const struct lttng_event_expr *parent_expr = NULL; + unsigned int index; + + assert(expression); + assert(writer); + assert(expression->type == LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT); + + status = lttng_event_expr_array_field_element_get_index( + expression, &index); + assert(status == LTTNG_EVENT_EXPR_STATUS_OK); + + parent_expr = lttng_event_expr_array_field_element_get_parent_expr( + expression); + assert(parent_expr != NULL); + + /* Open event expr array field element. */ + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_event_expr_array_field_element); + if (ret) { + goto mi_error; + } + + /* Index. */ + ret = mi_lttng_writer_write_element_unsigned_int( + writer, mi_lttng_element_event_expr_index, index); + if (ret) { + goto mi_error; + } + + /* Parent expression. */ + ret_code = lttng_event_expr_mi_serialize(parent_expr, writer); + if (ret_code != LTTNG_OK) { + goto end; + } + + /* Close event expr array field element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; +end: + return ret_code; +} + +LTTNG_HIDDEN +enum lttng_error_code lttng_event_expr_mi_serialize( + const struct lttng_event_expr *expression, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + + assert(expression); + assert(writer); + + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_expr); + if (ret) { + goto mi_error; + } + + switch (expression->type) { + case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: + ret_code = lttng_event_expr_event_payload_field_mi_serialize( + expression, writer); + break; + case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: + ret_code = lttng_event_expr_channel_context_field_mi_serialize( + expression, writer); + break; + case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: + ret_code = lttng_event_expr_app_specific_context_field_mi_serialize( + expression, writer); + break; + case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: + ret_code = lttng_event_expr_array_field_element_mi_serialize( + expression, writer); + break; + default: + abort(); + } + + if (ret_code != LTTNG_OK) { + goto end; + } + + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; + +end: + return ret_code; +}