+static
+struct lttng_event_expr *ir_op_load_expr_to_event_expr(
+ const struct ir_load_expression *load_exp, const char *capture_str)
+{
+ char *provider_name = NULL;
+ struct lttng_event_expr *event_expr = NULL;
+ const struct ir_load_expression_op *load_expr_op = load_exp->child;
+
+ switch (load_expr_op->type) {
+ case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+ case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+ {
+ const char *field_name;
+
+ load_expr_op = load_expr_op->next;
+ assert(load_expr_op);
+ assert(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
+ field_name = load_expr_op->u.symbol;
+ assert(field_name);
+
+ event_expr = load_expr_op->type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
+ lttng_event_expr_event_payload_field_create(field_name) :
+ lttng_event_expr_channel_context_field_create(field_name);
+ if (!event_expr) {
+ ERR("Failed to create %s event expression: field name = `%s`.",
+ load_expr_op->type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
+ "payload field" : "channel context",
+ field_name);
+ goto error;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+ {
+ const char *colon;
+ const char *type_name;
+ const char *field_name;
+
+ load_expr_op = load_expr_op->next;
+ assert(load_expr_op);
+ assert(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
+ field_name = load_expr_op->u.symbol;
+ assert(field_name);
+
+ /*
+ * The field name needs to be of the form PROVIDER:TYPE. We
+ * split it here.
+ */
+ colon = strchr(field_name, ':');
+ if (!colon) {
+ ERR("Invalid app-specific context field name: missing colon in `%s`.",
+ field_name);
+ goto error;
+ }
+
+ type_name = colon + 1;
+ if (*type_name == '\0') {
+ ERR("Invalid app-specific context field name: missing type name after colon in `%s`.",
+ field_name);
+ goto error;
+ }
+
+ provider_name = strndup(field_name, colon - field_name);
+ if (!provider_name) {
+ PERROR("Failed to allocate field name string");
+ goto error;
+ }
+
+ event_expr = lttng_event_expr_app_specific_context_field_create(
+ provider_name, type_name);
+ if (!event_expr) {
+ ERR("Failed to create app-specific context field event expression: provider name = `%s`, type name = `%s`",
+ provider_name, type_name);
+ goto error;
+ }
+
+ break;
+ }
+ default:
+ ERR("%s: unexpected load expr type %d.", __func__,
+ load_expr_op->type);
+ abort();
+ }
+
+ load_expr_op = load_expr_op->next;
+
+ /* There may be a single array index after that. */
+ if (load_expr_op->type == IR_LOAD_EXPRESSION_GET_INDEX) {
+ struct lttng_event_expr *index_event_expr;
+ const uint64_t index = load_expr_op->u.index;
+
+ index_event_expr = lttng_event_expr_array_field_element_create(event_expr, index);
+ if (!index_event_expr) {
+ ERR("Failed to create array field element event expression.");
+ goto error;
+ }
+
+ event_expr = index_event_expr;
+ load_expr_op = load_expr_op->next;
+ }
+
+ switch (load_expr_op->type) {
+ case IR_LOAD_EXPRESSION_LOAD_FIELD:
+ /*
+ * This is what we expect, IR_LOAD_EXPRESSION_LOAD_FIELD is
+ * always found at the end of the chain.
+ */
+ break;
+ case IR_LOAD_EXPRESSION_GET_SYMBOL:
+ ERR("While parsing expression `%s`: Capturing subfields is not supported.",
+ capture_str);
+ goto error;
+
+ default:
+ ERR("%s: unexpected load expression operator %s.", __func__,
+ ir_load_expression_type_str(load_expr_op->type));
+ abort();
+ }
+
+ goto end;
+
+error:
+ lttng_event_expr_destroy(event_expr);
+ event_expr = NULL;
+
+end:
+ free(provider_name);
+
+ return event_expr;
+}
+
+static
+struct lttng_event_expr *ir_op_load_to_event_expr(
+ const struct ir_op *ir, const char *capture_str)
+{
+ struct lttng_event_expr *event_expr = NULL;
+
+ assert(ir->op == IR_OP_LOAD);
+
+ switch (ir->data_type) {
+ case IR_DATA_EXPRESSION:
+ {
+ const struct ir_load_expression *ir_load_expr =
+ ir->u.load.u.expression;
+
+ event_expr = ir_op_load_expr_to_event_expr(
+ ir_load_expr, capture_str);
+ break;
+ }
+ default:
+ ERR("%s: unexpected data type: %s.", __func__,
+ ir_data_type_str(ir->data_type));
+ abort();
+ }
+
+ return event_expr;
+}
+
+static
+const char *ir_operator_type_human_str(enum ir_op_type op)
+{
+ const char *name;
+
+ switch (op) {
+ case IR_OP_BINARY:
+ name = "Binary";
+ break;
+ case IR_OP_UNARY:
+ name = "Unary";
+ break;
+ case IR_OP_LOGICAL:
+ name = "Logical";
+ break;
+ default:
+ abort();
+ }
+
+ return name;
+}
+
+static
+struct lttng_event_expr *ir_op_root_to_event_expr(const struct ir_op *ir,
+ const char *capture_str)
+{
+ struct lttng_event_expr *event_expr = NULL;
+
+ assert(ir->op == IR_OP_ROOT);
+ ir = ir->u.root.child;
+
+ switch (ir->op) {
+ case IR_OP_LOAD:
+ event_expr = ir_op_load_to_event_expr(ir, capture_str);
+ break;
+ case IR_OP_BINARY:
+ case IR_OP_UNARY:
+ case IR_OP_LOGICAL:
+ ERR("While parsing expression `%s`: %s operators are not allowed in capture expressions.",
+ capture_str,
+ ir_operator_type_human_str(ir->op));
+ break;
+ default:
+ ERR("%s: unexpected IR op type: %s.", __func__,
+ ir_op_type_str(ir->op));
+ abort();
+ }
+
+ return event_expr;
+}
+
+static
+void destroy_event_expr(void *ptr)
+{
+ lttng_event_expr_destroy(ptr);
+}
+
+struct parse_event_rule_res {
+ /* Owned by this. */
+ struct lttng_event_rule *er;
+
+ /* Array of `struct lttng_event_expr *` */
+ struct lttng_dynamic_pointer_array capture_descriptors;
+};
+
+static
+struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)