static int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node) { int ret; struct unary_op insn; /* Visit child */ ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child); if (ret) return ret; /* Generate end of bytecode instruction */ switch (node->u.unary.type) { case AST_UNARY_UNKNOWN: default: fprintf(stderr, "[error] Unknown unary node type in %s\n", __func__); return -EINVAL; case AST_UNARY_PLUS: /* Nothing to do. */ return 0; case AST_UNARY_MINUS: insn.op = FILTER_OP_UNARY_MINUS; return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn)); case AST_UNARY_NOT: insn.op = FILTER_OP_UNARY_NOT; return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn)); } }
static int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node) { int ret; struct return_op insn; /* Visit child */ ret = recursive_visit_gen_bytecode(ctx, node->u.root.child); if (ret) return ret; /* Generate end of bytecode instruction */ insn.op = FILTER_OP_RETURN; return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn)); }
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; }
int main(int argc, char **argv) { struct parg_state ps; int c; int interactive = 0; char *execute = NULL; int t = 0; int p = 0; parg_init(&ps); while((c = parg_getopt(&ps, argc, argv, "pthie:")) != -1) { switch(c) { case 1: printf("nonoption '%s'\n", ps.optarg); break; case 'i': interactive++; break; case 'e': execute = (char *)ps.optarg; break; case 't': t++; break; case 'p': p++; break; case 'h': printf("usage: stir [-i input]\n"); return EXIT_SUCCESS; default: printf("unknown option: %c", (char)c); } } if (t) { uint8_t memory[32]; uint32_t instructions[] = { bytecode_iconst(32), bytecode_iconst(10), bytecode_pop(0, 4), bytecode_pop(1, 4), bytecode_iadd(0, 1, 2), bytecode_store(2, 0), bytecode_push(2, 4), bytecode_halt(0) }; int ret = cpu_execute(instructions, sizeof(instructions) / sizeof(instructions[0]), memory, sizeof(memory) / sizeof(memory[0]), 0); printf("[%d]\n", ret); int i = 0; for(; i < sizeof(memory) / sizeof(memory[0]); i++) { if ((i % 16) == 0) { printf("\n"); } printf("%02x ", memory[i]); } } printf("\n----------\n"); parser_t parser_val; parser_t *parser = &parser_val; parser_init(parser); if (execute != NULL) { uint32_t* instructions; uint8_t* data; uint32_t i_count; uint32_t d_count; token_t* tokens; int t_count; parser_process(parser, execute, &tokens, &t_count); code_generator_generate(tokens, t_count, &instructions, &i_count, &data, &d_count); printf("ptr %p", instructions); // TODO(sebe): copy over the data to the memory // and structure the program's memory sanely uint8_t memory[32]; d_count = 32; if (!p) { int ret = cpu_execute(instructions, i_count, memory, d_count, 0); printf("[%d]\n", ret); int i = 0; for(; i < d_count; i++) { if ((i % 16) == 0) { printf("\n"); } printf("%02x ", memory[i]); } } } if (interactive) { printf("\n>"); char* line; while ((line = read_stdin())) { if (line != NULL) { token_t* tokens; int t_count; printf("%s", line); parser_process(parser, line, &tokens, &t_count); } printf("\n>"); } } parser_free(parser); return 0; }
/* * A logical op always return a s64 (1 or 0). */ static int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node) { int ret; struct logical_op insn; uint16_t skip_offset_loc; uint16_t target_loc; /* Visit left child */ ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left); if (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_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) { cast_insn.op = FILTER_OP_CAST_TO_S64; } else { cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64; } ret = bytecode_push(&ctx->bytecode, &cast_insn, 1, sizeof(cast_insn)); if (ret) return ret; } switch (node->u.logical.type) { default: fprintf(stderr, "[error] Unknown node type in %s\n", __func__); return -EINVAL; case AST_OP_AND: insn.op = FILTER_OP_AND; break; case AST_OP_OR: insn.op = FILTER_OP_OR; break; } insn.skip_offset = (uint16_t) -1UL; /* Temporary */ ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn), &skip_offset_loc); if (ret) return ret; /* Visit right child */ ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right); if (ret) 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_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) { cast_insn.op = FILTER_OP_CAST_TO_S64; } else { cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64; } ret = bytecode_push(&ctx->bytecode, &cast_insn, 1, sizeof(cast_insn)); if (ret) return ret; } /* We now know where the logical op can skip. */ target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b); ret = bytecode_patch(&ctx->bytecode, &target_loc, /* Offset to jump to */ skip_offset_loc, /* Where to patch */ sizeof(uint16_t)); return ret; }
/* * Binary comparator nesting is disallowed. This allows fitting into * only 2 registers. */ static int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node) { int ret; struct binary_op insn; /* Visit child */ ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left); if (ret) return ret; ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right); if (ret) return ret; switch (node->u.binary.type) { case AST_OP_UNKNOWN: default: fprintf(stderr, "[error] Unknown unary node type in %s\n", __func__); return -EINVAL; case AST_OP_AND: case AST_OP_OR: fprintf(stderr, "[error] Unexpected logical node type in %s\n", __func__); return -EINVAL; case AST_OP_MUL: insn.op = FILTER_OP_MUL; break; case AST_OP_DIV: insn.op = FILTER_OP_DIV; break; case AST_OP_MOD: insn.op = FILTER_OP_MOD; break; case AST_OP_PLUS: insn.op = FILTER_OP_PLUS; break; case AST_OP_MINUS: insn.op = FILTER_OP_MINUS; break; case AST_OP_RSHIFT: insn.op = FILTER_OP_RSHIFT; break; case AST_OP_LSHIFT: insn.op = FILTER_OP_LSHIFT; break; case AST_OP_BIN_AND: insn.op = FILTER_OP_BIN_AND; break; case AST_OP_BIN_OR: insn.op = FILTER_OP_BIN_OR; break; case AST_OP_BIN_XOR: insn.op = FILTER_OP_BIN_XOR; break; case AST_OP_EQ: insn.op = FILTER_OP_EQ; break; case AST_OP_NE: insn.op = FILTER_OP_NE; break; case AST_OP_GT: insn.op = FILTER_OP_GT; break; case AST_OP_LT: insn.op = FILTER_OP_LT; break; case AST_OP_GE: insn.op = FILTER_OP_GE; break; case AST_OP_LE: insn.op = FILTER_OP_LE; break; } return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn)); }
static int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node) { int ret; switch (node->data_type) { case IR_DATA_UNKNOWN: default: fprintf(stderr, "[error] Unknown data type in %s\n", __func__); return -EINVAL; case IR_DATA_STRING: { struct load_op *insn; uint32_t insn_len = sizeof(struct load_op) + strlen(node->u.load.u.string) + 1; insn = calloc(insn_len, 1); if (!insn) return -ENOMEM; insn->op = FILTER_OP_LOAD_STRING; strcpy(insn->data, node->u.load.u.string); ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len); free(insn); return ret; } case IR_DATA_NUMERIC: { struct load_op *insn; uint32_t insn_len = sizeof(struct load_op) + sizeof(struct literal_numeric); insn = calloc(insn_len, 1); if (!insn) return -ENOMEM; insn->op = FILTER_OP_LOAD_S64; memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t)); ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len); free(insn); return ret; } case IR_DATA_FLOAT: { struct load_op *insn; uint32_t insn_len = sizeof(struct load_op) + sizeof(struct literal_double); insn = calloc(insn_len, 1); if (!insn) return -ENOMEM; insn->op = FILTER_OP_LOAD_DOUBLE; memcpy(insn->data, &node->u.load.u.flt, sizeof(double)); ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len); free(insn); return ret; } case IR_DATA_FIELD_REF: /* fall-through */ case IR_DATA_GET_CONTEXT_REF: { struct load_op *insn; uint32_t insn_len = sizeof(struct load_op) + sizeof(struct field_ref); struct field_ref ref_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: insn->op = FILTER_OP_LOAD_FIELD_REF; break; case IR_DATA_GET_CONTEXT_REF: insn->op = FILTER_OP_GET_CONTEXT_REF; break; default: free(insn); return -EINVAL; } ref_offset.offset = (uint16_t) -1U; memcpy(insn->data, &ref_offset, sizeof(ref_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, 1, strlen(node->u.load.u.ref) + 1); free(insn); return ret; } } }