From 7aa3827d2b038d7f8ad1c422b396ce9c92719d0b Mon Sep 17 00:00:00 2001 From: mpi Date: Wed, 21 Apr 2021 10:28:54 +0000 Subject: [PATCH] Support for local (scratch) variables: "$var_name". Every rule gets its own list of (local) variables. --- usr.sbin/btrace/TODO | 1 - usr.sbin/btrace/bt_parse.y | 192 +++++++++++++++++++++++++----------- usr.sbin/btrace/bt_parser.h | 8 +- 3 files changed, 135 insertions(+), 66 deletions(-) diff --git a/usr.sbin/btrace/TODO b/usr.sbin/btrace/TODO index 1e1ea83a090..c38454e7afe 100644 --- a/usr.sbin/btrace/TODO +++ b/usr.sbin/btrace/TODO @@ -5,7 +5,6 @@ Missing feature: Missing language features: - if/else -- scratch variable ($name) - `args', tracepoint arguments support (requires kernel work) - str(args->buf, args->count) - 'argv' diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y index 0fbf19ba6c6..9b375a7c2cf 100644 --- a/usr.sbin/btrace/bt_parse.y +++ b/usr.sbin/btrace/bt_parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: bt_parse.y,v 1.25 2021/04/21 10:26:18 mpi Exp $ */ +/* $OpenBSD: bt_parse.y,v 1.26 2021/04/21 10:28:54 mpi Exp $ */ /* * Copyright (c) 2019-2021 Martin Pieuchot @@ -53,6 +53,9 @@ int g_nprobes; /* List of global variables, including maps. */ SLIST_HEAD(, bt_var) g_variables; +/* List of local variables, cleaned for each new rule. */ +SLIST_HEAD(, bt_var) l_variables; + struct bt_rule *br_new(struct bt_probe *, struct bt_filter *, struct bt_stmt *, enum bt_rtype); struct bt_filter *bf_new(enum bt_argtype, enum bt_filtervar, int); @@ -61,12 +64,17 @@ struct bt_arg *ba_append(struct bt_arg *, struct bt_arg *); struct bt_stmt *bs_new(enum bt_action, struct bt_arg *, struct bt_var *); struct bt_stmt *bs_append(struct bt_stmt *, struct bt_stmt *); -struct bt_var *bv_find(const char *); -struct bt_arg *bv_get(const char *); -struct bt_stmt *bv_set(const char *, struct bt_arg *); +struct bt_var *bg_lookup(const char *); +struct bt_stmt *bg_store(const char *, struct bt_arg *); +struct bt_arg *bg_find(const char *); +struct bt_var *bg_get(const char *); + +struct bt_var *bl_lookup(const char *); +struct bt_stmt *bl_store(const char *, struct bt_arg *); +struct bt_arg *bl_find(const char *); -struct bt_arg *bm_get(const char *, struct bt_arg *); -struct bt_stmt *bm_set(const char *, struct bt_arg *, struct bt_arg *); +struct bt_arg *bm_find(const char *, struct bt_arg *); +struct bt_stmt *bm_insert(const char *, struct bt_arg *, struct bt_arg *); struct bt_stmt *bm_op(enum bt_action, struct bt_arg *, struct bt_arg *); struct bt_stmt *bh_inc(const char *, struct bt_arg *, struct bt_arg *); @@ -110,15 +118,15 @@ static int pflag; %token STRING CSTRING %token NUMBER -%type gvar -%type value +%type gvar lvar +%type staticval %type fval testop binop builtin %type BUILTIN F_DELETE F_PRINT FUNC0 FUNC1 FUNCN OP1 OP4 %type MOP0 MOP1 -%type probe probeval +%type probe probename %type predicate %type action stmt stmtlist -%type expr vargs map mexpr printargs term variable +%type expr vargs mentry mexpr printargs term globalvar variable %type beginend %left '|' @@ -141,9 +149,9 @@ beginend : BEGIN { $$ = B_RT_BEGIN; } | END { $$ = B_RT_END; } ; -probe : { pflag = 1; } probeval { $$ = $2; pflag = 0; } +probe : { pflag = 1; } probename { $$ = $2; pflag = 0; } -probeval : STRING ':' STRING ':' STRING { $$ = bp_new($1, $3, $5, 0); } +probename : STRING ':' STRING ':' STRING { $$ = bp_new($1, $3, $5, 0); } | STRING ':' HZ ':' NUMBER { $$ = bp_new($1, "hz", NULL, $5); } ; @@ -169,18 +177,31 @@ binop : testop | '|' { $$ = B_AT_OP_BOR; } ; -value : NUMBER +staticval : NUMBER | '$' NUMBER { $$ = get_varg($2); } ; +gvar : '@' STRING { $$ = $2; } + | '@' { $$ = UNNAMED_MAP; } + +lvar : '$' STRING { $$ = $2; } + + predicate : /* empty */ { $$ = NULL; } - | '/' fval testop value '/' { $$ = bf_new($3, $2, $4); } - | '/' value testop fval '/' { $$ = bf_new($3, $4, $2); } + | '/' fval testop staticval '/' { $$ = bf_new($3, $2, $4); } + | '/' staticval testop fval '/' { $$ = bf_new($3, $4, $2); } | '/' variable '/' { $$ = bc_new($2); } ; -variable : gvar { $$ = bv_get($1); } - | map +mentry : gvar '[' vargs ']' { $$ = bm_find($1, $3); } + ; + +globalvar : gvar { $$ = bg_find($1); } + | mentry + ; + +variable : globalvar + | lvar { $$ = bl_find($1); } ; builtin : PID { $$ = B_AT_BI_PID; } @@ -199,35 +220,31 @@ expr : CSTRING { $$ = ba_new($1, B_AT_STR); } term : '(' term ')' { $$ = $2; } | term binop term { $$ = ba_op($2, $1, $3); } - | value { $$ = ba_new($1, B_AT_LONG); } + | staticval { $$ = ba_new($1, B_AT_LONG); } | builtin { $$ = ba_new(NULL, $1); } | variable -gvar : '@' STRING { $$ = $2; } - | '@' { $$ = UNNAMED_MAP; } - -map : gvar '[' vargs ']' { $$ = bm_get($1, $3); } - ; vargs : expr | vargs ',' expr { $$ = ba_append($1, $3); } ; printargs : term - | gvar ',' expr { $$ = ba_append(bv_get($1), $3); } + | gvar ',' expr { $$ = ba_append(bg_find($1), $3); } ; NL : /* empty */ | '\n' ; stmt : ';' NL { $$ = NULL; } - | gvar '=' expr { $$ = bv_set($1, $3); } - | gvar '[' vargs ']' '=' mexpr { $$ = bm_set($1, $3, $6); } + | gvar '=' expr { $$ = bg_store($1, $3); } + | lvar '=' expr { $$ = bl_store($1, $3); } + | gvar '[' vargs ']' '=' mexpr { $$ = bm_insert($1, $3, $6); } | FUNCN '(' vargs ')' { $$ = bs_new($1, $3, NULL); } | FUNC1 '(' expr ')' { $$ = bs_new($1, $3, NULL); } | FUNC0 '(' ')' { $$ = bs_new($1, NULL, NULL); } - | F_DELETE '(' map ')' { $$ = bm_op($1, $3, NULL); } + | F_DELETE '(' mentry ')' { $$ = bm_op($1, $3, NULL); } | F_PRINT '(' printargs ')' { $$ = bs_new($1, $3, NULL); } | gvar '=' OP1 '(' expr ')' { $$ = bh_inc($1, $5, NULL); } | gvar '=' OP4 '(' expr ',' vargs ')' {$$ = bh_inc($1, $5, $7);} @@ -268,6 +285,9 @@ br_new(struct bt_probe *probe, struct bt_filter *filter, struct bt_stmt *head, SLIST_FIRST(&br->br_action) = head; br->br_type = rtype; + SLIST_FIRST(&br->br_variables) = SLIST_FIRST(&l_variables); + SLIST_INIT(&l_variables); + if (rtype == B_RT_PROBE) { g_nprobes++; TAILQ_INSERT_TAIL(&g_rules, br, br_next); @@ -421,9 +441,23 @@ bv_name(struct bt_var *bv) return bv->bv_name; } +/* Allocate a variable. */ +struct bt_var * +bv_new(const char *vname) +{ + struct bt_var *bv; + + bv = calloc(1, sizeof(*bv)); + if (bv == NULL) + err(1, "bt_var: calloc"); + bv->bv_name = vname; + + return bv; +} + /* Return the global variable corresponding to `vname'. */ struct bt_var * -bv_find(const char *vname) +bg_lookup(const char *vname) { struct bt_var *bv; @@ -435,46 +469,85 @@ bv_find(const char *vname) return bv; } -/* Find or allocate a global variable. */ +/* Find or allocate a global variable corresponding to `vname' */ struct bt_var * -bv_new(const char *vname) +bg_get(const char *vname) { struct bt_var *bv; - bv = calloc(1, sizeof(*bv)); - if (bv == NULL) - err(1, "bt_var: calloc"); - bv->bv_name = vname; - SLIST_INSERT_HEAD(&g_variables, bv, bv_next); + bv = bg_lookup(vname); + if (bv == NULL) { + bv = bv_new(vname); + SLIST_INSERT_HEAD(&g_variables, bv, bv_next); + } return bv; } -/* Create a 'variable store' statement to assign a value to a variable. */ -struct bt_stmt * -bv_set(const char *vname, struct bt_arg *vval) +/* Create an "argument" that points to an existing untyped variable. */ +struct bt_arg * +bg_find(const char *vname) { struct bt_var *bv; - bv = bv_find(vname); + bv = bg_lookup(vname); if (bv == NULL) - bv = bv_new(vname); - return bs_new(B_AC_STORE, vval, bv); + yyerror("variable '%s' accessed before being set", vname); + + return ba_new(bv, B_AT_VAR); +} + +/* Create a 'store' statement to assign a value to a global variable. */ +struct bt_stmt * +bg_store(const char *vname, struct bt_arg *vval) +{ + return bs_new(B_AC_STORE, vval, bg_get(vname)); } -/* Create an argument that points to a variable. */ +/* Return the local variable corresponding to `vname'. */ +struct bt_var * +bl_lookup(const char *vname) +{ + struct bt_var *bv; + + SLIST_FOREACH(bv, &l_variables, bv_next) { + if (strcmp(vname, bv->bv_name) == 0) + break; + } + + return bv; +} + +/* Find or create a local variable corresponding to `vname' */ struct bt_arg * -bv_get(const char *vname) +bl_find(const char *vname) { struct bt_var *bv; - bv = bv_find(vname); - if (bv == NULL) - yyerror("variable '%s' accessed before being set", vname); + bv = bl_lookup(vname); + if (bv == NULL) { + bv = bv_new(vname); + SLIST_INSERT_HEAD(&l_variables, bv, bv_next); + } return ba_new(bv, B_AT_VAR); } +/* Create a 'store' statement to assign a value to a local variable. */ +struct bt_stmt * +bl_store(const char *vname, struct bt_arg *vval) +{ + struct bt_var *bv; + + bv = bl_lookup(vname); + if (bv == NULL) { + bv = bv_new(vname); + SLIST_INSERT_HEAD(&l_variables, bv, bv_next); + } + + return bs_new(B_AC_STORE, vval, bv); +} + struct bt_stmt * bm_op(enum bt_action mact, struct bt_arg *ba, struct bt_arg *mval) { @@ -483,27 +556,28 @@ bm_op(enum bt_action mact, struct bt_arg *ba, struct bt_arg *mval) /* Create a 'map store' statement to assign a value to a map entry. */ struct bt_stmt * -bm_set(const char *mname, struct bt_arg *mkey, struct bt_arg *mval) +bm_insert(const char *mname, struct bt_arg *mkey, struct bt_arg *mval) { struct bt_arg *ba; - struct bt_var *bv; - bv = bv_find(mname); - if (bv == NULL) - bv = bv_new(mname); - ba = ba_new(bv, B_AT_MAP); + ba = ba_new(bg_get(mname), B_AT_MAP); ba->ba_key = mkey; + return bs_new(B_AC_INSERT, ba, (struct bt_var *)mval); } /* Create an argument that points to a variable and attach a key to it. */ struct bt_arg * -bm_get(const char *mname, struct bt_arg *mkey) +bm_find(const char *vname, struct bt_arg *mkey) { + struct bt_var *bv; struct bt_arg *ba; - ba = bv_get(mname); - ba->ba_type = B_AT_MAP; + bv = bg_lookup(vname); + if (bv == NULL) + yyerror("variable '%s' accessed before being set", vname); + + ba = ba_new(bv, B_AT_MAP); ba->ba_key = mkey; return ba; } @@ -517,7 +591,6 @@ struct bt_stmt * bh_inc(const char *hname, struct bt_arg *hval, struct bt_arg *hrange) { struct bt_arg *ba; - struct bt_var *bv; if (hrange == NULL) { /* Power-of-2 histogram */ @@ -554,10 +627,7 @@ bh_inc(const char *hname, struct bt_arg *hval, struct bt_arg *hrange) yyerror("%d missing arguments", 3 - count); } - bv = bv_find(hname); - if (bv == NULL) - bv = bv_new(hname); - ba = ba_new(bv, B_AT_HIST); + ba = ba_new(bg_get(hname), B_AT_HIST); ba->ba_key = hrange; return bs_new(B_AC_BUCKETIZE, ba, (struct bt_var *)hval); } @@ -892,5 +962,7 @@ btparse(const char *str, size_t len, const char *filename, int debug) yyparse(); + assert(SLIST_EMPTY(&l_variables)); + return perrors; } diff --git a/usr.sbin/btrace/bt_parser.h b/usr.sbin/btrace/bt_parser.h index 5db6304d589..3181ab78926 100644 --- a/usr.sbin/btrace/bt_parser.h +++ b/usr.sbin/btrace/bt_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bt_parser.h,v 1.14 2021/04/21 10:26:18 mpi Exp $ */ +/* $OpenBSD: bt_parser.h,v 1.15 2021/04/21 10:28:54 mpi Exp $ */ /* * Copyright (c) 2019-2021 Martin Pieuchot @@ -82,6 +82,7 @@ struct bt_rule { struct bt_probe *br_probe; struct bt_filter *br_filter; SLIST_HEAD(, bt_stmt) br_action; + SLIST_HEAD(, bt_var) br_variables; /* local variables */ enum bt_rtype { B_RT_BEGIN = 1, @@ -123,7 +124,7 @@ struct bt_arg { enum bt_argtype { B_AT_STR = 1, /* C-style string */ B_AT_LONG, /* Number (integer) */ - B_AT_VAR, /* global variable (@var) */ + B_AT_VAR, /* global/local variable */ B_AT_MAP, /* global map (@map[]) */ B_AT_HIST, /* histogram */ @@ -205,7 +206,4 @@ struct bt_arg *ba_new0(void *, enum bt_argtype); const char *bv_name(struct bt_var *); -void bm_insert(struct bt_var *, struct bt_arg *, - struct bt_arg *); - #endif /* BT_PARSER_H */ -- 2.20.1