Extends the bytecode with new instructions.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
AST_LINK_UNKNOWN = 0,
AST_LINK_DOT,
AST_LINK_RARROW,
+ AST_LINK_BRACKET,
};
struct filter_node {
*/
struct filter_node *child;
} u;
- /* linked dot/arrow chain */
+ /* prev: linked dot/arrow chain (postfix expression) */
struct filter_node *prev;
+ /* next: linked bracket chain (prefix expression) */
struct filter_node *next;
} expression;
struct {
uint16_t offset;
} LTTNG_PACKED;
+struct field_ref_index {
+ /* Initially, symbol offset. After link, field offset. */
+ uint16_t offset;
+ uint64_t index; /* array index */
+} LTTNG_PACKED;
+
struct literal_numeric {
int64_t v;
} LTTNG_PACKED;
FILTER_OP_EQ_STAR_GLOB_STRING = 77,
FILTER_OP_NE_STAR_GLOB_STRING = 78,
+ /* load field ref with index */
+ FILTER_OP_LOAD_FIELD_REF_INDEX = 79,
+ FILTER_OP_LOAD_FIELD_REF_INDEX_S64 = 80,
+
+ /* get context ref with index */
+ FILTER_OP_GET_CONTEXT_REF_INDEX = 81,
+ FILTER_OP_GET_CONTEXT_REF_INDEX_S64 = 82,
+
NR_FILTER_OPS,
};
IR_DATA_FLOAT,
IR_DATA_FIELD_REF,
IR_DATA_GET_CONTEXT_REF,
+ IR_DATA_FIELD_REF_INDEX,
+ IR_DATA_GET_CONTEXT_REF_INDEX,
};
enum ir_op_type {
int64_t num;
double flt;
char *ref;
+ struct {
+ char *symbol;
+ uint64_t index;
+ } ref_index;
} u;
};
postfix_expression
: primary_expression
{ $$ = $1; }
+ | postfix_expression LSBRAC unary_expression RSBRAC
+ {
+ $$ = $1;
+ $$->u.expression.pre_op = AST_LINK_BRACKET;
+ $$->u.expression.next = $3;
+ }
| postfix_expression DOT IDENTIFIER
{
$$ = make_node(parser_ctx, NODE_EXPRESSION);
insn = calloc(insn_len, 1);
if (!insn)
return -ENOMEM;
- switch(node->data_type) {
+ switch (node->data_type) {
case IR_DATA_FIELD_REF:
insn->op = FILTER_OP_LOAD_FIELD_REF;
break;
free(insn);
return ret;
}
+ case IR_DATA_FIELD_REF_INDEX: /* fall-through */
+ case IR_DATA_GET_CONTEXT_REF_INDEX:
+ {
+ struct load_op *insn;
+ uint32_t insn_len = sizeof(struct load_op)
+ + sizeof(struct field_ref_index);
+ struct field_ref_index ref_index_offset;
+ uint32_t reloc_offset_u32;
+ uint16_t reloc_offset;
+
+ insn = calloc(insn_len, 1);
+ if (!insn)
+ return -ENOMEM;
+ switch (node->data_type) {
+ case IR_DATA_FIELD_REF_INDEX:
+ insn->op = FILTER_OP_LOAD_FIELD_REF_INDEX;
+ break;
+ case IR_DATA_GET_CONTEXT_REF_INDEX:
+ insn->op = FILTER_OP_GET_CONTEXT_REF_INDEX;
+ break;
+ default:
+ free(insn);
+ return -EINVAL;
+ }
+ ref_index_offset.offset = (uint16_t) -1U;
+ ref_index_offset.index = node->u.load.u.ref_index.index;
+ memcpy(insn->data, &ref_index_offset, sizeof(ref_index_offset));
+ /* reloc_offset points to struct load_op */
+ reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+ if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+ free(insn);
+ return -EINVAL;
+ }
+ reloc_offset = (uint16_t) reloc_offset_u32;
+ ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+ if (ret) {
+ free(insn);
+ return ret;
+ }
+ /* append reloc */
+ ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+ 1, sizeof(reloc_offset));
+ if (ret) {
+ free(insn);
+ return ret;
+ }
+ ret = bytecode_push(&ctx->bytecode_reloc, node->u.load.u.ref_index.symbol,
+ 1, strlen(node->u.load.u.ref_index.symbol) + 1);
+ free(insn);
+ return ret;
+ }
}
}
return ret;
/* Cast to s64 if float or field ref */
if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
- || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF)
+ || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+ || node->u.binary.left->data_type == IR_DATA_FIELD_REF_INDEX
+ || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF_INDEX)
|| node->u.binary.left->data_type == IR_DATA_FLOAT) {
struct cast_op cast_insn;
if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
- || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF) {
+ || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+ || node->u.binary.left->data_type == IR_DATA_FIELD_REF_INDEX
+ || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) {
cast_insn.op = FILTER_OP_CAST_TO_S64;
} else {
cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
return ret;
/* Cast to s64 if float or field ref */
if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
- || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF)
+ || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+ || node->u.binary.right->data_type == IR_DATA_FIELD_REF_INDEX
+ || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF_INDEX)
|| node->u.binary.right->data_type == IR_DATA_FLOAT) {
struct cast_op cast_insn;
if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
- || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF) {
+ || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+ || node->u.binary.right->data_type == IR_DATA_FIELD_REF_INDEX
+ || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) {
cast_insn.op = FILTER_OP_CAST_TO_S64;
} else {
cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
}
static
-struct ir_op *make_op_load_field_ref(char *string, enum ir_side side)
+struct ir_op *make_op_load_field_ref(char *string,
+ enum ir_side side)
{
struct ir_op *op;
op->side = side;
op->u.load.u.ref = strdup(string);
if (!op->u.load.u.ref) {
- free(op);
+ goto error;
+ }
+ return op;
+
+error:
+ free(op);
+ return NULL;
+}
+
+static
+struct ir_op *make_op_load_field_ref_index(char *string,
+ struct filter_node *next,
+ enum ir_side side)
+{
+ struct ir_op *op;
+
+ op = calloc(sizeof(struct ir_op), 1);
+ if (!op)
return NULL;
+ op->op = IR_OP_LOAD;
+ op->data_type = IR_DATA_FIELD_REF_INDEX;
+ op->signedness = IR_SIGN_DYN;
+ op->side = side;
+ op->u.load.u.ref_index.symbol = strdup(string);
+ if (!op->u.load.u.ref_index.symbol) {
+ goto error;
+ }
+ /* Only positive integer literals accepted as index. */
+ if (next->type == NODE_UNARY_OP) {
+ fprintf(stderr, "[error] Unexpected unary operator as index\n");
+ goto error;
+ }
+ if (next->type != NODE_EXPRESSION) {
+ fprintf(stderr, "[error] Expecting expression as index\n");
+ goto error;
+ }
+ if (next->u.expression.type != AST_EXP_CONSTANT) {
+ fprintf(stderr, "[error] Expecting constant index\n");
+ goto error;
+ }
+ if (next->u.expression.u.constant < 0) {
+ fprintf(stderr, "[error] Expecting positive constant index\n");
+ goto error;
}
+ op->u.load.u.ref_index.index = next->u.expression.u.constant;
return op;
+
+error:
+ free(op);
+ return NULL;
}
static
-struct ir_op *make_op_load_get_context_ref(char *string, enum ir_side side)
+struct ir_op *make_op_load_get_context_ref(char *string,
+ enum ir_side side)
{
struct ir_op *op;
op->side = side;
op->u.load.u.ref = strdup(string);
if (!op->u.load.u.ref) {
- free(op);
+ goto error;
+ }
+ return op;
+
+error:
+ free(op);
+ return NULL;
+}
+
+static
+struct ir_op *make_op_load_get_context_ref_index(char *string,
+ struct filter_node *next,
+ enum ir_side side)
+{
+ struct ir_op *op;
+
+ op = calloc(sizeof(struct ir_op), 1);
+ if (!op)
return NULL;
+ op->op = IR_OP_LOAD;
+ op->data_type = IR_DATA_GET_CONTEXT_REF_INDEX;
+ op->signedness = IR_SIGN_DYN;
+ op->side = side;
+ op->u.load.u.ref_index.symbol = strdup(string);
+ if (!op->u.load.u.ref_index.symbol) {
+ goto error;
+ }
+ /* Only positive integer literals accepted as offset. */
+ if (next->type == NODE_UNARY_OP) {
+ fprintf(stderr, "[error] Unexpected unary operator as index\n");
+ goto error;
+ }
+ if (next->type != NODE_EXPRESSION) {
+ fprintf(stderr, "[error] Expecting expression as index\n");
+ goto error;
}
+ if (next->u.expression.type != AST_EXP_CONSTANT) {
+ fprintf(stderr, "[error] Expecting constant index\n");
+ goto error;
+ }
+ if (next->u.expression.u.constant < 0) {
+ fprintf(stderr, "[error] Expecting positive constant index\n");
+ goto error;
+ }
+ op->u.load.u.ref_index.index = next->u.expression.u.constant;
return op;
+
+error:
+ free(op);
+ return NULL;
}
static
case IR_DATA_GET_CONTEXT_REF:
free(op->u.load.u.ref);
break;
+ case IR_DATA_FIELD_REF_INDEX: /* fall-through */
+ case IR_DATA_GET_CONTEXT_REF_INDEX:
+ free(op->u.load.u.ref_index.symbol);
+ break;
default:
break;
}
return make_op_load_float(node->u.expression.u.float_constant,
side);
case AST_EXP_IDENTIFIER:
- if (node->u.expression.pre_op != AST_LINK_UNKNOWN) {
+ switch (node->u.expression.pre_op) {
+ case AST_LINK_UNKNOWN:
+ return make_op_load_field_ref(node->u.expression.u.identifier,
+ side);
+ case AST_LINK_BRACKET:
+ return make_op_load_field_ref_index(node->u.expression.u.identifier,
+ node->u.expression.next,
+ side);
+ default:
fprintf(stderr, "[error] %s: dotted and dereferenced identifiers not supported\n", __func__);
return NULL;
}
- return make_op_load_field_ref(node->u.expression.u.identifier,
- side);
case AST_EXP_GLOBAL_IDENTIFIER:
{
const char *name;
fprintf(stderr, "[error] %s: Expecting a context name, e.g. \'$ctx.name\'.\n", __func__);
return NULL;
}
- return make_op_load_get_context_ref(node->u.expression.u.identifier,
+ switch (node->u.expression.pre_op) {
+ case AST_LINK_UNKNOWN:
+ return make_op_load_get_context_ref(node->u.expression.u.identifier,
side);
+ case AST_LINK_BRACKET:
+ return make_op_load_get_context_ref_index(node->u.expression.u.identifier,
+ node->u.expression.next,
+ side);
+ default:
+ fprintf(stderr, "[error] %s: dotted and dereferenced identifiers not supported\n", __func__);
+ return NULL;
+ }
+
}
case AST_EXP_NESTED:
return generate_ir_recursive(ctx, node->u.expression.u.child,
int recursive_visit_print_expression(struct filter_node *node,
FILE *stream, int indent)
{
+ struct filter_node *iter_node;
+
if (!node) {
fprintf(stderr, "[error] %s: NULL child\n", __func__);
return -EINVAL;
node->u.expression.type == AST_EXP_IDENTIFIER ?
"identifier" : "global_identifier",
node->u.expression.u.identifier);
- while (node->u.expression.next) {
+ iter_node = node->u.expression.next;
+ while (iter_node) {
print_tabs(stream, indent);
- fprintf(stream, "<link type=\"");
- switch (node->u.expression.pre_op) {
- case AST_LINK_UNKNOWN:
- default:
- fprintf(stderr, "[error] %s: unknown link\n", __func__);
- return -EINVAL;
- case AST_LINK_DOT:
- fprintf(stream, ".");
- break;
- case AST_LINK_RARROW:
- fprintf(stream, "->");
- break;
- }
- fprintf(stream, "\"/>\n");
-
- node = node->u.expression.next;
- if (node->type != NODE_EXPRESSION ||
- node->u.expression.type != AST_EXP_IDENTIFIER) {
- fprintf(stderr, "[error] %s: expecting identifier before link\n", __func__);
+ fprintf(stream, "<bracket>\n");
+ if (recursive_visit_print_expression(iter_node,
+ stream, indent + 1)) {
return -EINVAL;
}
-
print_tabs(stream, indent);
- fprintf(stream, "<identifier value=\"%s\"/>\n",
- node->u.expression.u.identifier);
+ fprintf(stream, "</bracket>\n");
+ iter_node = iter_node->u.expression.next;
+
}
break;
case AST_EXP_NESTED: