sync code with last improvements from OpenBSD
This commit is contained in:
parent
2a511f7966
commit
5455e77c6b
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: Makefile,v 1.29 2023/09/02 19:28:46 dv Exp $
|
||||
# $OpenBSD: Makefile,v 1.30 2023/09/11 19:03:53 mpi Exp $
|
||||
|
||||
BTRACE?= /usr/sbin/btrace
|
||||
ALLOWDT!= sysctl -n kern.allowdt 2>/dev/null
|
||||
@ -9,7 +9,7 @@ BT_LANG_SCRIPTS= arithm beginend beginend-argn boolean comments delete \
|
||||
map mapclear mapempty mapsyntax mapzero map-unnamed \
|
||||
maxoperand min+max+sum multismts nsecs+var \
|
||||
precedence print read-map-after-clear staticv-empty \
|
||||
syntaxerror
|
||||
syntaxerror tuple tupleeval vareval
|
||||
|
||||
BT_ARG_LANG_SCRIPTS= staticv str
|
||||
|
||||
|
4
regress/usr.sbin/btrace/tuple.bt
Normal file
4
regress/usr.sbin/btrace/tuple.bt
Normal file
@ -0,0 +1,4 @@
|
||||
BEGIN {
|
||||
$t = (1, 42, "something");
|
||||
printf("%d %s\n", $t.1, $t.2);
|
||||
}
|
1
regress/usr.sbin/btrace/tuple.ok
Normal file
1
regress/usr.sbin/btrace/tuple.ok
Normal file
@ -0,0 +1 @@
|
||||
42 something
|
8
regress/usr.sbin/btrace/tupleeval.bt
Normal file
8
regress/usr.sbin/btrace/tupleeval.bt
Normal file
@ -0,0 +1,8 @@
|
||||
BEGIN {
|
||||
$t = (5, comm, "str", probe);
|
||||
@u = $t;
|
||||
}
|
||||
|
||||
END {
|
||||
print(@u)
|
||||
}
|
1
regress/usr.sbin/btrace/tupleeval.ok
Normal file
1
regress/usr.sbin/btrace/tupleeval.ok
Normal file
@ -0,0 +1 @@
|
||||
(5, btrace, str, BEGIN)
|
5
regress/usr.sbin/btrace/vareval.bt
Normal file
5
regress/usr.sbin/btrace/vareval.bt
Normal file
@ -0,0 +1,5 @@
|
||||
BEGIN {
|
||||
$tmp = 5;
|
||||
@t = $tmp;
|
||||
@m[42] = @t;
|
||||
}
|
1
regress/usr.sbin/btrace/vareval.ok
Normal file
1
regress/usr.sbin/btrace/vareval.ok
Normal file
@ -0,0 +1 @@
|
||||
@m[42]: 5
|
@ -1,4 +1,5 @@
|
||||
.\" $OpenBSD: ruby-module.5,v 1.40 2023/05/31 15:27:45 jeremy Exp $
|
||||
m
|
||||
.\" $OpenBSD: ruby-module.5,v 1.41 2023/09/11 20:02:38 jeremy Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2008 Marc Espie, Jeremy Evans
|
||||
.\"
|
||||
@ -24,7 +25,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2023 $
|
||||
.Dd $Mdocdate: September 11 2023 $
|
||||
.Dt RUBY-MODULE 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -38,48 +39,40 @@ in the
|
||||
tree.
|
||||
.Pp
|
||||
Sets
|
||||
.Ev MODRUBY_REV ,
|
||||
.Ev RUBY ,
|
||||
.Ev RAKE ,
|
||||
.Ev RSPEC ,
|
||||
.Ev MODRUBY_BIN_TESTRB ,
|
||||
.Ev MODRUBY_BIN_RSPEC ,
|
||||
.Ev MODRUBY_WANTLIB ,
|
||||
.Ev MODRUBY_RUN_DEPENDS ,
|
||||
.Ev MODRUBY_LIB_DEPENDS ,
|
||||
.Ev MODRUBY_BUILD_DEPENDS ,
|
||||
.Ev MODRUBY_RSPEC_DEPENDS ,
|
||||
.Ev MODRUBY_RSPEC3_DEPENDS ,
|
||||
.Ev MODRUBY_RUBY_ADJ ,
|
||||
.Ev GEM ,
|
||||
.Ev GEM_BASE_BIN ,
|
||||
.Ev GEM_BASE_LIB ,
|
||||
.Ev GEM_BIN ,
|
||||
.Ev GEM_BIN_SUFFIX ,
|
||||
.Ev GEM_EXTENSIONS_DIR,
|
||||
.Ev GEM_FLAGS ,
|
||||
.Ev GEM_LIB ,
|
||||
.Ev GEM_MAN_SUFFIX ,
|
||||
.Ev MODRUBY_ADJ_FILES ,
|
||||
.Ev MODRUBY_LIBDIR ,
|
||||
.Ev MODRUBY_DOCDIR ,
|
||||
.Ev MODRUBY_ARCH ,
|
||||
.Ev MODRUBY_BINREV ,
|
||||
.Ev MODRUBY_BIN_RSPEC ,
|
||||
.Ev MODRUBY_BUILD_DEPENDS ,
|
||||
.Ev MODRUBY_BUILDDEP ,
|
||||
.Ev MODRUBY_FLAVOR ,
|
||||
.Ev MODRUBY_HANDLE_FLAVORS ,
|
||||
.Ev MODRUBY_LIBREV ,
|
||||
.Ev MODRUBY_LIB_DEPENDS ,
|
||||
.Ev MODRUBY_PKG_PREFIX ,
|
||||
.Ev MODRUBY_RELEXAMPLEDIR ,
|
||||
.Ev MODRUBY_REV ,
|
||||
.Ev MODRUBY_RUBY_ADJ ,
|
||||
.Ev MODRUBY_RUN_DEPENDS ,
|
||||
.Ev MODRUBY_RUNDEP ,
|
||||
.Ev MODRUBY_SITEARCHDIR ,
|
||||
.Ev MODRUBY_SITEDIR ,
|
||||
.Ev MODRUBY_EXAMPLEDIR ,
|
||||
.Ev MODRUBY_ARCH ,
|
||||
.Ev MODRUBY_LIBREV ,
|
||||
.Ev MODRUBY_BINREV ,
|
||||
.Ev MODRUBY_HANDLE_FLAVORS ,
|
||||
.Ev MODRUBY_PKG_PREFIX ,
|
||||
.Ev MODRUBY_FLAVOR ,
|
||||
.Ev MODRUBY_TEST ,
|
||||
.Ev MODRUBY_TEST_TARGET ,
|
||||
.Ev MODRUBY_TEST_DIR ,
|
||||
.Ev MODRUBY_TEST_ENV ,
|
||||
.Ev MODRUBY_BUILD_TARGET ,
|
||||
.Ev MODRUBY_INSTALL_TARGET ,
|
||||
.Ev MODRUBY_EXTRACT_TARGET ,
|
||||
.Ev GEM ,
|
||||
.Ev GEM_BIN ,
|
||||
.Ev GEM_LIB ,
|
||||
.Ev GEM_BASE_LIB ,
|
||||
.Ev GEM_ABS_PATH ,
|
||||
.Ev GEM_BASE_BIN ,
|
||||
.Ev GEM_BIN_SUFFIX ,
|
||||
.Ev GEM_MAN_SUFFIX ,
|
||||
.Ev MODRUBY_TEST_TARGET ,
|
||||
.Ev MODRUBY_WANTLIB ,
|
||||
.Ev RAKE ,
|
||||
and
|
||||
.Ev GEM_FLAGS .
|
||||
.Ev RUBY .
|
||||
.Pp
|
||||
Appends to
|
||||
.Ev CATEGORIES
|
||||
@ -98,23 +91,17 @@ unless
|
||||
.Ev MODRUBY_RUNDEP
|
||||
is set to No.
|
||||
.Pp
|
||||
.Ev MODRUBY_RSPEC_DEPENDS
|
||||
is set to the dependency line for the rspec 1 port for the version of ruby in
|
||||
use.
|
||||
.Ev MODRUBY_RSPEC3_DEPENDS
|
||||
is set to the dependency line for the rspec 3 port for the version of ruby in
|
||||
use.
|
||||
.Ev RUBY ,
|
||||
.Ev RAKE ,
|
||||
and
|
||||
.Ev MODRUBY_BIN_TESTRB
|
||||
are the path to the ruby, rake, and
|
||||
testrb binaries for the related ruby implementation.
|
||||
.Ev RSPEC
|
||||
and
|
||||
.Ev RAKE
|
||||
are the path to the ruby and rake
|
||||
binaries for the related ruby implementation.
|
||||
.Ev MODRUBY_BIN_RSPEC
|
||||
are the path to the spec (rspec 1) and
|
||||
rspec (rspec 3) binaries for the related ruby implementation.
|
||||
is the path to the rspec (rspec 3) binaries for the related ruby
|
||||
implementation.
|
||||
.Pp
|
||||
.Ev MODRUBY_RUBY_ADJ
|
||||
is a command that takes filename arguments and replaces
|
||||
@ -129,14 +116,10 @@ Creates a do-test target if
|
||||
.Ev MODRUBY_TEST
|
||||
is used and one is not already defined.
|
||||
.Ev MODRUBY_TEST
|
||||
can be set to ruby, rake, rspec, rspec3, or testrb to
|
||||
can be set to ruby, rake, rspec3, or testrb to
|
||||
choose the appropriate binary to run the regress tests.
|
||||
.Ev MODRUBY_TEST_ENV
|
||||
can be used to set environment variables for the regress tests.
|
||||
.Ev MODRUBY_TEST_DIR
|
||||
can be used to set the directory in which to execute
|
||||
the regress tests, it defaults to
|
||||
.Ev WRKSRC .
|
||||
.Ev MODRUBY_TEST_TARGET
|
||||
sets the argument to the regress test program.
|
||||
.Pp
|
||||
@ -152,7 +135,7 @@ The "ruby gem"
|
||||
should be used for pure ruby gems without C extensions.
|
||||
This adds
|
||||
.Ev PKG_ARCH
|
||||
= * and adds ruby30, ruby31, ruby32, and jruby
|
||||
= * and adds ruby30, ruby31, and ruby32
|
||||
.Ev FLAVOR Ns s
|
||||
to the port, so the same port can build packages for multiple versions of ruby.
|
||||
.It
|
||||
@ -192,8 +175,7 @@ instead of ruby as the package prefix.
|
||||
Specifying
|
||||
.Ev MODRUBY_FLAVOR
|
||||
is necessary so that if a ruby x.y package is being built for the current
|
||||
port, it depends on the ruby x.y package of the
|
||||
dependencies.
|
||||
port, it depends on the ruby x.y package of the dependencies.
|
||||
.Pp
|
||||
The ports system defaults to using ruby 3.2 if the version of ruby is not
|
||||
specified.
|
||||
@ -202,7 +184,7 @@ If you want to specify a version for a gem port, use a specific
|
||||
such as ruby31 to use ruby 3.1.
|
||||
If you want to specify a version for a non-gem port, set
|
||||
.Ev MODRUBY_REV
|
||||
for the version of ruby you want to use (3.0, 3.1, 3.2, jruby).
|
||||
for the version of ruby you want to use (3.0, 3.1, 3.2).
|
||||
.Pp
|
||||
If you do not want the ports system to automatically set up
|
||||
.Ev FLAVOR Ns s
|
||||
@ -218,7 +200,7 @@ When
|
||||
.Ev MODRUBY_HANDLE_FLAVORS
|
||||
is Yes, the ports system automatically adds the appropriate prefix to the
|
||||
.Ev FULLPKGNAME
|
||||
(e.g. jruby- for jruby, ruby32- for ruby 3.2).
|
||||
(e.g. ruby31- for ruby 3.1, ruby32- for ruby 3.2).
|
||||
Additionally, it adds
|
||||
.Ev GEM_BIN_SUFFIX
|
||||
and
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* $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>
|
||||
*
|
||||
@ -72,6 +72,8 @@ 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_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 *);
|
||||
@ -210,9 +212,11 @@ fterm : fterm '*' factor { $$ = ba_op(B_AT_OP_MULT, $1, $3); }
|
||||
|
||||
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); }
|
||||
@ -419,7 +423,7 @@ ba_new0(void *val, enum bt_argtype type)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
@ -592,6 +596,17 @@ bl_store(const char *vname, struct bt_arg *vval)
|
||||
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)
|
||||
{
|
||||
@ -610,7 +625,7 @@ bm_insert(const char *mname, struct bt_arg *mkey, 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)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: bt_parser.h,v 1.23 2022/12/28 21:30:16 jmc Exp $ */
|
||||
/* $OpenBSD: bt_parser.h,v 1.24 2023/09/11 19:01:26 mpi Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
|
||||
@ -94,7 +94,7 @@ struct bt_rule {
|
||||
};
|
||||
|
||||
/*
|
||||
* Global variable representation.
|
||||
* Global and local variable representation.
|
||||
*
|
||||
* Variables are untyped and also include maps and histograms.
|
||||
*/
|
||||
@ -105,6 +105,7 @@ struct bt_var {
|
||||
enum bt_vartype {
|
||||
B_VT_STR = 1,
|
||||
B_VT_LONG,
|
||||
B_VT_TUPLE,
|
||||
B_VT_MAP,
|
||||
B_VT_HIST,
|
||||
} bv_type;
|
||||
@ -126,6 +127,8 @@ struct bt_arg {
|
||||
B_AT_VAR, /* global/local variable */
|
||||
B_AT_MAP, /* global map (@map[]) */
|
||||
B_AT_HIST, /* histogram */
|
||||
B_AT_TUPLE, /* tuple (1, 42, "str") */
|
||||
B_AT_TMEMBER, /* tuple member $t.2 */
|
||||
B_AT_NIL, /* empty value */
|
||||
|
||||
B_AT_BI_PID,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* $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
|
||||
@ -95,6 +95,7 @@ bool stmt_test(struct bt_stmt *, struct dt_evt *);
|
||||
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 *,
|
||||
@ -854,6 +855,7 @@ stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
|
||||
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;
|
||||
|
||||
@ -870,8 +872,17 @@ stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -943,6 +954,7 @@ stmt_insert(struct bt_stmt *bs, struct dt_evt *dtev)
|
||||
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);
|
||||
@ -952,7 +964,36 @@ stmt_insert(struct bt_stmt *bs, struct dt_evt *dtev)
|
||||
|
||||
/* 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);
|
||||
@ -1018,7 +1059,7 @@ void
|
||||
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);
|
||||
|
||||
@ -1031,33 +1072,33 @@ stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
|
||||
bv->bv_value = ba;
|
||||
bv->bv_type = B_VT_LONG;
|
||||
break;
|
||||
case B_AT_VAR:
|
||||
bvar = ba->ba_value;
|
||||
bv->bv_type = bvar->bv_type;
|
||||
bv->bv_value = bvar->bv_value;
|
||||
break;
|
||||
case B_AT_TUPLE:
|
||||
bv->bv_value = baeval(ba, dtev);
|
||||
bv->bv_type = B_VT_TUPLE;
|
||||
break;
|
||||
case B_AT_BI_PID:
|
||||
bv->bv_value = ba_new((long)dtev->dtev_pid, B_AT_LONG);
|
||||
bv->bv_type = B_VT_LONG;
|
||||
break;
|
||||
case B_AT_BI_TID:
|
||||
bv->bv_value = ba_new((long)dtev->dtev_tid, B_AT_LONG);
|
||||
bv->bv_type = B_VT_LONG;
|
||||
break;
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1160,7 +1201,6 @@ ba_read(struct bt_arg *ba)
|
||||
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(). */
|
||||
@ -1170,6 +1210,57 @@ ba_read(struct bt_arg *ba)
|
||||
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)
|
||||
{
|
||||
@ -1556,6 +1647,7 @@ ba2str(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';
|
||||
@ -1567,6 +1659,26 @@ ba2str(struct bt_arg *ba, struct dt_evt *dtev)
|
||||
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;
|
||||
@ -1674,6 +1786,8 @@ ba2dtflags(struct bt_arg *ba)
|
||||
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:
|
||||
@ -1720,6 +1834,8 @@ ba2dtflags(struct bt_arg *ba)
|
||||
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;
|
||||
|
||||
@ -1728,8 +1844,24 @@ bacmp(struct bt_arg *a, struct bt_arg *b)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: btrace.h,v 1.12 2023/05/12 14:14:16 claudio Exp $ */
|
||||
/* $OpenBSD: btrace.h,v 1.13 2023/09/11 19:01:26 mpi Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
|
||||
@ -46,14 +46,15 @@ int kelf_snprintsym(struct syms *, char *, size_t,
|
||||
/* map.c */
|
||||
struct map;
|
||||
struct hist;
|
||||
struct map *map_new(void);
|
||||
void map_clear(struct map *);
|
||||
void map_delete(struct map *, const char *);
|
||||
struct bt_arg *map_get(struct map *, const char *);
|
||||
struct map *map_insert(struct map *, const char *, struct bt_arg *,
|
||||
struct dt_evt *);
|
||||
void map_insert(struct map *, const char *, void *);
|
||||
void map_print(struct map *, size_t, const char *);
|
||||
void map_zero(struct map *);
|
||||
struct hist *hist_increment(struct hist *, const char *, long);
|
||||
struct hist *hist_new(long);
|
||||
void hist_increment(struct hist *, const char *);
|
||||
void hist_print(struct hist *, const char *);
|
||||
|
||||
#define KLEN 1024 /* # of characters in map key, contain a stack trace */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $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>
|
||||
@ -33,14 +33,6 @@
|
||||
#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 {
|
||||
@ -79,6 +71,18 @@ mget(struct map *map, const char *key)
|
||||
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)
|
||||
{
|
||||
@ -118,75 +122,14 @@ map_get(struct map *map, const char *key)
|
||||
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;
|
||||
mep->mval = cookie;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -248,26 +191,36 @@ map_zero(struct map *map)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
return (struct hist *)map_insert(&hist->hmap, key, &incba, NULL);
|
||||
return hist;
|
||||
}
|
||||
|
||||
void
|
||||
hist_increment(struct hist *hist, const char *bucket)
|
||||
{
|
||||
struct bt_arg *ba;
|
||||
long val;
|
||||
|
||||
ba = map_get(&hist->hmap, bucket);
|
||||
|
||||
assert(ba->ba_type == B_AT_LONG);
|
||||
val = (long)ba->ba_value;
|
||||
val++;
|
||||
ba->ba_value = (void *)val;
|
||||
}
|
||||
|
||||
long
|
||||
|
Loading…
Reference in New Issue
Block a user