-/* $OpenBSD: bt_parse.y,v 1.52 2023/09/02 19:28:46 dv Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.53 2023/09/11 19:01:26 mpi Exp $ */
/*
- * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019-2023 Martin Pieuchot <mpi@openbsd.org>
* Copyright (c) 2019 Tobias Heider <tobhe@openbsd.org>
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
*
struct bt_arg *bg_find(const char *);
struct bt_var *bg_get(const char *);
+struct bt_arg *bi_find(struct bt_arg *, unsigned long);
+
struct bt_var *bl_lookup(const char *);
struct bt_stmt *bl_store(const char *, struct bt_arg *);
struct bt_arg *bl_find(const char *);
variable: lvar { $$ = bl_find($1); }
| gvar { $$ = bg_find($1); }
+ | variable '.' NUMBER { $$ = bi_find($1, $3); }
;
factor : '(' expr ')' { $$ = $2; }
+ | '(' vargs ',' expr ')'{ $$ = ba_new(ba_append($2, $4), B_AT_TUPLE); }
| NUMBER { $$ = ba_new($1, B_AT_LONG); }
| BUILTIN { $$ = ba_new(NULL, $1); }
| CSTRING { $$ = ba_new($1, B_AT_STR); }
/*
* Link two arguments together, to build an argument list used in
- * function calls.
+ * operators, tuples and function calls.
*/
struct bt_arg *
ba_append(struct bt_arg *da0, struct bt_arg *da1)
return bs_new(B_AC_STORE, vval, bv);
}
+/* Create an argument that points to a tuple variable and a given index */
+struct bt_arg *
+bi_find(struct bt_arg *ba, unsigned long index)
+{
+ struct bt_var *bv = ba->ba_value;
+
+ ba = ba_new(bv, B_AT_TMEMBER);
+ ba->ba_key = (void *)index;
+ return ba;
+}
+
struct bt_stmt *
bm_op(enum bt_action mact, struct bt_arg *ba, struct bt_arg *mval)
{
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. */
+/* Create an argument that points to a map variable and attach a key to it. */
struct bt_arg *
bm_find(const char *vname, struct bt_arg *mkey)
{
-/* $OpenBSD: btrace.c,v 1.75 2023/09/02 15:16:12 dv Exp $ */
+/* $OpenBSD: btrace.c,v 1.76 2023/09/11 19:01:26 mpi Exp $ */
/*
- * Copyright (c) 2019 - 2021 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019 - 2023 Martin Pieuchot <mpi@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
void stmt_time(struct bt_stmt *, struct dt_evt *);
void stmt_zero(struct bt_stmt *);
struct bt_arg *ba_read(struct bt_arg *);
+struct bt_arg *baeval(struct bt_arg *, struct dt_evt *);
const char *ba2hash(struct bt_arg *, struct dt_evt *);
long baexpr2long(struct bt_arg *, struct dt_evt *);
const char *ba2bucket(struct bt_arg *, struct bt_arg *,
struct bt_arg *brange, *bhist = SLIST_FIRST(&bs->bs_args);
struct bt_arg *bval = (struct bt_arg *)bs->bs_var;
struct bt_var *bv = bhist->ba_value;
+ struct hist *hist;
const char *bucket;
long step = 0;
debug("hist=%p '%s' increment bucket '%s'\n", bv->bv_value,
bv_name(bv), bucket);
- bv->bv_value = (struct bt_arg *)
- hist_increment((struct hist *)bv->bv_value, bucket, step);
+ /* hist is NULL before first insert or after clear() */
+ hist = (struct hist *)bv->bv_value;
+ if (hist == NULL)
+ hist = hist_new(step);
+
+ hist_increment(hist, bucket);
+
+ debug("hist=%p '%s' increment bucket=%p '%s' bval=%p\n", hist,
+ bv_name(bv), brange, bucket, bval);
+
+ bv->bv_value = (struct bt_arg *)hist;
bv->bv_type = B_VT_HIST;
}
struct bt_var *bv = bmap->ba_value;
struct map *map;
const char *hash;
+ long val;
assert(bmap->ba_type == B_AT_MAP);
assert(SLIST_NEXT(bval, ba_next) == NULL);
/* map is NULL before first insert or after clear() */
map = (struct map *)bv->bv_value;
- map = map_insert(map, hash, bval, dtev);
+ if (map == NULL)
+ map = map_new();
+
+ /* Operate on existring value for count(), max(), min() and sum(). */
+ switch (bval->ba_type) {
+ case B_AT_MF_COUNT:
+ val = ba2long(map_get(map, hash), NULL);
+ val++;
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_MAX:
+ val = ba2long(map_get(map, hash), NULL);
+ val = MAXIMUM(val, ba2long(bval->ba_value, dtev));
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_MIN:
+ val = ba2long(map_get(map, hash), NULL);
+ val = MINIMUM(val, ba2long(bval->ba_value, dtev));
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ case B_AT_MF_SUM:
+ val = ba2long(map_get(map, hash), NULL);
+ val += ba2long(bval->ba_value, dtev);
+ bval = ba_new(val, B_AT_LONG);
+ break;
+ default:
+ break;
+ }
+
+ map_insert(map, hash, bval);
debug("map=%p '%s' insert key=%p '%s' bval=%p\n", map,
bv_name(bv), bkey, hash, bval);
stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
{
struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
- struct bt_var *bv = bs->bs_var;
+ struct bt_var *bvar, *bv = bs->bs_var;
assert(SLIST_NEXT(ba, ba_next) == NULL);
bv->bv_value = ba;
bv->bv_type = B_VT_LONG;
break;
- case B_AT_BI_PID:
- bv->bv_value = ba_new((long)dtev->dtev_pid, B_AT_LONG);
- bv->bv_type = B_VT_LONG;
+ case B_AT_VAR:
+ bvar = ba->ba_value;
+ bv->bv_type = bvar->bv_type;
+ bv->bv_value = bvar->bv_value;
break;
- case B_AT_BI_TID:
- bv->bv_value = ba_new((long)dtev->dtev_tid, B_AT_LONG);
- bv->bv_type = B_VT_LONG;
+ case B_AT_TUPLE:
+ bv->bv_value = baeval(ba, dtev);
+ bv->bv_type = B_VT_TUPLE;
break;
+ case B_AT_BI_PID:
+ case B_AT_BI_TID:
case B_AT_BI_NSECS:
- bv->bv_value = ba_new(builtin_nsecs(dtev), B_AT_LONG);
- bv->bv_type = B_VT_LONG;
- break;
case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
- /* FALLTHROUGH */
case B_AT_OP_PLUS ... B_AT_OP_LOR:
- bv->bv_value = ba_new(ba2long(ba, dtev), B_AT_LONG);
+ bv->bv_value = baeval(ba, dtev);
bv->bv_type = B_VT_LONG;
break;
case B_AT_FN_STR:
- bv->bv_value = ba_new(ba2str(ba, dtev), B_AT_STR);
+ bv->bv_value = baeval(ba, dtev);
bv->bv_type = B_VT_STR;
break;
default:
xabort("store not implemented for type %d", ba->ba_type);
}
- debug("bv=%p var '%s' store (%p)\n", bv, bv_name(bv), bv->bv_value);
+ debug("bv=%p var '%s' store (%p)='%s'\n", bv, bv_name(bv), bv->bv_value,
+ ba2str(bv->bv_value, dtev));
}
/*
struct bt_var *bv = ba->ba_value;
assert(ba->ba_type == B_AT_VAR);
-
debug("bv=%p read '%s' (%p)\n", bv, bv_name(bv), bv->bv_value);
/* Handle map/hist access after clear(). */
return bv->bv_value;
}
+// XXX
+extern struct bt_arg *ba_append(struct bt_arg *, struct bt_arg *);
+
+/*
+ * Return a new argument that doesn't depend on `dtev'. This is used
+ * when storing values in variables, maps, etc.
+ */
+struct bt_arg *
+baeval(struct bt_arg *bval, struct dt_evt *dtev)
+{
+ struct bt_arg *ba, *bh = NULL;
+
+ switch (bval->ba_type) {
+ case B_AT_VAR:
+ ba = baeval(ba_read(bval), NULL);
+ break;
+ case B_AT_LONG:
+ case B_AT_BI_PID:
+ case B_AT_BI_TID:
+ case B_AT_BI_CPU:
+ case B_AT_BI_NSECS:
+ case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
+ case B_AT_BI_RETVAL:
+ case B_AT_OP_PLUS ... B_AT_OP_LOR:
+ ba = ba_new(ba2long(bval, dtev), B_AT_LONG);
+ break;
+ case B_AT_STR:
+ case B_AT_BI_COMM:
+ case B_AT_BI_KSTACK:
+ case B_AT_BI_USTACK:
+ case B_AT_BI_PROBE:
+ case B_AT_FN_STR:
+ ba = ba_new(ba2str(bval, dtev), B_AT_STR);
+ break;
+ case B_AT_TUPLE:
+ ba = bval->ba_value;
+ do {
+ bh = ba_append(bh, baeval(ba, dtev));
+ } while ((ba = SLIST_NEXT(ba, ba_next)) != NULL);
+ ba = ba_new(bh, B_AT_TUPLE);
+ break;
+ default:
+ xabort("no eval support for type %d", bval->ba_type);
+ }
+
+ return ba;
+}
+
+/*
+ * Return a string of coma-separated values
+ */
const char *
ba2hash(struct bt_arg *ba, struct dt_evt *dtev)
{
static char buf[STRLEN];
struct bt_var *bv;
struct dtioc_probe_info *dtpi;
+ unsigned long idx;
const char *str;
buf[0] = '\0';
snprintf(buf, sizeof(buf), "%ld",(long)ba->ba_value);
str = buf;
break;
+ case B_AT_TUPLE:
+ snprintf(buf, sizeof(buf), "(%s)", ba2hash(ba->ba_value, dtev));
+ str = buf;
+ break;
+ case B_AT_TMEMBER:
+ idx = (unsigned long)ba->ba_key;
+ bv = ba->ba_value;
+ /* Uninitialized tuple */
+ if (bv->bv_value == NULL) {
+ str = buf;
+ break;
+ }
+ ba = bv->bv_value;
+ assert(ba->ba_type == B_AT_TUPLE);
+ ba = ba->ba_value;
+ while (ba != NULL && idx-- > 0) {
+ ba = SLIST_NEXT(ba, ba_next);
+ }
+ str = ba2str(ba, dtev);
+ break;
case B_AT_NIL:
str = "";
break;
switch (bval->ba_type) {
case B_AT_STR:
case B_AT_LONG:
+ case B_AT_TUPLE:
+ case B_AT_TMEMBER:
case B_AT_VAR:
case B_AT_HIST:
case B_AT_NIL:
long
bacmp(struct bt_arg *a, struct bt_arg *b)
{
+ long val;
+
if (a->ba_type != b->ba_type)
return a->ba_type - b->ba_type;
return ba2long(a, NULL) - ba2long(b, NULL);
case B_AT_STR:
return strcmp(ba2str(a, NULL), ba2str(b, NULL));
+ case B_AT_TUPLE:
+ /* Compare two lists of arguments one by one. */
+ do {
+ val = bacmp(a, b);
+ if (val != 0)
+ break;
+
+ a = SLIST_NEXT(a, ba_next);
+ b = SLIST_NEXT(b, ba_next);
+ if (a == NULL && b != NULL)
+ val = -1;
+ else if (a != NULL && b == NULL)
+ val = 1;
+ } while (a != NULL && b != NULL);
+
+ return val;
default:
- errx(1, "no compare support for type %d", a->ba_type);
+ xabort("no compare support for type %d", a->ba_type);
}
}
-/* $OpenBSD: map.c,v 1.23 2023/09/03 10:26:35 mpi Exp $ */
+/* $OpenBSD: map.c,v 1.24 2023/09/11 19:01:26 mpi Exp $ */
/*
* Copyright (c) 2020 Martin Pieuchot <mpi@openbsd.org>
#include "bt_parser.h"
#include "btrace.h"
-#ifndef MIN
-#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
-#endif
-
-#ifndef MAX
-#define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
-#endif
-
RB_HEAD(map, mentry);
struct mentry {
return mep;
}
+struct map *
+map_new(void)
+{
+ struct map *map;
+
+ map = calloc(1, sizeof(struct map));
+ if (map == NULL)
+ err(1, "map: calloc");
+
+ return map;
+}
+
void
map_clear(struct map *map)
{
return mep->mval;
}
-struct map *
-map_insert(struct map *map, const char *key, struct bt_arg *bval,
- struct dt_evt *dtev)
+void
+map_insert(struct map *map, const char *key, void *cookie)
{
struct mentry *mep;
- long val;
-
- if (map == NULL) {
- map = calloc(1, sizeof(struct map));
- if (map == NULL)
- err(1, "map: calloc");
- }
mep = mget(map, key);
- switch (bval->ba_type) {
- case B_AT_STR:
- free(mep->mval);
- mep->mval = ba_new(ba2str(bval, dtev), B_AT_LONG);
- break;
- case B_AT_LONG:
- case B_AT_BI_PID:
- case B_AT_BI_TID:
- case B_AT_BI_CPU:
- case B_AT_BI_NSECS:
- case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
- case B_AT_BI_RETVAL:
- case B_AT_BI_PROBE:
- free(mep->mval);
- mep->mval = ba_new(ba2long(bval, dtev), B_AT_LONG);
- break;
- case B_AT_MF_COUNT:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val++;
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_MAX:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val = MAX(val, ba2long(bval->ba_value, dtev));
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_MIN:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val = MIN(val, ba2long(bval->ba_value, dtev));
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_MF_SUM:
- if (mep->mval == NULL)
- mep->mval = ba_new(0, B_AT_LONG);
- val = (long)mep->mval->ba_value;
- val += ba2long(bval->ba_value, dtev);
- mep->mval->ba_value = (void *)val;
- break;
- case B_AT_BI_COMM:
- case B_AT_BI_KSTACK:
- case B_AT_BI_USTACK:
- free(mep->mval);
- mep->mval = ba_new(ba2str(bval, dtev), B_AT_STR);
- break;
- default:
- errx(1, "no insert support for type %d", bval->ba_type);
- }
-
- return map;
+ free(mep->mval);
+ mep->mval = cookie;
}
static int
/*
* Histogram implemented with map.
*/
-
struct hist {
struct map hmap;
int hstep;
};
struct hist *
-hist_increment(struct hist *hist, const char *key, long step)
+hist_new(long step)
{
- static struct bt_arg incba = BA_INITIALIZER(NULL, B_AT_MF_COUNT);
+ struct hist *hist;
- if (hist == NULL) {
- hist = calloc(1, sizeof(struct hist));
- if (hist == NULL)
- err(1, "hist: calloc");
- hist->hstep = step;
- }
- assert(hist->hstep == step);
+ hist = calloc(1, sizeof(struct hist));
+ if (hist == NULL)
+ err(1, "hist: calloc");
+ hist->hstep = step;
+
+ return hist;
+}
+
+void
+hist_increment(struct hist *hist, const char *bucket)
+{
+ struct bt_arg *ba;
+ long val;
+
+ ba = map_get(&hist->hmap, bucket);
- return (struct hist *)map_insert(&hist->hmap, key, &incba, NULL);
+ assert(ba->ba_type == B_AT_LONG);
+ val = (long)ba->ba_value;
+ val++;
+ ba->ba_value = (void *)val;
}
long