LTTNG_HIDDEN int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx) { int ret; ret = bytecode_init(&ctx->bytecode); if (ret) return ret; ret = bytecode_init(&ctx->bytecode_reloc); if (ret) goto error; ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root); if (ret) goto error; /* Finally, append symbol table to bytecode */ ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b); return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data, 1, bytecode_get_len(&ctx->bytecode_reloc->b)); error: filter_bytecode_free(ctx); return ret; }
/* * Enable event(s) for a channel, possibly with exclusions and a filter. * If no event name is specified, all events are enabled. * If no channel name is specified, the default name is used. * If filter expression is not NULL, the filter is set for the event. * If exclusion count is not zero, the exclusions are set for the event. * Returns size of returned session payload data or a negative error code. */ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, struct lttng_event *ev, const char *channel_name, const char *original_filter_expression, int exclusion_count, char **exclusion_list) { struct lttcomm_session_msg lsm; char *varlen_data; int ret = 0; unsigned int free_filter_expression = 0; struct filter_parser_ctx *ctx = NULL; /* * Cast as non-const since we may replace the filter expression * by a dynamically allocated string. Otherwise, the original * string is not modified. */ char *filter_expression = (char *) original_filter_expression; if (handle == NULL || ev == NULL) { ret = -LTTNG_ERR_INVALID; goto error; } /* Empty filter string will always be rejected by the parser * anyway, so treat this corner-case early to eliminate * lttng_fmemopen error for 0-byte allocation. */ if (filter_expression && filter_expression[0] == '\0') { ret = -LTTNG_ERR_INVALID; goto error; } memset(&lsm, 0, sizeof(lsm)); /* If no channel name, send empty string. */ if (channel_name == NULL) { lttng_ctl_copy_string(lsm.u.enable.channel_name, "", sizeof(lsm.u.enable.channel_name)); } else { lttng_ctl_copy_string(lsm.u.enable.channel_name, channel_name, sizeof(lsm.u.enable.channel_name)); } lsm.cmd_type = LTTNG_ENABLE_EVENT; if (ev->name[0] == '\0') { /* Enable all events */ lttng_ctl_copy_string(ev->name, "*", sizeof(ev->name)); } lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain); /* FIXME: copying non-packed struct to packed struct. */ memcpy(&lsm.u.enable.event, ev, sizeof(lsm.u.enable.event)); lttng_ctl_copy_string(lsm.session.name, handle->session_name, sizeof(lsm.session.name)); lsm.u.enable.exclusion_count = exclusion_count; lsm.u.enable.bytecode_len = 0; /* * For the JUL domain, a filter is enforced except for the enable all * event. This is done to avoid having the event in all sessions thus * filtering by logger name. */ if (exclusion_count == 0 && filter_expression == NULL && (handle->domain.type != LTTNG_DOMAIN_JUL && handle->domain.type != LTTNG_DOMAIN_LOG4J && handle->domain.type != LTTNG_DOMAIN_PYTHON)) { goto ask_sessiond; } /* * We have either a filter or some exclusions, so we need to set up * a variable-length memory block from where to send the data */ /* Parse filter expression */ if (filter_expression != NULL || handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || handle->domain.type == LTTNG_DOMAIN_PYTHON) { if (handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || handle->domain.type == LTTNG_DOMAIN_PYTHON) { char *agent_filter; /* Setup JUL filter if needed. */ agent_filter = set_agent_filter(filter_expression, ev); if (!agent_filter) { if (!filter_expression) { /* No JUL and no filter, just skip everything below. */ goto ask_sessiond; } } else { /* * With an agent filter, the original filter has been added to * it thus replace the filter expression. */ filter_expression = agent_filter; free_filter_expression = 1; } } ret = generate_filter(filter_expression, &lsm, &ctx); if (ret) { goto filter_error; } } varlen_data = zmalloc(lsm.u.enable.bytecode_len + lsm.u.enable.expression_len + LTTNG_SYMBOL_NAME_LEN * exclusion_count); if (!varlen_data) { ret = -LTTNG_ERR_EXCLUSION_NOMEM; goto mem_error; } /* Put exclusion names first in the data */ while (exclusion_count--) { strncpy(varlen_data + LTTNG_SYMBOL_NAME_LEN * exclusion_count, *(exclusion_list + exclusion_count), LTTNG_SYMBOL_NAME_LEN); } /* Add filter expression next */ if (lsm.u.enable.expression_len != 0) { memcpy(varlen_data + LTTNG_SYMBOL_NAME_LEN * lsm.u.enable.exclusion_count, filter_expression, lsm.u.enable.expression_len); } /* Add filter bytecode next */ if (ctx && lsm.u.enable.bytecode_len != 0) { memcpy(varlen_data + LTTNG_SYMBOL_NAME_LEN * lsm.u.enable.exclusion_count + lsm.u.enable.expression_len, &ctx->bytecode->b, lsm.u.enable.bytecode_len); } ret = lttng_ctl_ask_sessiond_varlen(&lsm, varlen_data, (LTTNG_SYMBOL_NAME_LEN * lsm.u.enable.exclusion_count) + lsm.u.enable.bytecode_len + lsm.u.enable.expression_len, NULL); free(varlen_data); mem_error: if (filter_expression && ctx) { filter_bytecode_free(ctx); filter_ir_free(ctx); filter_parser_ctx_free(ctx); } filter_error: if (free_filter_expression) { /* * The filter expression has been replaced and must be freed as it is * not the original filter expression received as a parameter. */ free(filter_expression); } error: /* * Return directly to the caller and don't ask the sessiond since something * went wrong in the parsing of data above. */ return ret; ask_sessiond: ret = lttng_ctl_ask_sessiond(&lsm, NULL); return ret; }
int main(int argc, char **argv) { struct filter_parser_ctx *ctx; int ret; int print_xml = 0, generate_ir = 0, generate_bytecode = 0, print_bytecode = 0; int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-p") == 0) print_xml = 1; else if (strcmp(argv[i], "-i") == 0) generate_ir = 1; else if (strcmp(argv[i], "-b") == 0) generate_bytecode = 1; else if (strcmp(argv[i], "-d") == 0) filter_parser_debug = 1; else if (strcmp(argv[i], "-B") == 0) print_bytecode = 1; } ctx = filter_parser_ctx_alloc(stdin); if (!ctx) { fprintf(stderr, "Error allocating parser\n"); goto alloc_error; } ret = filter_parser_ctx_append_ast(ctx); if (ret) { fprintf(stderr, "Parse error\n"); goto parse_error; } ret = filter_visitor_set_parent(ctx); if (ret) { fprintf(stderr, "Set parent error\n"); goto parse_error; } if (print_xml) { ret = filter_visitor_print_xml(ctx, stdout, 0); if (ret) { fflush(stdout); fprintf(stderr, "XML print error\n"); goto parse_error; } } if (generate_ir) { printf("Generating IR... "); fflush(stdout); ret = filter_visitor_ir_generate(ctx); if (ret) { fprintf(stderr, "Generate IR error\n"); goto parse_error; } printf("done\n"); printf("Validating IR... "); fflush(stdout); ret = filter_visitor_ir_check_binary_op_nesting(ctx); if (ret) { goto parse_error; } printf("done\n"); } if (generate_bytecode) { printf("Generating bytecode... "); fflush(stdout); ret = filter_visitor_bytecode_generate(ctx); if (ret) { fprintf(stderr, "Generate bytecode error\n"); goto parse_error; } printf("done\n"); printf("Size of bytecode generated: %u bytes.\n", bytecode_get_len(&ctx->bytecode->b)); } #if 0 if (run_bytecode) { int64_t retval; printf("Interpreting bytecode... "); fflush(stdout); ret = bytecode_interpret(&ctx->bytecode->b, &retval, NULL); if (ret) { fprintf(stderr, "Error interpreting bytecode\n"); goto parse_error; } else { printf("Bytecode interpret result: %" PRIi64 "\n", retval); } printf("done\n"); } #endif //0 if (print_bytecode) { unsigned int bytecode_len, len, i; len = bytecode_get_len(&ctx->bytecode->b); bytecode_len = ctx->bytecode->b.reloc_table_offset; printf("Bytecode:\n"); for (i = 0; i < bytecode_len; i++) { printf("0x%X ", ((uint8_t *) ctx->bytecode->b.data)[i]); } printf("\n"); printf("Reloc table:\n"); for (i = bytecode_len; i < len;) { printf("{ 0x%X, ", *(uint16_t *) &ctx->bytecode->b.data[i]); i += sizeof(uint16_t); printf("%s } ", &((char *) ctx->bytecode->b.data)[i]); i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1; } printf("\n"); } filter_bytecode_free(ctx); filter_ir_free(ctx); filter_parser_ctx_free(ctx); return 0; parse_error: filter_bytecode_free(ctx); filter_ir_free(ctx); filter_parser_ctx_free(ctx); alloc_error: exit(EXIT_FAILURE); }
/* * Create or enable an event with a filter expression. * * Return negative error value on error. * Return size of returned session payload data if OK. */ int lttng_enable_event_with_filter(struct lttng_handle *handle, struct lttng_event *event, const char *channel_name, const char *filter_expression) { struct lttcomm_session_msg lsm; struct filter_parser_ctx *ctx; FILE *fmem; int ret = 0; if (!filter_expression) { /* * Fall back to normal event enabling if no filter * specified. */ return lttng_enable_event(handle, event, channel_name); } /* * Empty filter string will always be rejected by the parser * anyway, so treat this corner-case early to eliminate * lttng_fmemopen error for 0-byte allocation. */ if (handle == NULL || filter_expression[0] == '\0') { return -LTTNG_ERR_INVALID; } /* * casting const to non-const, as the underlying function will * use it in read-only mode. */ fmem = lttng_fmemopen((void *) filter_expression, strlen(filter_expression), "r"); if (!fmem) { fprintf(stderr, "Error opening memory as stream\n"); return -LTTNG_ERR_FILTER_NOMEM; } ctx = filter_parser_ctx_alloc(fmem); if (!ctx) { fprintf(stderr, "Error allocating parser\n"); ret = -LTTNG_ERR_FILTER_NOMEM; goto alloc_error; } ret = filter_parser_ctx_append_ast(ctx); if (ret) { fprintf(stderr, "Parse error\n"); ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } ret = filter_visitor_set_parent(ctx); if (ret) { fprintf(stderr, "Set parent error\n"); ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } if (print_xml) { ret = filter_visitor_print_xml(ctx, stdout, 0); if (ret) { fflush(stdout); fprintf(stderr, "XML print error\n"); ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } } dbg_printf("Generating IR... "); fflush(stdout); ret = filter_visitor_ir_generate(ctx); if (ret) { fprintf(stderr, "Generate IR error\n"); ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } dbg_printf("done\n"); dbg_printf("Validating IR... "); fflush(stdout); ret = filter_visitor_ir_check_binary_op_nesting(ctx); if (ret) { ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } dbg_printf("done\n"); dbg_printf("Generating bytecode... "); fflush(stdout); ret = filter_visitor_bytecode_generate(ctx); if (ret) { fprintf(stderr, "Generate bytecode error\n"); ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } dbg_printf("done\n"); dbg_printf("Size of bytecode generated: %u bytes.\n", bytecode_get_len(&ctx->bytecode->b)); memset(&lsm, 0, sizeof(lsm)); lsm.cmd_type = LTTNG_ENABLE_EVENT_WITH_FILTER; /* Copy channel name */ copy_string(lsm.u.enable.channel_name, channel_name, sizeof(lsm.u.enable.channel_name)); /* Copy event name */ if (event) { memcpy(&lsm.u.enable.event, event, sizeof(lsm.u.enable.event)); } lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b) + bytecode_get_len(&ctx->bytecode->b); copy_lttng_domain(&lsm.domain, &handle->domain); copy_string(lsm.session.name, handle->session_name, sizeof(lsm.session.name)); ret = ask_sessiond_varlen(&lsm, &ctx->bytecode->b, lsm.u.enable.bytecode_len, NULL); filter_bytecode_free(ctx); filter_ir_free(ctx); filter_parser_ctx_free(ctx); if (fclose(fmem) != 0) { perror("fclose"); } return ret; parse_error: filter_bytecode_free(ctx); filter_ir_free(ctx); filter_parser_ctx_free(ctx); alloc_error: if (fclose(fmem) != 0) { perror("fclose"); } return ret; }