Skip to content

Commit

Permalink
usdt: is-enabled probe support
Browse files Browse the repository at this point in the history
This implementation is in many ways similar to v1's, but contains one
significant simplification: rather than is-enabled probes appearing to
the user as a function that returns a 1 or 0, they appear as a function
that returns void and takes the address of a local variable: the
_IS_ENABLED macros use the GCC statement-expression extension
to declare and initialize a distinct local for each use of the
is-enabled probe:

	({ uint32_t enabled = 0; \
	__dtraceenabled_foo___bar(&enabled); \
	   enabled; })

The is-enabled trampoline writes a 1 into this local variable.  This
allows the dt_link code to discard all the architecture-dependent code
dealing with return value handling and treat is-enabled probes just like
other USDT probes: it still tracks whether is-enabled probes are used,
but doesn't use the info for anything but setting the DOF version.

The downside of this approach, of course, is that users need the
statement-expression extension to work, and that old is-enabled probes
from DTrace v1 aren't going to work without regeneration with dtrace
-G. Neither of these seem likely to be serious problems in practice, and
the commit before this one should help.

We use #pragma system_header to suppress -pedantic warnings about
use of the extension.

Internally, there are tiny changes in the dtprobed and dt_pid
uprobe-registration-and-creation layers to put is-enabled probes in a
different uprobe group to prevent their names clashing with USDT probes
with the same name (dt_pid_is_enabled/ rather than dt_pid/). Normal USDT
probes enable the correspondinng is-enabled probe, if any, when they are
enabled: those probes have custom trampoline that copy a 64-bit-wide 1
into the first function parameter (and have truncated parameter-copying
code that avoids preserving any parameter but the first, because there
will never be any more).

Please ignore the code duplication between trampoline() and
trampoline_is_enabled(): this is temporary to make it easier to make
changes for getting globbed systemwide probing working later on.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
nickalcock authored and kvanhees committed May 24, 2023
1 parent 73f8bb9 commit c200591
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 217 deletions.
8 changes: 3 additions & 5 deletions dtprobed/dtprobed.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace; DOF-consumption and USDT-probe-creation daemon.
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -323,15 +323,13 @@ create_probe(pid_t pid, dof_parsed_t *provider, dof_parsed_t *probe,
{
const char *mod, *fun, *prb;

if (tp->tracepoint.is_enabled)
return; /* Not yet implemented. */

mod = probe->probe.name;
fun = mod + strlen(mod) + 1;
prb = fun + strlen(fun) + 1;

free(uprobe_create_from_addr(pid, tp->tracepoint.addr,
provider->provider.name, mod, fun, prb));
tp->tracepoint.is_enabled, provider->provider.name,
mod, fun, prb));
}

/*
Expand Down
27 changes: 14 additions & 13 deletions libcommon/uprobes.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -209,13 +209,13 @@ uprobe_decode_name(const char *name)
}

char *
uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
{
char *name;

if (asprintf(&name, "dt_pid/%c_%llx_%llx_%lx", isret ? 'r' : 'p',
(unsigned long long)dev, (unsigned long long)ino,
(unsigned long)addr) < 0)
if (asprintf(&name, "dt_pid%s/%c_%llx_%llx_%lx", is_enabled?"_is_enabled":"",
isret ? 'r' : 'p', (unsigned long long)dev,
(unsigned long long)ino, (unsigned long)addr) < 0)
return NULL;

return name;
Expand All @@ -229,7 +229,7 @@ uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret)
*/
char *
uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
const char *prv, const char *mod, const char *fun,
int is_enabled, const char *prv, const char *mod, const char *fun,
const char *prb)
{
int fd = -1;
Expand Down Expand Up @@ -261,7 +261,7 @@ uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int i
return NULL;
}

name = uprobe_name(dev, ino, addr, isret);
name = uprobe_name(dev, ino, addr, isret, is_enabled);
if (!name)
goto out;

Expand Down Expand Up @@ -292,9 +292,10 @@ uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int i
* systemwide uprobe list.)
*/
char *
uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret,
int is_enabled)
{
return uprobe_create_named(dev, ino, addr, spec, isret,
return uprobe_create_named(dev, ino, addr, spec, isret, is_enabled,
NULL, NULL, NULL, NULL);
}

Expand All @@ -304,7 +305,7 @@ uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec, int isret)
* are set, they are passed down as the name of the corresponding DTrace probe.
*/
char *
uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled, const char *prv,
const char *mod, const char *fun, const char *prb)
{
char *spec;
Expand All @@ -316,7 +317,7 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
return NULL;

name = uprobe_create_named(mapp.pr_dev, mapp.pr_inum, addr, spec, 0,
prv, mod, fun, prb);
is_enabled, prv, mod, fun, prb);
free(spec);
return name;
}
Expand All @@ -325,13 +326,13 @@ uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
* Destroy a uprobe for a given device, address, and spec.
*/
int
uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret)
uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret, int is_enabled)
{
int fd = -1;
int rc = -1;
char *name;

name = uprobe_name(dev, ino, addr, isret);
name = uprobe_name(dev, ino, addr, isret, is_enabled);
if (!name)
goto out;

Expand Down
22 changes: 12 additions & 10 deletions libcommon/uprobes.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace; simple uprobe helper functions
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
Expand All @@ -15,17 +15,19 @@

extern char *uprobe_spec_by_addr(pid_t pid, ps_prochandle *P, uint64_t addr,
prmap_t *mapp);
extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret);
extern char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int isret,
int is_enabled);
extern char *uprobe_create_named(dev_t dev, ino_t ino, uint64_t addr,
const char *spec, int isret, const char *prv,
const char *mod, const char *fun,
const char *prb);
const char *spec, int isret, int is_enabled,
const char *prv, const char *mod,
const char *fun, const char *prb);
extern char *uprobe_create(dev_t dev, ino_t ino, uint64_t addr, const char *spec,
int isret);
extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, const char *prv,
const char *mod, const char *fun,
const char *prb);
extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret);
int isret, int is_enabled);
extern char *uprobe_create_from_addr(pid_t pid, uint64_t addr, int is_enabled,
const char *prv, const char *mod,
const char *fun, const char *prb);
extern int uprobe_delete(dev_t dev, ino_t ino, uint64_t addr, int isret,
int is_enabled);
extern char *uprobe_encode_name(const char *);
extern char *uprobe_decode_name(const char *);

Expand Down

0 comments on commit c200591

Please sign in to comment.