#include #include #include #include #include #include "func.h" #include "ir.h" #include "node.h" #include "ply.h" #include "sym.h" #include "type.h" struct providers { struct provider **ps; size_t len; } providers; #define providers_foreach(_ps, _p) \ for((_p) = (_ps)->ps; (_p) < &(_ps)->ps[(_ps)->len]; (_p)++) struct provider *provider_get(const char *name) { struct provider **p; providers_foreach(&providers, p) { if (strstr((*p)->name, name) == (*p)->name) return *p; } return NULL; } void provider_register(struct provider *p) { assert(p); assert(p->probe); assert(p->sym_alloc); providers.ps = realloc(providers.ps, ++providers.len * sizeof(*providers.ps)); providers.ps[providers.len - 1] = p; } struct pass { int (*run)(struct pass *, struct ctx *); nwalk_fn pre; nwalk_fn post; }; struct symtab syms = { .syms = NULL, .len = 0 }; /* symtab_t locals = { .sym = NULL, .len = 0 }; */ struct ctx *ctx_get(void) { struct ctx *ctx; struct prog *prog; ctx = calloc(1, sizeof(*ctx)); ctx->globals = calloc(1, sizeof(*ctx->globals)); ctx->progs = calloc(3, sizeof(*ctx->progs)); /* PROBE0 */ prog = calloc(1, sizeof(*prog)); prog->locals = calloc(1, sizeof(*prog->locals)); prog->globals = ctx->globals; prog->probe = "k:SyS_read"; /* { * # us = pid(); * t[0, pid()] = time(); * reads[pid()] = quantize(arg2); * } */ prog->ast = node_expr(":block", /* node_expr("=", */ /* node_ident("us"), */ /* node_expr("pid", NULL), */ /* NULL), */ node_expr("=", node_expr("{}", node_ident("t"), node_expr("pid", NULL), node_num("0x10000000"), NULL), node_expr("time", NULL), NULL), /* node_expr("=", */ /* node_expr("{}", */ /* node_ident("reads"), */ /* node_expr("pid", NULL), */ /* NULL), */ /* node_expr("quantize", node_ident("arg2"), NULL), */ /* NULL), */ NULL); prog->provider = provider_get("k"); prog->provider->probe(prog); prog->ir = ir_new(); ctx->progs[0] = prog; /* PROBE1 */ /* prog = calloc(1, sizeof(*prog)); */ /* prog->locals = calloc(1, sizeof(*prog->locals)); */ /* prog->globals = ctx->globals; */ /* /\* TODO: k -> kret *\/ */ /* prog->probe = "k:SyS_read2"; */ /* /\* { times[pid()] = quantize(time() - t[0, pid()]) } *\/ */ /* prog->ast = */ /* node_expr("=", */ /* node_expr("{}", */ /* node_ident("times"), */ /* node_expr("pid", NULL), */ /* NULL), */ /* node_expr("quantize", */ /* node_expr("-", */ /* node_expr("time", NULL), */ /* node_expr("{}", */ /* node_ident("t"), */ /* node_num("0"), */ /* node_expr("time", NULL), */ /* node_expr("pid", NULL), */ /* NULL), */ /* NULL), */ /* NULL), */ /* NULL); */ /* prog->provider = provider_get("k"); */ /* prog->provider->probe(prog); */ /* prog->ir = ir_new(); */ /* ctx->progs[1] = prog; */ return ctx; } int pass_sym_alloc(struct node *n, void *_prog) { struct prog *prog = _prog; struct provider *global = provider_get(":"); int err = 0; if (n->sym) return 0; switch (n->ntype) { case N_EXPR: case N_IDENT: err = prog->provider->sym_alloc(prog, n); if (!err || (err != -ENOENT)) break; err = global->sym_alloc(prog, n); break; case N_NUM: case N_STRING: err = global->sym_alloc(prog, n); } if (err) { if ((err == -ENOENT)) _e("%#N: unknown symbol %N.\n", n, n); } return err; } int pass_type_infer(struct node *n, void *_prog) { struct prog *prog = _prog; if (n->sym->func->type_infer) return n->sym->func->type_infer(n->sym->func, n); /* TODO recurse as long as we're infering new types */ return 0; } int pass_rewrite(struct node *n, void *_prog) { struct prog *prog = _prog; if (n->sym->func->rewrite) return n->sym->func->rewrite(n->sym->func, n, prog); return 0; } int pass_ir_pre(struct node *n, void *_prog) { struct prog *prog = _prog; if (n->sym->func->ir_pre) return n->sym->func->ir_pre(n->sym->func, n, prog); return 0; } int pass_ir_post(struct node *n, void *_prog) { struct prog *prog = _prog; if (n->sym->func->ir_post) return n->sym->func->ir_post(n->sym->func, n, prog); return 0; } int run_ir(struct pass *pass, struct ctx *ctx) { struct prog **progp; int err; for (progp = ctx->progs; *progp; progp++) { struct prog *prog = *progp; err = prog->provider->ir_pre ? prog->provider->ir_pre(prog) : 0; if (err) return err; err = node_walk(prog->ast, pass_ir_pre, pass_ir_post, prog); if (err) return err; err = prog->provider->ir_post ? prog->provider->ir_post(prog) : 0; if (err) return err; ir_emit_insn(prog->ir, EXIT, 0, 0); } return 0; } int run_walk(struct pass *pass, struct ctx *ctx) { struct prog **prog; int err; for (prog = ctx->progs; *prog; prog++) { err = node_walk((*prog)->ast, pass->pre, pass->post, *prog); if (err) return err; } return 0; } struct pass passes[] = { { .run = run_walk, .post = pass_sym_alloc }, { .run = run_walk, .post = pass_type_infer }, { .run = run_walk, .post = pass_rewrite }, { .run = run_walk, .post = pass_sym_alloc }, { .run = run_walk, .post = pass_type_infer }, { .run = run_ir }, /* program flattened to vBPF instructions, now rewrite it to * fit into the actual hw/vm. */ /* BPF program ready */ { NULL } }; int main(void) { struct ctx *ctx = ctx_get(); struct prog **prog; struct pass *pass; int err = 0; for (pass = passes; pass->run; pass++) { err = pass->run(pass, ctx); if (err) break; } for (prog = ctx->progs; *prog; prog++) { printf("\n\e[34m%s\e[0m\n", (*prog)->probe); ast_fprint(stdout, (*prog)->ast); printf("\n-- locals\n"); symtab_dump((*prog)->locals, stdout); printf("-- ir\n"); ir_dump((*prog)->ir, stdout); } printf("\n\n-- globals\n"); symtab_dump(ctx->globals, stdout); /* printf("\n\n-- decls\n"); */ /* type_dump_decls(stdout); */ if (err) printf("ERR: %d\n", err); return err; }