libdtrace: Permit taking the address of an identifier without type info

Symbols defined using assembler directives lack type info, but in this
case one ought to be able to cast a pointer to the symbol and
dereference the pointer to get a value.  Without this change, D
disallows this trick since it requires all identifiers to have a type.

Relax the rules slightly and allow an identifier to have type "void" if
we know we're just taking its address.

As a result, the following dtrace invocation works:

  dtrace -n 'tick-1s {printf("%d", *(int *)&`ticks);}'

In particular, since commit b2b974f7ef ("clock: Simplify subr_ticks
and rename"), "ticks" does not have any type info associated with it, so
its value couldn't be printed.  This trick provides a workaround and is
probably generally useful.

Add a regression test which exercises this functionality.

PR:		287752
Reviewed by:	avg
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D51417
This commit is contained in:
Mark Johnston 2025-07-21 13:34:30 +00:00
parent 654dea5967
commit dabde7d976
4 changed files with 78 additions and 3 deletions

View file

@ -0,0 +1,54 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2025 Mark Johnston <markj@FreeBSD.org>
*/
/*
* For 10s, verify that the value of `ticks goes up by `hz each second.
*/
#pragma D option quiet
BEGIN
{
i = 0;
}
tick-1s
{
if (i == 0) {
t = *(int *)&`ticks;
i++;
} else {
u = *(int *)&`ticks;
if (u - t != `hz) {
printf("ticks: %d, expected %d\n", u - t, `hz);
exit(1);
}
t = u;
i++;
if (i == 10) {
exit(0);
}
}
}

View file

@ -1918,6 +1918,14 @@ dt_node_op1(int op, dt_node_t *cp)
return (cp);
}
/*
* When applying the addressof operator to an identifier, it's okay if
* we can't find type information for the identifier, so flag the node
* to ensure that we don't raise an error.
*/
if (op == DT_TOK_ADDROF && cp->dn_kind == DT_NODE_IDENT)
cp->dn_flags |= DT_NF_IDENTADDR;
dnp = dt_node_alloc(DT_NODE_OP1);
assert(op <= USHRT_MAX);
dnp->dn_op = (ushort_t)op;
@ -2786,10 +2794,21 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
dt_module_modelname(dtp->dt_ddefs));
}
xyerror(D_SYM_NOTYPES,
/*
* If we're taking the address of an identifier that
* doesn't have type info, try to make it a void *.
* This lets us use identifiers that are defined in
* assembly and don't have type information.
*/
if ((dnp->dn_flags & DT_NF_IDENTADDR) == 0 ||
dtrace_lookup_by_type(dtp, DTRACE_OBJ_CDEFS,
"void", &dtt) != 0) {
xyerror(D_SYM_NOTYPES,
"no symbolic type information is available for "
"%s%s%s: %s\n", dts.dts_object, mark, dts.dts_name,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
"%s%s%s: %s\n", dts.dts_object, mark,
dts.dts_name,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
}
}
idp = dt_ident_create(name, DT_IDENT_SYMBOL, 0, 0,

View file

@ -182,6 +182,7 @@ typedef struct dt_node {
#define DT_NF_WRITABLE 0x10 /* node is writable (can be modified) */
#define DT_NF_BITFIELD 0x20 /* node is an integer bitfield */
#define DT_NF_USERLAND 0x40 /* data is a userland address */
#define DT_NF_IDENTADDR 0x80 /* node is an identifier address */
#define DT_TYPE_NAMELEN 128 /* reasonable size for ctf_type_name() */

View file

@ -37,6 +37,7 @@ ${PACKAGE}FILES= \
tst.profileusec.d \
tst.profileusec.d.out \
tst.sym.ksh \
tst.ticks.d \
tst.ufunc.ksh \
tst.ufuncsort.ksh \
tst.ufuncsort.ksh.out \