Support for local (scratch) variables: "$var_name".
authormpi <mpi@openbsd.org>
Wed, 21 Apr 2021 10:28:54 +0000 (10:28 +0000)
committermpi <mpi@openbsd.org>
Wed, 21 Apr 2021 10:28:54 +0000 (10:28 +0000)
Every rule gets its own list of (local) variables.

usr.sbin/btrace/TODO
usr.sbin/btrace/bt_parse.y
usr.sbin/btrace/bt_parser.h

index 1e1ea83..c38454e 100644 (file)
@@ -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'
index 0fbf19b..9b375a7 100644 (file)
@@ -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 <mpi@openbsd.org>
@@ -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 <v.string>      STRING CSTRING
 %token <v.number>      NUMBER
 
-%type  <v.string>      gvar
-%type  <v.number>      value
+%type  <v.string>      gvar lvar
+%type  <v.number>      staticval
 %type  <v.i>           fval testop binop builtin
 %type  <v.i>           BUILTIN F_DELETE F_PRINT FUNC0 FUNC1 FUNCN OP1 OP4
 %type  <v.i>           MOP0 MOP1
-%type  <v.probe>       probe probeval
+%type  <v.probe>       probe probename
 %type  <v.filter>      predicate
 %type  <v.stmt>        action stmt stmtlist
-%type  <v.arg>         expr vargs map mexpr printargs term variable
+%type  <v.arg>         expr vargs mentry mexpr printargs term globalvar variable
 %type  <v.rtype>       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;
 }
index 5db6304..3181ab7 100644 (file)
@@ -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 <mpi@openbsd.org>
@@ -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 */