Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d (revision 326499) @@ -0,0 +1,25 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option setenv=balloon=something_bad_happens + +BEGIN +{ + exit(0); +} Property changes on: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d (revision 326499) @@ -0,0 +1,25 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option unsetenv=rectalexambot + +BEGIN +{ + exit(0); +} Property changes on: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh (revision 326499) @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Check that the LD_NOLAZYLOAD variable is set to 1 as expected. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -c 'printenv LD_NOLAZYLOAD' + +exit $? Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out (revision 326499) @@ -0,0 +1,2 @@ +1 + Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh (revision 326499) @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Reset an environment variable we already know to be set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xsetenv=LD_NOLAZYLOAD=0 -c 'printenv LD_NOLAZYLOAD' + +exit $? Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out (revision 326499) @@ -0,0 +1,2 @@ +0 + Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh (revision 326499) @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test setting a variable that we isn't already set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xsetenv=CORPORATIONS=PEOPLE -c 'printenv CORPORATIONS' + +exit $? Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out (revision 326499) @@ -0,0 +1,2 @@ +PEOPLE + Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh (revision 326499) @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test unsetting a variable we know to be set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xunsetenv=LD_NOLAZYLOAD -c 'printenv LD_NOLAZYLOAD' + +exit $? Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh (revision 326499) @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test invalid syntax to the unsetenv option. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xunsetenv=ed=screven -c 'true' 2>&1 + +[[ $? -eq 1 ]] && exit 0 + +exit 1 Index: head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out =================================================================== --- head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out (nonexistent) +++ head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out (revision 326499) @@ -0,0 +1 @@ +dtrace: failed to set -x unsetenv: Invalid value for specified option Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c (revision 326498) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c (revision 326499) @@ -1,1741 +1,1742 @@ /* * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012, 2016 by Delphix. All rights reserved. */ #include #ifdef illumos #include #include #else #include #include #include #endif #include #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #define _POSIX_PTHREAD_SEMANTICS #include #undef _POSIX_PTHREAD_SEMANTICS #include #include #include #include #include #include #ifndef illumos #include #include #endif #if defined(__i386__) #include #endif /* * Stability and versioning definitions. These #defines are used in the tables * of identifiers below to fill in the attribute and version fields associated * with each identifier. The DT_ATTR_* macros are a convenience to permit more * concise declarations of common attributes such as Stable/Stable/Common. The * DT_VERS_* macros declare the encoded integer values of all versions used so * far. DT_VERS_LATEST must correspond to the latest version value among all * versions exported by the D compiler. DT_VERS_STRING must be an ASCII string * that contains DT_VERS_LATEST within it along with any suffixes (e.g. Beta). * You must update DT_VERS_LATEST and DT_VERS_STRING when adding a new version, * and then add the new version to the _dtrace_versions[] array declared below. * Refer to the Solaris Dynamic Tracing Guide Stability and Versioning chapters * respectively for an explanation of these DTrace features and their values. * * NOTE: Although the DTrace versioning scheme supports the labeling and * introduction of incompatible changes (e.g. dropping an interface in a * major release), the libdtrace code does not currently support this. * All versions are assumed to strictly inherit from one another. If * we ever need to provide divergent interfaces, this will need work. */ #define DT_ATTR_STABCMN { DTRACE_STABILITY_STABLE, \ DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON } #define DT_ATTR_EVOLCMN { DTRACE_STABILITY_EVOLVING, \ DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON \ } /* * The version number should be increased for every customer visible release * of DTrace. The major number should be incremented when a fundamental * change has been made that would affect all consumers, and would reflect * sweeping changes to DTrace or the D language. The minor number should be * incremented when a change is introduced that could break scripts that had * previously worked; for example, adding a new built-in variable could break * a script which was already using that identifier. The micro number should * be changed when introducing functionality changes or major bug fixes that * do not affect backward compatibility -- this is merely to make capabilities * easily determined from the version number. Minor bugs do not require any * modification to the version number. */ #define DT_VERS_1_0 DT_VERSION_NUMBER(1, 0, 0) #define DT_VERS_1_1 DT_VERSION_NUMBER(1, 1, 0) #define DT_VERS_1_2 DT_VERSION_NUMBER(1, 2, 0) #define DT_VERS_1_2_1 DT_VERSION_NUMBER(1, 2, 1) #define DT_VERS_1_2_2 DT_VERSION_NUMBER(1, 2, 2) #define DT_VERS_1_3 DT_VERSION_NUMBER(1, 3, 0) #define DT_VERS_1_4 DT_VERSION_NUMBER(1, 4, 0) #define DT_VERS_1_4_1 DT_VERSION_NUMBER(1, 4, 1) #define DT_VERS_1_5 DT_VERSION_NUMBER(1, 5, 0) #define DT_VERS_1_6 DT_VERSION_NUMBER(1, 6, 0) #define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1) #define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2) #define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3) #define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0) #define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1) #define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0) #define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1) #define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0) #define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1) #define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0) #define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0) #define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0) #define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1) #define DT_VERS_1_13 DT_VERSION_NUMBER(1, 13, 0) #define DT_VERS_LATEST DT_VERS_1_13 #define DT_VERS_STRING "Sun D 1.13" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ DT_VERS_1_1, /* D API 1.1.0 Solaris Express 6/05 */ DT_VERS_1_2, /* D API 1.2.0 Solaris 10 Update 1 */ DT_VERS_1_2_1, /* D API 1.2.1 Solaris Express 4/06 */ DT_VERS_1_2_2, /* D API 1.2.2 Solaris Express 6/06 */ DT_VERS_1_3, /* D API 1.3 Solaris Express 10/06 */ DT_VERS_1_4, /* D API 1.4 Solaris Express 2/07 */ DT_VERS_1_4_1, /* D API 1.4.1 Solaris Express 4/07 */ DT_VERS_1_5, /* D API 1.5 Solaris Express 7/07 */ DT_VERS_1_6, /* D API 1.6 */ DT_VERS_1_6_1, /* D API 1.6.1 */ DT_VERS_1_6_2, /* D API 1.6.2 */ DT_VERS_1_6_3, /* D API 1.6.3 */ DT_VERS_1_7, /* D API 1.7 */ DT_VERS_1_7_1, /* D API 1.7.1 */ DT_VERS_1_8, /* D API 1.8 */ DT_VERS_1_8_1, /* D API 1.8.1 */ DT_VERS_1_9, /* D API 1.9 */ DT_VERS_1_9_1, /* D API 1.9.1 */ DT_VERS_1_10, /* D API 1.10 */ DT_VERS_1_11, /* D API 1.11 */ DT_VERS_1_12, /* D API 1.12 */ DT_VERS_1_12_1, /* D API 1.12.1 */ DT_VERS_1_13, /* D API 1.13 */ 0 }; /* * Global variables that are formatted on FreeBSD based on the kernel file name. */ #ifndef illumos static char curthread_str[MAXPATHLEN]; static char intmtx_str[MAXPATHLEN]; static char threadmtx_str[MAXPATHLEN]; static char rwlock_str[MAXPATHLEN]; static char sxlock_str[MAXPATHLEN]; #endif /* * Table of global identifiers. This is used to populate the global identifier * hash when a new dtrace client open occurs. For more info see dt_ident.h. * The global identifiers that represent functions use the dt_idops_func ops * and specify the private data pointer as a prototype string which is parsed * when the identifier is first encountered. These prototypes look like ANSI * C function prototypes except that the special symbol "@" can be used as a * wildcard to represent a single parameter of any type (i.e. any dt_node_t). * The standard "..." notation can also be used to represent varargs. An empty * parameter list is taken to mean void (that is, no arguments are permitted). * A parameter enclosed in square brackets (e.g. "[int]") denotes an optional * argument. */ static const dt_ident_t _dtrace_globals[] = { { "alloca", DT_IDENT_FUNC, 0, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void *(size_t)" }, { "arg0", DT_IDENT_SCALAR, 0, DIF_VAR_ARG0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg1", DT_IDENT_SCALAR, 0, DIF_VAR_ARG1, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg2", DT_IDENT_SCALAR, 0, DIF_VAR_ARG2, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg3", DT_IDENT_SCALAR, 0, DIF_VAR_ARG3, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg4", DT_IDENT_SCALAR, 0, DIF_VAR_ARG4, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg5", DT_IDENT_SCALAR, 0, DIF_VAR_ARG5, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg6", DT_IDENT_SCALAR, 0, DIF_VAR_ARG6, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg7", DT_IDENT_SCALAR, 0, DIF_VAR_ARG7, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg8", DT_IDENT_SCALAR, 0, DIF_VAR_ARG8, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg9", DT_IDENT_SCALAR, 0, DIF_VAR_ARG9, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "args", DT_IDENT_ARRAY, 0, DIF_VAR_ARGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_args, NULL }, { "avg", DT_IDENT_AGGFUNC, 0, DTRACEAGG_AVG, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "basename", DT_IDENT_FUNC, 0, DIF_SUBR_BASENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "bcopy", DT_IDENT_FUNC, 0, DIF_SUBR_BCOPY, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(void *, void *, size_t)" }, { "breakpoint", DT_IDENT_ACTFUNC, 0, DT_ACT_BREAKPOINT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "caller", DT_IDENT_SCALAR, 0, DIF_VAR_CALLER, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uintptr_t" }, { "chill", DT_IDENT_ACTFUNC, 0, DT_ACT_CHILL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "cleanpath", DT_IDENT_FUNC, 0, DIF_SUBR_CLEANPATH, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "clear", DT_IDENT_ACTFUNC, 0, DT_ACT_CLEAR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "commit", DT_IDENT_ACTFUNC, 0, DT_ACT_COMMIT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "copyin", DT_IDENT_FUNC, 0, DIF_SUBR_COPYIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void *(uintptr_t, size_t)" }, { "copyinstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(uintptr_t, [size_t])" }, { "copyinto", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINTO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(uintptr_t, size_t, void *)" }, { "copyout", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(void *, uintptr_t, size_t)" }, { "copyoutstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUTSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(char *, uintptr_t, size_t)" }, { "count", DT_IDENT_AGGFUNC, 0, DTRACEAGG_COUNT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD, { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, DT_VERS_1_0, #ifdef illumos &dt_idops_type, "genunix`kthread_t *" }, #else &dt_idops_type, curthread_str }, #endif { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "string(void *, int64_t)" }, { "denormalize", DT_IDENT_ACTFUNC, 0, DT_ACT_DENORMALIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "dirname", DT_IDENT_FUNC, 0, DIF_SUBR_DIRNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int" }, { "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "freopen", DT_IDENT_ACTFUNC, 0, DT_ACT_FREOPEN, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "void(@, ...)" }, { "ftruncate", DT_IDENT_ACTFUNC, 0, DT_ACT_FTRUNCATE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "func", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, { "getmajor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMAJOR, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`major_t(genunix`dev_t)" }, { "getminor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMINOR, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`minor_t(genunix`dev_t)" }, { "htonl", DT_IDENT_FUNC, 0, DIF_SUBR_HTONL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint32_t(uint32_t)" }, { "htonll", DT_IDENT_FUNC, 0, DIF_SUBR_HTONLL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint64_t(uint64_t)" }, { "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint16_t(uint16_t)" }, { "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10, &dt_idops_func, "file_t *(int)" }, { "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "gid_t" }, { "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "int(const char *, const char *, [int])" }, { "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN, #ifdef illumos DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" }, #else DT_VERS_1_5, &dt_idops_func, "string(in_addr_t *)" }, #endif { "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN, #ifdef illumos DT_VERS_1_5, &dt_idops_func, "string(in6_addr_t *)" }, #else DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" }, #endif { "inet_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOP, DT_ATTR_STABCMN, DT_VERS_1_5, &dt_idops_func, "string(int, void *)" }, { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11, &dt_idops_func, "string(const char *, const char *)" }, { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(int64_t, [int])" }, { "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_7, &dt_idops_func, "void(@, int32_t, int32_t, int32_t, int32_t, ...)" }, { "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, int32_t, int32_t, ...)" }, { "max", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MAX, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "uintptr_t *(void *, size_t)" }, #ifndef illumos { "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(void *, char, size_t)" }, #endif { "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, { "msgdsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGDSIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(mblk_t *)" }, { "msgsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGSIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(mblk_t *)" }, #ifdef illumos { "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, { "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`kthread_t *(genunix`kmutex_t *)" }, { "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, { "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, #else { "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, { "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, threadmtx_str }, { "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, { "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, #endif { "ntohl", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint32_t(uint32_t)" }, { "ntohll", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHLL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint64_t(uint64_t)" }, { "ntohs", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHS, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint16_t(uint16_t)" }, { "normalize", DT_IDENT_ACTFUNC, 0, DT_ACT_NORMALIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "panic", DT_IDENT_ACTFUNC, 0, DT_ACT_PANIC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "pid", DT_IDENT_SCALAR, 0, DIF_VAR_PID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "pid_t" }, { "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "pid_t" }, { "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9, &dt_idops_func, "void(@)" }, { "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "printm", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(size_t, uintptr_t *)" }, { "probefunc", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEFUNC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probemod", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEMOD, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probename", DT_IDENT_SCALAR, 0, DIF_VAR_PROBENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probeprov", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEPROV, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "progenyof", DT_IDENT_FUNC, 0, DIF_SUBR_PROGENYOF, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int(pid_t)" }, { "quantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_QUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "raise", DT_IDENT_ACTFUNC, 0, DT_ACT_RAISE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, { "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "int(const char *, const char *, [int])" }, #ifdef illumos { "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, { "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, { "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, #else { "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, { "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, { "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, #endif { "self", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "void" }, { "setopt", DT_IDENT_ACTFUNC, 0, DT_ACT_SETOPT, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "void(const char *, [const char *])" }, { "speculate", DT_IDENT_ACTFUNC, 0, DT_ACT_SPECULATE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "speculation", DT_IDENT_FUNC, 0, DIF_SUBR_SPECULATION, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, { "stack", DT_IDENT_ACTFUNC, 0, DT_ACT_STACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "stackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_STACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint32_t" }, { "stddev", DT_IDENT_AGGFUNC, 0, DTRACEAGG_STDDEV, DT_ATTR_STABCMN, DT_VERS_1_6, &dt_idops_func, "void(@)" }, { "stop", DT_IDENT_ACTFUNC, 0, DT_ACT_STOP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "strchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRCHR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, char)" }, { "strlen", DT_IDENT_FUNC, 0, DIF_SUBR_STRLEN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(const char *)" }, { "strjoin", DT_IDENT_FUNC, 0, DIF_SUBR_STRJOIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *, const char *)" }, { "strrchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRRCHR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, char)" }, { "strstr", DT_IDENT_FUNC, 0, DIF_SUBR_STRSTR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, const char *)" }, { "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, const char *)" }, { "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11, &dt_idops_func, "int64_t(const char *, [int])" }, { "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, int, [int])" }, { "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, #ifndef illumos { "sx_isexclusive", DT_IDENT_FUNC, 0, DIF_SUBR_SX_ISEXCLUSIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, { "sx_shared_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_SHARED_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, { "sx_exclusive_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_EXCLUSIVE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, #endif { "sym", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, { "system", DT_IDENT_ACTFUNC, 0, DT_ACT_SYSTEM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "this", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "void" }, { "tid", DT_IDENT_SCALAR, 0, DIF_VAR_TID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "id_t" }, { "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, { "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8, &dt_idops_func, "string(const char *)" }, { "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8, &dt_idops_func, "string(const char *)" }, { "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, size_t, ...)" }, { "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_type, "uint64_t" }, { "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uid_t" }, { "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_regs, NULL }, { "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_type, "uint32_t" }, { "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, { "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, #ifdef illumos { "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, #endif #ifndef illumos { "cpu", DT_IDENT_SCALAR, 0, DIF_VAR_CPU, DT_ATTR_STABCMN, DT_VERS_1_6_3, &dt_idops_type, "int" }, #endif { NULL, 0, 0, 0, { 0, 0, 0 }, 0, NULL, NULL } }; /* * Tables of ILP32 intrinsic integer and floating-point type templates to use * to populate the dynamic "C" CTF type container. */ static const dt_intrinsic_t _dtrace_intrinsics_32[] = { { "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER }, { "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "unsigned", { 0, 0, 32 }, CTF_K_INTEGER }, { "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER }, { "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER }, { "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER }, { "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT }, { "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT }, { "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT }, { "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT }, { "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT }, { "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT }, { "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT }, { "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT }, { "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT }, { NULL, { 0, 0, 0 }, 0 } }; /* * Tables of LP64 intrinsic integer and floating-point type templates to use * to populate the dynamic "C" CTF type container. */ static const dt_intrinsic_t _dtrace_intrinsics_64[] = { { "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER }, { "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "unsigned", { 0, 0, 32 }, CTF_K_INTEGER }, { "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER }, { "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long", { 0, 0, 64 }, CTF_K_INTEGER }, { "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER }, { "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER }, { "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT }, { "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT }, { "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT }, { "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT }, { "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT }, { "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT }, { "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT }, { "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT }, { "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT }, { NULL, { 0, 0, 0 }, 0 } }; /* * Tables of ILP32 typedefs to use to populate the dynamic "D" CTF container. * These aliases ensure that D definitions can use typical names. */ static const dt_typedef_t _dtrace_typedefs_32[] = { { "char", "int8_t" }, { "short", "int16_t" }, { "int", "int32_t" }, { "long long", "int64_t" }, { "int", "intptr_t" }, { "int", "ssize_t" }, { "unsigned char", "uint8_t" }, { "unsigned short", "uint16_t" }, { "unsigned", "uint32_t" }, { "unsigned long long", "uint64_t" }, { "unsigned char", "uchar_t" }, { "unsigned short", "ushort_t" }, { "unsigned", "uint_t" }, { "unsigned long", "ulong_t" }, { "unsigned long long", "u_longlong_t" }, { "int", "ptrdiff_t" }, { "unsigned", "uintptr_t" }, { "unsigned", "size_t" }, { "long", "id_t" }, { "long", "pid_t" }, { NULL, NULL } }; /* * Tables of LP64 typedefs to use to populate the dynamic "D" CTF container. * These aliases ensure that D definitions can use typical names. */ static const dt_typedef_t _dtrace_typedefs_64[] = { { "char", "int8_t" }, { "short", "int16_t" }, { "int", "int32_t" }, { "long", "int64_t" }, { "long", "intptr_t" }, { "long", "ssize_t" }, { "unsigned char", "uint8_t" }, { "unsigned short", "uint16_t" }, { "unsigned", "uint32_t" }, { "unsigned long", "uint64_t" }, { "unsigned char", "uchar_t" }, { "unsigned short", "ushort_t" }, { "unsigned", "uint_t" }, { "unsigned long", "ulong_t" }, { "unsigned long long", "u_longlong_t" }, { "long", "ptrdiff_t" }, { "unsigned long", "uintptr_t" }, { "unsigned long", "size_t" }, { "int", "id_t" }, { "int", "pid_t" }, { NULL, NULL } }; /* * Tables of ILP32 integer type templates used to populate the dtp->dt_ints[] * cache when a new dtrace client open occurs. Values are set by dtrace_open(). */ static const dt_intdesc_t _dtrace_ints_32[] = { { "int", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned int", NULL, CTF_ERR, 0xffffffffULL }, { "long", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned long", NULL, CTF_ERR, 0xffffffffULL }, { "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL } }; /* * Tables of LP64 integer type templates used to populate the dtp->dt_ints[] * cache when a new dtrace client open occurs. Values are set by dtrace_open(). */ static const dt_intdesc_t _dtrace_ints_64[] = { { "int", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned int", NULL, CTF_ERR, 0xffffffffULL }, { "long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long", NULL, CTF_ERR, 0xffffffffffffffffULL }, { "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL } }; /* * Table of macro variable templates used to populate the macro identifier hash * when a new dtrace client open occurs. Values are set by dtrace_update(). */ static const dt_ident_t _dtrace_macros[] = { { "egid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "euid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "gid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "pid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "pgid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "ppid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "projid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "sid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "taskid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "target", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "uid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { NULL, 0, 0, 0, { 0, 0, 0 }, 0 } }; /* * Hard-wired definition string to be compiled and cached every time a new * DTrace library handle is initialized. This string should only be used to * contain definitions that should be present regardless of DTRACE_O_NOLIBS. */ static const char _dtrace_hardwire[] = "\ inline long NULL = 0; \n\ #pragma D binding \"1.0\" NULL\n\ "; /* * Default DTrace configuration to use when opening libdtrace DTRACE_O_NODEV. * If DTRACE_O_NODEV is not set, we load the configuration from the kernel. * The use of CTF_MODEL_NATIVE is more subtle than it might appear: we are * relying on the fact that when running dtrace(1M), isaexec will invoke the * binary with the same bitness as the kernel, which is what we want by default * when generating our DIF. The user can override the choice using oflags. */ static const dtrace_conf_t _dtrace_conf = { DIF_VERSION, /* dtc_difversion */ DIF_DIR_NREGS, /* dtc_difintregs */ DIF_DTR_NREGS, /* dtc_diftupregs */ CTF_MODEL_NATIVE /* dtc_ctfmodel */ }; const dtrace_attribute_t _dtrace_maxattr = { DTRACE_STABILITY_MAX, DTRACE_STABILITY_MAX, DTRACE_CLASS_MAX }; const dtrace_attribute_t _dtrace_defattr = { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }; const dtrace_attribute_t _dtrace_symattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_attribute_t _dtrace_typattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_attribute_t _dtrace_prvattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_pattr_t _dtrace_prvdesc = { { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, }; #ifdef illumos const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */ const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */ #else const char *_dtrace_defcpp = "cpp"; /* default cpp(1) to invoke */ const char *_dtrace_defld = "ld"; /* default ld(1) to invoke */ const char *_dtrace_defobjcopy = "objcopy"; /* default objcopy(1) to invoke */ #endif const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */ #ifdef illumos const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */ #else const char *_dtrace_libdir32 = "/usr/lib32/dtrace"; const char *_dtrace_provdir = "/dev/dtrace"; /* provider directory */ #endif int _dtrace_strbuckets = 211; /* default number of hash buckets (prime) */ int _dtrace_intbuckets = 256; /* default number of integer buckets (Pof2) */ uint_t _dtrace_strsize = 256; /* default size of string intrinsic type */ uint_t _dtrace_stkindent = 14; /* default whitespace indent for stack/ustack */ uint_t _dtrace_pidbuckets = 64; /* default number of pid hash buckets */ uint_t _dtrace_pidlrulim = 8; /* default number of pid handles to cache */ size_t _dtrace_bufsize = 512; /* default dt_buf_create() size */ int _dtrace_argmax = 32; /* default maximum number of probe arguments */ int _dtrace_debug = 0; /* debug messages enabled (off) */ const char *const _dtrace_version = DT_VERS_STRING; /* API version string */ int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */ typedef struct dt_fdlist { int *df_fds; /* array of provider driver file descriptors */ uint_t df_ents; /* number of valid elements in df_fds[] */ uint_t df_size; /* size of df_fds[] */ } dt_fdlist_t; #ifdef illumos #pragma init(_dtrace_init) #else void _dtrace_init(void) __attribute__ ((constructor)); #endif void _dtrace_init(void) { _dtrace_debug = getenv("DTRACE_DEBUG") != NULL; for (; _dtrace_rdvers > 0; _dtrace_rdvers--) { if (rd_init(_dtrace_rdvers) == RD_OK) break; } #if defined(__i386__) /* make long doubles 64 bits -sson */ (void) fpsetprec(FP_PE); #endif } static dtrace_hdl_t * set_open_errno(dtrace_hdl_t *dtp, int *errp, int err) { if (dtp != NULL) dtrace_close(dtp); if (errp != NULL) *errp = err; return (NULL); } static void dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp) { dt_provmod_t *prov; char path[PATH_MAX]; int fd; #ifdef illumos struct dirent *dp, *ep; DIR *dirp; if ((dirp = opendir(_dtrace_provdir)) == NULL) return; /* failed to open directory; just skip it */ ep = alloca(sizeof (struct dirent) + PATH_MAX + 1); bzero(ep, sizeof (struct dirent) + PATH_MAX + 1); while (readdir_r(dirp, ep, &dp) == 0 && dp != NULL) { if (dp->d_name[0] == '.') continue; /* skip "." and ".." */ if (dfp->df_ents == dfp->df_size) { uint_t size = dfp->df_size ? dfp->df_size * 2 : 16; int *fds = realloc(dfp->df_fds, size * sizeof (int)); if (fds == NULL) break; /* skip the rest of this directory */ dfp->df_fds = fds; dfp->df_size = size; } (void) snprintf(path, sizeof (path), "%s/%s", _dtrace_provdir, dp->d_name); if ((fd = open(path, O_RDONLY)) == -1) continue; /* failed to open driver; just skip it */ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) || (prov->dp_name = malloc(strlen(dp->d_name) + 1)) == NULL) { free(prov); (void) close(fd); break; } (void) strcpy(prov->dp_name, dp->d_name); prov->dp_next = *provmod; *provmod = prov; dt_dprintf("opened provider %s\n", dp->d_name); dfp->df_fds[dfp->df_ents++] = fd; } (void) closedir(dirp); #else /* !illumos */ char *p; char *p1; char *p_providers = NULL; int error; size_t len = 0; /* * Loop to allocate/reallocate memory for the string of provider * names and retry: */ while(1) { /* * The first time around, get the string length. The next time, * hopefully we've allocated enough memory. */ error = sysctlbyname("debug.dtrace.providers",p_providers,&len,NULL,0); if (len == 0) /* No providers? That's strange. Where's dtrace? */ break; else if (error == 0 && p_providers == NULL) { /* * Allocate the initial memory which should be enough * unless another provider loads before we have * time to go back and get the string. */ if ((p_providers = malloc(len)) == NULL) /* How do we report errors here? */ return; } else if (error == -1 && errno == ENOMEM) { /* * The current buffer isn't large enough, so * reallocate it. We normally won't need to do this * because providers aren't being loaded all the time. */ if ((p = realloc(p_providers,len)) == NULL) { free(p_providers); /* How do we report errors here? */ return; } p_providers = p; } else break; } /* Check if we got a string of provider names: */ if (error == 0 && len > 0 && p_providers != NULL) { p = p_providers; /* * Parse the string containing the space separated * provider names. */ while ((p1 = strsep(&p," ")) != NULL) { if (dfp->df_ents == dfp->df_size) { uint_t size = dfp->df_size ? dfp->df_size * 2 : 16; int *fds = realloc(dfp->df_fds, size * sizeof (int)); if (fds == NULL) break; dfp->df_fds = fds; dfp->df_size = size; } (void) snprintf(path, sizeof (path), "/dev/dtrace/%s", p1); if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) continue; /* failed to open driver; just skip it */ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) || (prov->dp_name = malloc(strlen(p1) + 1)) == NULL) { free(prov); (void) close(fd); break; } (void) strcpy(prov->dp_name, p1); prov->dp_next = *provmod; *provmod = prov; dt_dprintf("opened provider %s\n", p1); dfp->df_fds[dfp->df_ents++] = fd; } } if (p_providers != NULL) free(p_providers); #endif /* illumos */ } static void dt_provmod_destroy(dt_provmod_t **provmod) { dt_provmod_t *next, *current; for (current = *provmod; current != NULL; current = next) { next = current->dp_next; free(current->dp_name); free(current); } *provmod = NULL; } #ifdef illumos static const char * dt_get_sysinfo(int cmd, char *buf, size_t len) { ssize_t rv = sysinfo(cmd, buf, len); char *p = buf; if (rv < 0 || rv > len) (void) snprintf(buf, len, "%s", "Unknown"); while ((p = strchr(p, '.')) != NULL) *p++ = '_'; return (buf); } #endif static dtrace_hdl_t * dt_vopen(int version, int flags, int *errp, const dtrace_vector_t *vector, void *arg) { dtrace_hdl_t *dtp = NULL; int dtfd = -1, ftfd = -1, fterr = 0; dtrace_prog_t *pgp; dt_module_t *dmp; dt_provmod_t *provmod = NULL; int i, err; struct rlimit rl; const dt_intrinsic_t *dinp; const dt_typedef_t *dtyp; const dt_ident_t *idp; dtrace_typeinfo_t dtt; ctf_funcinfo_t ctc; ctf_arinfo_t ctr; dt_fdlist_t df = { NULL, 0, 0 }; char isadef[32], utsdef[32]; char s1[64], s2[64]; if (version <= 0) return (set_open_errno(dtp, errp, EINVAL)); if (version > DTRACE_VERSION) return (set_open_errno(dtp, errp, EDT_VERSION)); if (version < DTRACE_VERSION) { /* * Currently, increasing the library version number is used to * denote a binary incompatible change. That is, a consumer * of the library cannot run on a version of the library with * a higher DTRACE_VERSION number than the consumer compiled * against. Once the library API has been committed to, * backwards binary compatibility will be required; at that * time, this check should change to return EDT_OVERSION only * if the specified version number is less than the version * number at the time of interface commitment. */ return (set_open_errno(dtp, errp, EDT_OVERSION)); } if (flags & ~DTRACE_O_MASK) return (set_open_errno(dtp, errp, EINVAL)); if ((flags & DTRACE_O_LP64) && (flags & DTRACE_O_ILP32)) return (set_open_errno(dtp, errp, EINVAL)); if (vector == NULL && arg != NULL) return (set_open_errno(dtp, errp, EINVAL)); if (elf_version(EV_CURRENT) == EV_NONE) return (set_open_errno(dtp, errp, EDT_ELFVERSION)); if (vector != NULL || (flags & DTRACE_O_NODEV)) goto alloc; /* do not attempt to open dtrace device */ /* * Before we get going, crank our limit on file descriptors up to the * hard limit. This is to allow for the fact that libproc keeps file * descriptors to objects open for the lifetime of the proc handle; * without raising our hard limit, we would have an acceptably small * bound on the number of processes that we could concurrently * instrument with the pid provider. */ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rl.rlim_cur = rl.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rl); } /* * Get the device path of each of the providers. We hold them open * in the df.df_fds list until we open the DTrace driver itself, * allowing us to see all of the probes provided on this system. Once * we have the DTrace driver open, we can safely close all the providers * now that they have registered with the framework. */ dt_provmod_open(&provmod, &df); dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC); err = errno; /* save errno from opening dtfd */ #if defined(__FreeBSD__) /* * Automatically load the 'dtraceall' module if we couldn't open the * char device. */ if (err == ENOENT && modfind("dtraceall") < 0) { kldload("dtraceall"); /* ignore the error */ dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC); err = errno; } #endif #ifdef illumos ftfd = open("/dev/dtrace/provider/fasttrap", O_RDWR); #else ftfd = open("/dev/dtrace/fasttrap", O_RDWR | O_CLOEXEC); #endif fterr = ftfd == -1 ? errno : 0; /* save errno from open ftfd */ while (df.df_ents-- != 0) (void) close(df.df_fds[df.df_ents]); free(df.df_fds); /* * If we failed to open the dtrace device, fail dtrace_open(). * We convert some kernel errnos to custom libdtrace errnos to * improve the resulting message from the usual strerror(). */ if (dtfd == -1) { dt_provmod_destroy(&provmod); switch (err) { case ENOENT: err = EDT_NOENT; break; case EBUSY: err = EDT_BUSY; break; case EACCES: err = EDT_ACCESS; break; } return (set_open_errno(dtp, errp, err)); } alloc: if ((dtp = malloc(sizeof (dtrace_hdl_t))) == NULL) { dt_provmod_destroy(&provmod); return (set_open_errno(dtp, errp, EDT_NOMEM)); } bzero(dtp, sizeof (dtrace_hdl_t)); dtp->dt_oflags = flags; #ifdef illumos dtp->dt_prcmode = DT_PROC_STOP_PREINIT; #else dtp->dt_prcmode = DT_PROC_STOP_POSTINIT; #endif dtp->dt_linkmode = DT_LINK_KERNEL; dtp->dt_linktype = DT_LTYP_ELF; dtp->dt_xlatemode = DT_XL_STATIC; dtp->dt_stdcmode = DT_STDC_XA; dtp->dt_encoding = DT_ENCODING_UNSET; dtp->dt_version = version; dtp->dt_fd = dtfd; dtp->dt_ftfd = ftfd; dtp->dt_fterr = fterr; dtp->dt_cdefs_fd = -1; dtp->dt_ddefs_fd = -1; #ifdef illumos dtp->dt_stdout_fd = -1; #else dtp->dt_freopen_fp = NULL; #endif dtp->dt_modbuckets = _dtrace_strbuckets; dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); #ifdef __FreeBSD__ dtp->dt_kmods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); #endif dtp->dt_provbuckets = _dtrace_strbuckets; dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *)); - dt_proc_hash_create(dtp); + dt_proc_init(dtp); dtp->dt_vmax = DT_VERS_LATEST; dtp->dt_cpp_path = strdup(_dtrace_defcpp); dtp->dt_cpp_argv = malloc(sizeof (char *)); dtp->dt_cpp_argc = 1; dtp->dt_cpp_args = 1; dtp->dt_ld_path = strdup(_dtrace_defld); #ifdef __FreeBSD__ dtp->dt_objcopy_path = strdup(_dtrace_defobjcopy); #endif dtp->dt_provmod = provmod; dtp->dt_vector = vector; dtp->dt_varg = arg; dt_dof_init(dtp); (void) uname(&dtp->dt_uts); if (dtp->dt_mods == NULL || dtp->dt_provs == NULL || - dtp->dt_procs == NULL || dtp->dt_ld_path == NULL || + dtp->dt_procs == NULL || dtp->dt_proc_env == NULL || + dtp->dt_ld_path == NULL || dtp->dt_cpp_path == NULL || #ifdef __FreeBSD__ dtp->dt_kmods == NULL || dtp->dt_objcopy_path == NULL || #endif - dtp->dt_cpp_path == NULL || dtp->dt_cpp_argv == NULL) + dtp->dt_cpp_argv == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); for (i = 0; i < DTRACEOPT_MAX; i++) dtp->dt_options[i] = DTRACEOPT_UNSET; dtp->dt_cpp_argv[0] = (char *)strbasename(dtp->dt_cpp_path); #ifdef illumos (void) snprintf(isadef, sizeof (isadef), "-D__SUNW_D_%u", (uint_t)(sizeof (void *) * NBBY)); (void) snprintf(utsdef, sizeof (utsdef), "-D__%s_%s", dt_get_sysinfo(SI_SYSNAME, s1, sizeof (s1)), dt_get_sysinfo(SI_RELEASE, s2, sizeof (s2))); if (dt_cpp_add_arg(dtp, "-D__sun") == NULL || dt_cpp_add_arg(dtp, "-D__unix") == NULL || dt_cpp_add_arg(dtp, "-D__SVR4") == NULL || dt_cpp_add_arg(dtp, "-D__SUNW_D=1") == NULL || dt_cpp_add_arg(dtp, isadef) == NULL || dt_cpp_add_arg(dtp, utsdef) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); #endif if (flags & DTRACE_O_NODEV) bcopy(&_dtrace_conf, &dtp->dt_conf, sizeof (_dtrace_conf)); else if (dt_ioctl(dtp, DTRACEIOC_CONF, &dtp->dt_conf) != 0) return (set_open_errno(dtp, errp, errno)); if (flags & DTRACE_O_LP64) dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_LP64; else if (flags & DTRACE_O_ILP32) dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_ILP32; #ifdef __sparc /* * On SPARC systems, __sparc is always defined for * and __sparcv9 is defined if we are doing a 64-bit compile. */ if (dt_cpp_add_arg(dtp, "-D__sparc") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64 && dt_cpp_add_arg(dtp, "-D__sparcv9") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); #endif #ifdef illumos #ifdef __x86 /* * On x86 systems, __i386 is defined for for 32-bit * compiles and __amd64 is defined for 64-bit compiles. Unlike SPARC, * they are defined exclusive of one another (see PSARC 2004/619). */ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) { if (dt_cpp_add_arg(dtp, "-D__amd64") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } else { if (dt_cpp_add_arg(dtp, "-D__i386") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } #endif #else #if defined(__amd64__) || defined(__i386__) if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) { if (dt_cpp_add_arg(dtp, "-m64") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } else { if (dt_cpp_add_arg(dtp, "-m32") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } #endif #endif if (dtp->dt_conf.dtc_difversion < DIF_VERSION) return (set_open_errno(dtp, errp, EDT_DIFVERS)); if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32) bcopy(_dtrace_ints_32, dtp->dt_ints, sizeof (_dtrace_ints_32)); else bcopy(_dtrace_ints_64, dtp->dt_ints, sizeof (_dtrace_ints_64)); /* * On FreeBSD the kernel module name can't be hard-coded. The * 'kern.bootfile' sysctl value tells us exactly which file is being * used as the kernel. */ #ifndef illumos { char bootfile[MAXPATHLEN]; char *p; int i; size_t len = sizeof(bootfile); /* This call shouldn't fail, but use a default just in case. */ if (sysctlbyname("kern.bootfile", bootfile, &len, NULL, 0) != 0) strlcpy(bootfile, "kernel", sizeof(bootfile)); if ((p = strrchr(bootfile, '/')) != NULL) p++; else p = bootfile; /* * Format the global variables based on the kernel module name. */ snprintf(curthread_str, sizeof(curthread_str), "%s`struct thread *",p); snprintf(intmtx_str, sizeof(intmtx_str), "int(%s`struct mtx *)",p); snprintf(threadmtx_str, sizeof(threadmtx_str), "struct thread *(%s`struct mtx *)",p); snprintf(rwlock_str, sizeof(rwlock_str), "int(%s`struct rwlock *)",p); snprintf(sxlock_str, sizeof(sxlock_str), "int(%s`struct sx *)",p); } #endif dtp->dt_macros = dt_idhash_create("macro", NULL, 0, UINT_MAX); dtp->dt_aggs = dt_idhash_create("aggregation", NULL, DTRACE_AGGVARIDNONE + 1, UINT_MAX); dtp->dt_globals = dt_idhash_create("global", _dtrace_globals, DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX); dtp->dt_tls = dt_idhash_create("thread local", NULL, DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX); if (dtp->dt_macros == NULL || dtp->dt_aggs == NULL || dtp->dt_globals == NULL || dtp->dt_tls == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); /* * Populate the dt_macros identifier hash table by hand: we can't use * the dt_idhash_populate() mechanism because we're not yet compiling * and dtrace_update() needs to immediately reference these idents. */ for (idp = _dtrace_macros; idp->di_name != NULL; idp++) { if (dt_idhash_insert(dtp->dt_macros, idp->di_name, idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr, idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw, idp->di_iarg, 0) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } /* * Update the module list using /system/object and load the values for * the macro variable definitions according to the current process. */ dtrace_update(dtp); /* * Select the intrinsics and typedefs we want based on the data model. * The intrinsics are under "C". The typedefs are added under "D". */ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32) { dinp = _dtrace_intrinsics_32; dtyp = _dtrace_typedefs_32; } else { dinp = _dtrace_intrinsics_64; dtyp = _dtrace_typedefs_64; } /* * Create a dynamic CTF container under the "C" scope for intrinsic * types and types defined in ANSI-C header files that are included. */ if ((dmp = dtp->dt_cdefs = dt_module_create(dtp, "C")) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL) return (set_open_errno(dtp, errp, EDT_CTF)); dt_dprintf("created CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel); ctf_setspecific(dmp->dm_ctfp, dmp); dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */ dmp->dm_modid = -1; /* no module ID */ /* * Fill the dynamic "C" CTF container with all of the intrinsic * integer and floating-point types appropriate for this data model. */ for (; dinp->din_name != NULL; dinp++) { if (dinp->din_kind == CTF_K_INTEGER) { err = ctf_add_integer(dmp->dm_ctfp, CTF_ADD_ROOT, dinp->din_name, &dinp->din_data); } else { err = ctf_add_float(dmp->dm_ctfp, CTF_ADD_ROOT, dinp->din_name, &dinp->din_data); } if (err == CTF_ERR) { dt_dprintf("failed to add %s to C container: %s\n", dinp->din_name, ctf_errmsg( ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } } if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed to update C container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Add intrinsic pointer types that are needed to initialize printf * format dictionary types (see table in dt_printf.c). */ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "void")); (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "char")); (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "int")); if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed to update C container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Create a dynamic CTF container under the "D" scope for types that * are defined by the D program itself or on-the-fly by the D compiler. * The "D" CTF container is a child of the "C" CTF container. */ if ((dmp = dtp->dt_ddefs = dt_module_create(dtp, "D")) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL) return (set_open_errno(dtp, errp, EDT_CTF)); dt_dprintf("created CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel); ctf_setspecific(dmp->dm_ctfp, dmp); dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */ dmp->dm_modid = -1; /* no module ID */ if (ctf_import(dmp->dm_ctfp, dtp->dt_cdefs->dm_ctfp) == CTF_ERR) { dt_dprintf("failed to import D parent container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Fill the dynamic "D" CTF container with all of the built-in typedefs * that we need to use for our D variable and function definitions. * This ensures that basic inttypes.h names are always available to us. */ for (; dtyp->dty_src != NULL; dtyp++) { if (ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, dtyp->dty_dst, ctf_lookup_by_name(dmp->dm_ctfp, dtyp->dty_src)) == CTF_ERR) { dt_dprintf("failed to add typedef %s %s to D " "container: %s", dtyp->dty_src, dtyp->dty_dst, ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } } /* * Insert a CTF ID corresponding to a pointer to a type of kind * CTF_K_FUNCTION we can use in the compiler for function pointers. * CTF treats all function pointers as "int (*)()" so we only need one. */ ctc.ctc_return = ctf_lookup_by_name(dmp->dm_ctfp, "int"); ctc.ctc_argc = 0; ctc.ctc_flags = 0; dtp->dt_type_func = ctf_add_function(dmp->dm_ctfp, CTF_ADD_ROOT, &ctc, NULL); dtp->dt_type_fptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, dtp->dt_type_func); /* * We also insert CTF definitions for the special D intrinsic types * string and into the D container. The string type is added * as a typedef of char[n]. The type is an alias for void. * We compare types to these special CTF ids throughout the compiler. */ ctr.ctr_contents = ctf_lookup_by_name(dmp->dm_ctfp, "char"); ctr.ctr_index = ctf_lookup_by_name(dmp->dm_ctfp, "long"); ctr.ctr_nelems = _dtrace_strsize; dtp->dt_type_str = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "string", ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &ctr)); dtp->dt_type_dyn = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "stack", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_usymaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "_usymaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void")); if (dtp->dt_type_func == CTF_ERR || dtp->dt_type_fptr == CTF_ERR || dtp->dt_type_str == CTF_ERR || dtp->dt_type_dyn == CTF_ERR || dtp->dt_type_stack == CTF_ERR || dtp->dt_type_symaddr == CTF_ERR || dtp->dt_type_usymaddr == CTF_ERR) { dt_dprintf("failed to add intrinsic to D container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed update D container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Initialize the integer description table used to convert integer * constants to the appropriate types. Refer to the comments above * dt_node_int() for a complete description of how this table is used. */ for (i = 0; i < sizeof (dtp->dt_ints) / sizeof (dtp->dt_ints[0]); i++) { if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, dtp->dt_ints[i].did_name, &dtt) != 0) { dt_dprintf("failed to lookup integer type %s: %s\n", dtp->dt_ints[i].did_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); return (set_open_errno(dtp, errp, dtp->dt_errno)); } dtp->dt_ints[i].did_ctfp = dtt.dtt_ctfp; dtp->dt_ints[i].did_type = dtt.dtt_type; } /* * Now that we've created the "C" and "D" containers, move them to the * start of the module list so that these types and symbols are found * first (for stability) when iterating through the module list. */ dt_list_delete(&dtp->dt_modlist, dtp->dt_ddefs); dt_list_prepend(&dtp->dt_modlist, dtp->dt_ddefs); dt_list_delete(&dtp->dt_modlist, dtp->dt_cdefs); dt_list_prepend(&dtp->dt_modlist, dtp->dt_cdefs); if (dt_pfdict_create(dtp) == -1) return (set_open_errno(dtp, errp, dtp->dt_errno)); /* * If we are opening libdtrace DTRACE_O_NODEV enable C_ZDEFS by default * because without /dev/dtrace open, we will not be able to load the * names and attributes of any providers or probes from the kernel. */ if (flags & DTRACE_O_NODEV) dtp->dt_cflags |= DTRACE_C_ZDEFS; /* * Load hard-wired inlines into the definition cache by calling the * compiler on the raw definition string defined above. */ if ((pgp = dtrace_program_strcompile(dtp, _dtrace_hardwire, DTRACE_PROBESPEC_NONE, DTRACE_C_EMPTY, 0, NULL)) == NULL) { dt_dprintf("failed to load hard-wired definitions: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return (set_open_errno(dtp, errp, EDT_HARDWIRE)); } dt_program_destroy(dtp, pgp); /* * Set up the default DTrace library path. Once set, the next call to * dt_compile() will compile all the libraries. We intentionally defer * library processing to improve overhead for clients that don't ever * compile, and to provide better error reporting (because the full * reporting of compiler errors requires dtrace_open() to succeed). */ #ifdef __FreeBSD__ #ifdef __LP64__ if ((dtp->dt_oflags & DTRACE_O_ILP32) != 0) { if (dtrace_setopt(dtp, "libdir", _dtrace_libdir32) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); } #endif if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); #else if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); #endif return (dtp); } dtrace_hdl_t * dtrace_open(int version, int flags, int *errp) { return (dt_vopen(version, flags, errp, NULL, NULL)); } dtrace_hdl_t * dtrace_vopen(int version, int flags, int *errp, const dtrace_vector_t *vector, void *arg) { return (dt_vopen(version, flags, errp, vector, arg)); } void dtrace_close(dtrace_hdl_t *dtp) { dt_ident_t *idp, *ndp; dt_module_t *dmp; dt_provider_t *pvp; dtrace_prog_t *pgp; dt_xlator_t *dxp; dt_dirpath_t *dirp; #ifdef __FreeBSD__ dt_kmodule_t *dkm; uint_t h; #endif int i; if (dtp->dt_procs != NULL) - dt_proc_hash_destroy(dtp); + dt_proc_fini(dtp); while ((pgp = dt_list_next(&dtp->dt_programs)) != NULL) dt_program_destroy(dtp, pgp); while ((dxp = dt_list_next(&dtp->dt_xlators)) != NULL) dt_xlator_destroy(dtp, dxp); dt_free(dtp, dtp->dt_xlatormap); for (idp = dtp->dt_externs; idp != NULL; idp = ndp) { ndp = idp->di_next; dt_ident_destroy(idp); } if (dtp->dt_macros != NULL) dt_idhash_destroy(dtp->dt_macros); if (dtp->dt_aggs != NULL) dt_idhash_destroy(dtp->dt_aggs); if (dtp->dt_globals != NULL) dt_idhash_destroy(dtp->dt_globals); if (dtp->dt_tls != NULL) dt_idhash_destroy(dtp->dt_tls); #ifdef __FreeBSD__ for (h = 0; h < dtp->dt_modbuckets; h++) while ((dkm = dtp->dt_kmods[h]) != NULL) { dtp->dt_kmods[h] = dkm->dkm_next; free(dkm->dkm_name); free(dkm); } #endif while ((dmp = dt_list_next(&dtp->dt_modlist)) != NULL) dt_module_destroy(dtp, dmp); while ((pvp = dt_list_next(&dtp->dt_provlist)) != NULL) dt_provider_destroy(dtp, pvp); if (dtp->dt_fd != -1) (void) close(dtp->dt_fd); if (dtp->dt_ftfd != -1) (void) close(dtp->dt_ftfd); if (dtp->dt_cdefs_fd != -1) (void) close(dtp->dt_cdefs_fd); if (dtp->dt_ddefs_fd != -1) (void) close(dtp->dt_ddefs_fd); #ifdef illumos if (dtp->dt_stdout_fd != -1) (void) close(dtp->dt_stdout_fd); #else if (dtp->dt_freopen_fp != NULL) (void) fclose(dtp->dt_freopen_fp); #endif dt_epid_destroy(dtp); dt_aggid_destroy(dtp); dt_format_destroy(dtp); dt_strdata_destroy(dtp); dt_buffered_destroy(dtp); dt_aggregate_destroy(dtp); dt_pfdict_destroy(dtp); dt_provmod_destroy(&dtp->dt_provmod); dt_dof_fini(dtp); for (i = 1; i < dtp->dt_cpp_argc; i++) free(dtp->dt_cpp_argv[i]); while ((dirp = dt_list_next(&dtp->dt_lib_path)) != NULL) { dt_list_delete(&dtp->dt_lib_path, dirp); free(dirp->dir_path); free(dirp); } free(dtp->dt_cpp_argv); free(dtp->dt_cpp_path); free(dtp->dt_ld_path); #ifdef __FreeBSD__ free(dtp->dt_objcopy_path); #endif free(dtp->dt_mods); #ifdef __FreeBSD__ free(dtp->dt_kmods); #endif free(dtp->dt_provs); free(dtp); } int dtrace_provider_modules(dtrace_hdl_t *dtp, const char **mods, int nmods) { dt_provmod_t *prov; int i = 0; for (prov = dtp->dt_provmod; prov != NULL; prov = prov->dp_next, i++) { if (i < nmods) mods[i] = prov->dp_name; } return (i); } int dtrace_ctlfd(dtrace_hdl_t *dtp) { return (dtp->dt_fd); } Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c (revision 326498) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c (revision 326499) @@ -1,1210 +1,1262 @@ /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* * DTrace Process Control * * This file provides a set of routines that permit libdtrace and its clients * to create and grab process handles using libproc, and to share these handles * between library mechanisms that need libproc access, such as ustack(), and * client mechanisms that need libproc access, such as dtrace(1M) -c and -p. * The library provides several mechanisms in the libproc control layer: * * Reference Counting: The library code and client code can independently grab * the same process handles without interfering with one another. Only when * the reference count drops to zero and the handle is not being cached (see * below for more information on caching) will Prelease() be called on it. * * Handle Caching: If a handle is grabbed PGRAB_RDONLY (e.g. by ustack()) and * the reference count drops to zero, the handle is not immediately released. * Instead, libproc handles are maintained on dph_lrulist in order from most- * recently accessed to least-recently accessed. Idle handles are maintained * until a pre-defined LRU cache limit is exceeded, permitting repeated calls * to ustack() to avoid the overhead of releasing and re-grabbing processes. * * Process Control: For processes that are grabbed for control (~PGRAB_RDONLY) * or created by dt_proc_create(), a control thread is created to provide * callbacks on process exit and symbol table caching on dlopen()s. * * MT-Safety: Libproc is not MT-Safe, so dt_proc_lock() and dt_proc_unlock() * are provided to synchronize access to the libproc handle between libdtrace * code and client code and the control thread's use of the ps_prochandle. * * NOTE: MT-Safety is NOT provided for libdtrace itself, or for use of the * dtrace_proc_grab/dtrace_proc_create mechanisms. Like all exported libdtrace * calls, these are assumed to be MT-Unsafe. MT-Safety is ONLY provided for * synchronization between libdtrace control threads and the client thread. * * The ps_prochandles themselves are maintained along with a dt_proc_t struct * in a hash table indexed by PID. This provides basic locking and reference * counting. The dt_proc_t is also maintained in LRU order on dph_lrulist. * The dph_lrucnt and dph_lrulim count the number of cacheable processes and * the current limit on the number of actively cached entries. * * The control thread for a process establishes breakpoints at the rtld_db * locations of interest, updates mappings and symbol tables at these points, * and handles exec and fork (by always following the parent). The control * thread automatically exits when the process dies or control is lost. * * A simple notification mechanism is provided for libdtrace clients using * dtrace_handle_proc() for notification of PS_UNDEAD or PS_LOST events. If * such an event occurs, the dt_proc_t itself is enqueued on a notification * list and the control thread broadcasts to dph_cv. dtrace_sleep() will wake * up using this condition and will then call the client handler as necessary. */ #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #ifndef illumos #include #include #define SYS_forksys SYS_fork #endif #define IS_SYS_EXEC(w) (w == SYS_execve) #define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_forksys) static dt_bkpt_t * dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data) { struct ps_prochandle *P = dpr->dpr_proc; dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) { dbp->dbp_func = func; dbp->dbp_data = data; dbp->dbp_addr = addr; if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0) dbp->dbp_active = B_TRUE; dt_list_append(&dpr->dpr_bps, dbp); } return (dbp); } static void dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts) { int state = Pstate(dpr->dpr_proc); dt_bkpt_t *dbp, *nbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) { if (delbkpts && dbp->dbp_active && state != PS_LOST && state != PS_UNDEAD) { (void) Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr); } nbp = dt_list_next(dbp); dt_list_delete(&dpr->dpr_bps, dbp); dt_free(dpr->dpr_hdl, dbp); } } static void dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr) { #ifdef illumos const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp; #else unsigned long pc; #endif dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); #ifndef illumos proc_regget(dpr->dpr_proc, REG_PC, &pc); proc_bkptregadj(&pc); #endif for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { #ifdef illumos if (psp->pr_reg[R_PC] == dbp->dbp_addr) break; #else if (pc == dbp->dbp_addr) break; #endif } if (dbp == NULL) { dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n", #ifdef illumos (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]); #else (int)dpr->dpr_pid, pc); #endif return; } dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n", (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits); dbp->dbp_func(dtp, dpr, dbp->dbp_data); (void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr); } static void dt_proc_bpenable(dt_proc_t *dpr) { dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc, dbp->dbp_addr, &dbp->dbp_instr) == 0) dbp->dbp_active = B_TRUE; } dt_dprintf("breakpoints enabled\n"); } static void dt_proc_bpdisable(dt_proc_t *dpr) { dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr) == 0) dbp->dbp_active = B_FALSE; } dt_dprintf("breakpoints disabled\n"); } static void dt_proc_notify(dtrace_hdl_t *dtp, dt_proc_hash_t *dph, dt_proc_t *dpr, const char *msg) { dt_proc_notify_t *dprn = dt_alloc(dtp, sizeof (dt_proc_notify_t)); if (dprn == NULL) { dt_dprintf("failed to allocate notification for %d %s\n", (int)dpr->dpr_pid, msg); } else { dprn->dprn_dpr = dpr; if (msg == NULL) dprn->dprn_errmsg[0] = '\0'; else (void) strlcpy(dprn->dprn_errmsg, msg, sizeof (dprn->dprn_errmsg)); (void) pthread_mutex_lock(&dph->dph_lock); dprn->dprn_next = dph->dph_notify; dph->dph_notify = dprn; (void) pthread_cond_broadcast(&dph->dph_cv); (void) pthread_mutex_unlock(&dph->dph_lock); } } /* * Check to see if the control thread was requested to stop when the victim * process reached a particular event (why) rather than continuing the victim. * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue(). * If 'why' is not set, this function returns immediately and does nothing. */ static void dt_proc_stop(dt_proc_t *dpr, uint8_t why) { assert(DT_MUTEX_HELD(&dpr->dpr_lock)); assert(why != DT_PROC_STOP_IDLE); if (dpr->dpr_stop & why) { dpr->dpr_stop |= DT_PROC_STOP_IDLE; dpr->dpr_stop &= ~why; (void) pthread_cond_broadcast(&dpr->dpr_cv); /* * We disable breakpoints while stopped to preserve the * integrity of the program text for both our own disassembly * and that of the kernel. */ dt_proc_bpdisable(dpr); while (dpr->dpr_stop & DT_PROC_STOP_IDLE) (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); dt_proc_bpenable(dpr); } } /*ARGSUSED*/ static void dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname) { dt_dprintf("pid %d: breakpoint at %s()\n", (int)dpr->dpr_pid, fname); dt_proc_stop(dpr, DT_PROC_STOP_MAIN); } static void dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname) { rd_event_msg_t rdm; rd_err_e err; if ((err = rd_event_getmsg(dpr->dpr_rtld, &rdm)) != RD_OK) { dt_dprintf("pid %d: failed to get %s event message: %s\n", (int)dpr->dpr_pid, evname, rd_errstr(err)); return; } dt_dprintf("pid %d: rtld event %s type=%d state %d\n", (int)dpr->dpr_pid, evname, rdm.type, rdm.u.state); switch (rdm.type) { case RD_DLACTIVITY: if (rdm.u.state != RD_CONSISTENT) break; Pupdate_syms(dpr->dpr_proc); if (dt_pid_create_probes_module(dtp, dpr) != 0) dt_proc_notify(dtp, dtp->dt_procs, dpr, dpr->dpr_errmsg); break; case RD_PREINIT: Pupdate_syms(dpr->dpr_proc); dt_proc_stop(dpr, DT_PROC_STOP_PREINIT); break; case RD_POSTINIT: Pupdate_syms(dpr->dpr_proc); dt_proc_stop(dpr, DT_PROC_STOP_POSTINIT); break; } } static void dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname) { rd_notify_t rdn; rd_err_e err; if ((err = rd_event_addr(dpr->dpr_rtld, event, &rdn)) != RD_OK) { dt_dprintf("pid %d: failed to get event address for %s: %s\n", (int)dpr->dpr_pid, evname, rd_errstr(err)); return; } if (rdn.type != RD_NOTIFY_BPT) { dt_dprintf("pid %d: event %s has unexpected type %d\n", (int)dpr->dpr_pid, evname, rdn.type); return; } (void) dt_proc_bpcreate(dpr, rdn.u.bptaddr, #ifdef illumos (dt_bkpt_f *)dt_proc_rdevent, (void *)evname); #else /* XXX ugly */ (dt_bkpt_f *)dt_proc_rdevent, __DECONST(void *, evname)); #endif } /* * Common code for enabling events associated with the run-time linker after * attaching to a process or after a victim process completes an exec(2). */ static void dt_proc_attach(dt_proc_t *dpr, int exec) { #ifdef illumos const pstatus_t *psp = Pstatus(dpr->dpr_proc); #endif rd_err_e err; GElf_Sym sym; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); if (exec) { #ifdef illumos if (psp->pr_lwp.pr_errno != 0) return; /* exec failed: nothing needs to be done */ #endif dt_proc_bpdestroy(dpr, B_FALSE); #ifdef illumos Preset_maps(dpr->dpr_proc); #endif } if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL && (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) { #ifdef illumos dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT"); #endif dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT"); #ifdef illumos dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY"); #endif } else { dt_dprintf("pid %d: failed to enable rtld events: %s\n", (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) : "rtld_db agent initialization failed"); } Pupdate_maps(dpr->dpr_proc); if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE, "a.out", "main", &sym, NULL) == 0) { (void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value, (dt_bkpt_f *)dt_proc_bpmain, "a.out`main"); } else { dt_dprintf("pid %d: failed to find a.out`main: %s\n", (int)dpr->dpr_pid, strerror(errno)); } } /* * Wait for a stopped process to be set running again by some other debugger. * This is typically not required by /proc-based debuggers, since the usual * model is that one debugger controls one victim. But DTrace, as usual, has * its own needs: the stop() action assumes that prun(1) or some other tool * will be applied to resume the victim process. This could be solved by * adding a PCWRUN directive to /proc, but that seems like overkill unless * other debuggers end up needing this functionality, so we implement a cheap * equivalent to PCWRUN using the set of existing kernel mechanisms. * * Our intent is really not just to wait for the victim to run, but rather to * wait for it to run and then stop again for a reason other than the current * PR_REQUESTED stop. Since PCWSTOP/Pstopstatus() can be applied repeatedly * to a stopped process and will return the same result without affecting the * victim, we can just perform these operations repeatedly until Pstate() * changes, the representative LWP ID changes, or the stop timestamp advances. * dt_proc_control() will then rediscover the new state and continue as usual. * When the process is still stopped in the same exact state, we sleep for a * brief interval before waiting again so as not to spin consuming CPU cycles. */ static void dt_proc_waitrun(dt_proc_t *dpr) { printf("%s:%s(%d): not implemented\n", __FUNCTION__, __FILE__, __LINE__); #ifdef DOODAD struct ps_prochandle *P = dpr->dpr_proc; const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; int krflag = psp->pr_flags & (PR_KLC | PR_RLC); timestruc_t tstamp = psp->pr_tstamp; lwpid_t lwpid = psp->pr_lwpid; const long wstop = PCWSTOP; int pfd = Pctlfd(P); assert(DT_MUTEX_HELD(&dpr->dpr_lock)); assert(psp->pr_flags & PR_STOPPED); assert(Pstate(P) == PS_STOP); /* * While we are waiting for the victim to run, clear PR_KLC and PR_RLC * so that if the libdtrace client is killed, the victim stays stopped. * dt_proc_destroy() will also observe this and perform PRELEASE_HANG. */ (void) Punsetflags(P, krflag); Psync(P); (void) pthread_mutex_unlock(&dpr->dpr_lock); while (!dpr->dpr_quit) { if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR) continue; /* check dpr_quit and continue waiting */ (void) pthread_mutex_lock(&dpr->dpr_lock); (void) Pstopstatus(P, PCNULL, 0); psp = &Pstatus(P)->pr_lwp; /* * If we've reached a new state, found a new representative, or * the stop timestamp has changed, restore PR_KLC/PR_RLC to its * original setting and then return with dpr_lock held. */ if (Pstate(P) != PS_STOP || psp->pr_lwpid != lwpid || bcmp(&psp->pr_tstamp, &tstamp, sizeof (tstamp)) != 0) { (void) Psetflags(P, krflag); Psync(P); return; } (void) pthread_mutex_unlock(&dpr->dpr_lock); (void) poll(NULL, 0, MILLISEC / 2); } (void) pthread_mutex_lock(&dpr->dpr_lock); #endif } typedef struct dt_proc_control_data { dtrace_hdl_t *dpcd_hdl; /* DTrace handle */ dt_proc_t *dpcd_proc; /* proccess to control */ } dt_proc_control_data_t; /* * Main loop for all victim process control threads. We initialize all the * appropriate /proc control mechanisms, and then enter a loop waiting for * the process to stop on an event or die. We process any events by calling * appropriate subroutines, and exit when the victim dies or we lose control. * * The control thread synchronizes the use of dpr_proc with other libdtrace * threads using dpr_lock. We hold the lock for all of our operations except * waiting while the process is running: this is accomplished by writing a * PCWSTOP directive directly to the underlying /proc//ctl file. If the * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used. */ static void * dt_proc_control(void *arg) { dt_proc_control_data_t *datap = arg; dtrace_hdl_t *dtp = datap->dpcd_hdl; dt_proc_t *dpr = datap->dpcd_proc; - dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs; + dt_proc_hash_t *dph = dtp->dt_procs; struct ps_prochandle *P = dpr->dpr_proc; int pid = dpr->dpr_pid; #ifdef illumos int pfd = Pctlfd(P); const long wstop = PCWSTOP; #endif int notify = B_FALSE; /* * We disable the POSIX thread cancellation mechanism so that the * client program using libdtrace can't accidentally cancel our thread. * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit. */ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); /* * Set up the corresponding process for tracing by libdtrace. We want * to be able to catch breakpoints and efficiently single-step over * them, and we need to enable librtld_db to watch libdl activity. */ (void) pthread_mutex_lock(&dpr->dpr_lock); #ifdef illumos (void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */ (void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */ (void) Punsetflags(P, PR_FORK); /* do not inherit on fork */ (void) Pfault(P, FLTBPT, B_TRUE); /* always trace breakpoints */ (void) Pfault(P, FLTTRACE, B_TRUE); /* always trace single-step */ /* * We must trace exit from exec() system calls so that if the exec is * successful, we can reset our breakpoints and re-initialize libproc. */ (void) Psysexit(P, SYS_execve, B_TRUE); /* * We must trace entry and exit for fork() system calls in order to * disable our breakpoints temporarily during the fork. We do not set * the PR_FORK flag, so if fork succeeds the child begins executing and * does not inherit any other tracing behaviors or a control thread. */ (void) Psysentry(P, SYS_vfork, B_TRUE); (void) Psysexit(P, SYS_vfork, B_TRUE); (void) Psysentry(P, SYS_forksys, B_TRUE); (void) Psysexit(P, SYS_forksys, B_TRUE); Psync(P); /* enable all /proc changes */ #endif dt_proc_attach(dpr, B_FALSE); /* enable rtld breakpoints */ /* * If PR_KLC is set, we created the process; otherwise we grabbed it. * Check for an appropriate stop request and wait for dt_proc_continue. */ #ifdef illumos if (Pstatus(P)->pr_flags & PR_KLC) #else if (proc_getflags(P) & PR_KLC) #endif dt_proc_stop(dpr, DT_PROC_STOP_CREATE); else dt_proc_stop(dpr, DT_PROC_STOP_GRAB); if (Psetrun(P, 0, 0) == -1) { dt_dprintf("pid %d: failed to set running: %s\n", (int)dpr->dpr_pid, strerror(errno)); } (void) pthread_mutex_unlock(&dpr->dpr_lock); /* * Wait for the process corresponding to this control thread to stop, * process the event, and then set it running again. We want to sleep * with dpr_lock *unheld* so that other parts of libdtrace can use the * ps_prochandle in the meantime (e.g. ustack()). To do this, we write * a PCWSTOP directive directly to the underlying /proc//ctl file. * Once the process stops, we wake up, grab dpr_lock, and then call * Pwait() (which will return immediately) and do our processing. */ while (!dpr->dpr_quit) { const lwpstatus_t *psp; #ifdef illumos if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR) continue; /* check dpr_quit and continue waiting */ #else /* Wait for the process to report status. */ proc_wstatus(P); if (errno == EINTR) continue; /* check dpr_quit and continue waiting */ #endif (void) pthread_mutex_lock(&dpr->dpr_lock); #ifdef illumos pwait_locked: if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) { (void) pthread_mutex_unlock(&dpr->dpr_lock); continue; /* check dpr_quit and continue waiting */ } #endif switch (Pstate(P)) { case PS_STOP: #ifdef illumos psp = &Pstatus(P)->pr_lwp; #else psp = proc_getlwpstatus(P); #endif dt_dprintf("pid %d: proc stopped showing %d/%d\n", pid, psp->pr_why, psp->pr_what); /* * If the process stops showing PR_REQUESTED, then the * DTrace stop() action was applied to it or another * debugging utility (e.g. pstop(1)) asked it to stop. * In either case, the user's intention is for the * process to remain stopped until another external * mechanism (e.g. prun(1)) is applied. So instead of * setting the process running ourself, we wait for * someone else to do so. Once that happens, we return * to our normal loop waiting for an event of interest. */ if (psp->pr_why == PR_REQUESTED) { dt_proc_waitrun(dpr); (void) pthread_mutex_unlock(&dpr->dpr_lock); continue; } /* * If the process stops showing one of the events that * we are tracing, perform the appropriate response. * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and * PR_JOBCONTROL by design: if one of these conditions * occurs, we will fall through to Psetrun() but the * process will remain stopped in the kernel by the * corresponding mechanism (e.g. job control stop). */ if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT) dt_proc_bpmatch(dtp, dpr); else if (psp->pr_why == PR_SYSENTRY && IS_SYS_FORK(psp->pr_what)) dt_proc_bpdisable(dpr); else if (psp->pr_why == PR_SYSEXIT && IS_SYS_FORK(psp->pr_what)) dt_proc_bpenable(dpr); else if (psp->pr_why == PR_SYSEXIT && IS_SYS_EXEC(psp->pr_what)) dt_proc_attach(dpr, B_TRUE); break; case PS_LOST: #ifdef illumos if (Preopen(P) == 0) goto pwait_locked; #endif dt_dprintf("pid %d: proc lost: %s\n", pid, strerror(errno)); dpr->dpr_quit = B_TRUE; notify = B_TRUE; break; case PS_UNDEAD: dt_dprintf("pid %d: proc died\n", pid); dpr->dpr_quit = B_TRUE; notify = B_TRUE; break; } if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) { dt_dprintf("pid %d: failed to set running: %s\n", (int)dpr->dpr_pid, strerror(errno)); } (void) pthread_mutex_unlock(&dpr->dpr_lock); } /* * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue * the dt_proc_t structure on the dt_proc_hash_t notification list. */ if (notify) dt_proc_notify(dtp, dph, dpr, NULL); /* * Destroy and remove any remaining breakpoints, set dpr_done and clear * dpr_tid to indicate the control thread has exited, and notify any * waiting thread in dt_proc_destroy() that we have succesfully exited. */ (void) pthread_mutex_lock(&dpr->dpr_lock); dt_proc_bpdestroy(dpr, B_TRUE); dpr->dpr_done = B_TRUE; dpr->dpr_tid = 0; (void) pthread_cond_broadcast(&dpr->dpr_cv); (void) pthread_mutex_unlock(&dpr->dpr_lock); return (NULL); } /*PRINTFLIKE3*/ static struct ps_prochandle * dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...) { va_list ap; va_start(ap, format); dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); va_end(ap); if (dpr->dpr_proc != NULL) Prelease(dpr->dpr_proc, 0); dt_free(dtp, dpr); (void) dt_set_errno(dtp, EDT_COMPILER); return (NULL); } dt_proc_t * dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove) { dt_proc_hash_t *dph = dtp->dt_procs; #ifdef illumos pid_t pid = Pstatus(P)->pr_pid; #else pid_t pid = proc_getpid(P); #endif dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)]; for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) { if (dpr->dpr_pid == pid) break; else dpp = &dpr->dpr_hash; } assert(dpr != NULL); assert(dpr->dpr_proc == P); if (remove) *dpp = dpr->dpr_hash; /* remove from pid hash chain */ return (dpr); } static void dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_notify_t *npr, **npp; int rflag; assert(dpr != NULL); /* * If neither PR_KLC nor PR_RLC is set, then the process is stopped by * an external debugger and we were waiting in dt_proc_waitrun(). * Leave the process in this condition using PRELEASE_HANG. */ #ifdef illumos if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) { #else if (!(proc_getflags(dpr->dpr_proc) & (PR_KLC | PR_RLC))) { #endif dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid); rflag = PRELEASE_HANG; #ifdef illumos } else if (Pstatus(dpr->dpr_proc)->pr_flags & PR_KLC) { #else } else if (proc_getflags(dpr->dpr_proc) & PR_KLC) { #endif dt_dprintf("killing pid %d\n", (int)dpr->dpr_pid); rflag = PRELEASE_KILL; /* apply kill-on-last-close */ } else { dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid); rflag = 0; /* apply run-on-last-close */ } if (dpr->dpr_tid) { /* * Set the dpr_quit flag to tell the daemon thread to exit. We * send it a SIGCANCEL to poke it out of PCWSTOP or any other * long-term /proc system call. Our daemon threads have POSIX * cancellation disabled, so EINTR will be the only effect. We * then wait for dpr_done to indicate the thread has exited. * * We can't use pthread_kill() to send SIGCANCEL because the * interface forbids it and we can't use pthread_cancel() * because with cancellation disabled it won't actually * send SIGCANCEL to the target thread, so we use _lwp_kill() * to do the job. This is all built on evil knowledge of * the details of the cancellation mechanism in libc. */ (void) pthread_mutex_lock(&dpr->dpr_lock); dpr->dpr_quit = B_TRUE; #ifdef illumos (void) _lwp_kill(dpr->dpr_tid, SIGCANCEL); #else pthread_kill(dpr->dpr_tid, SIGTHR); #endif /* * If the process is currently idling in dt_proc_stop(), re- * enable breakpoints and poke it into running again. */ if (dpr->dpr_stop & DT_PROC_STOP_IDLE) { dt_proc_bpenable(dpr); dpr->dpr_stop &= ~DT_PROC_STOP_IDLE; (void) pthread_cond_broadcast(&dpr->dpr_cv); } while (!dpr->dpr_done) (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); (void) pthread_mutex_unlock(&dpr->dpr_lock); } /* * Before we free the process structure, remove this dt_proc_t from the * lookup hash, and then walk the dt_proc_hash_t's notification list * and remove this dt_proc_t if it is enqueued. */ (void) pthread_mutex_lock(&dph->dph_lock); (void) dt_proc_lookup(dtp, P, B_TRUE); npp = &dph->dph_notify; while ((npr = *npp) != NULL) { if (npr->dprn_dpr == dpr) { *npp = npr->dprn_next; dt_free(dtp, npr); } else { npp = &npr->dprn_next; } } (void) pthread_mutex_unlock(&dph->dph_lock); /* * Remove the dt_proc_list from the LRU list, release the underlying * libproc handle, and free our dt_proc_t data structure. */ if (dpr->dpr_cacheable) { assert(dph->dph_lrucnt != 0); dph->dph_lrucnt--; } dt_list_delete(&dph->dph_lrulist, dpr); Prelease(dpr->dpr_proc, rflag); dt_free(dtp, dpr); } static int dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop) { dt_proc_control_data_t data; sigset_t nset, oset; pthread_attr_t a; int err; (void) pthread_mutex_lock(&dpr->dpr_lock); dpr->dpr_stop |= stop; /* set bit for initial rendezvous */ (void) pthread_attr_init(&a); (void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); (void) sigfillset(&nset); (void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */ #ifdef illumos (void) sigdelset(&nset, SIGCANCEL); /* see dt_proc_destroy() */ #else (void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */ #endif data.dpcd_hdl = dtp; data.dpcd_proc = dpr; (void) pthread_sigmask(SIG_SETMASK, &nset, &oset); err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data); (void) pthread_sigmask(SIG_SETMASK, &oset, NULL); /* * If the control thread was created, then wait on dpr_cv for either * dpr_done to be set (the victim died or the control thread failed) * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now * stopped by /proc and the control thread is at the rendezvous event. * On success, we return with the process and control thread stopped: * the caller can then apply dt_proc_continue() to resume both. */ if (err == 0) { while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE)) (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); /* * If dpr_done is set, the control thread aborted before it * reached the rendezvous event. This is either due to PS_LOST * or PS_UNDEAD (i.e. the process died). We try to provide a * small amount of useful information to help figure it out. */ if (dpr->dpr_done) { #ifdef illumos const psinfo_t *prp = Ppsinfo(dpr->dpr_proc); int stat = prp ? prp->pr_wstat : 0; int pid = dpr->dpr_pid; #else int stat = proc_getwstat(dpr->dpr_proc); int pid = proc_getpid(dpr->dpr_proc); #endif if (proc_state(dpr->dpr_proc) == PS_LOST) { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process exec'd " "set-id or unobservable program\n", pid); } else if (WIFSIGNALED(stat)) { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process died " "from signal %d\n", pid, WTERMSIG(stat)); } else { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process exited " "with status %d\n", pid, WEXITSTATUS(stat)); } err = ESRCH; /* cause grab() or create() to fail */ } } else { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to create control thread for process-id %d: %s\n", (int)dpr->dpr_pid, strerror(err)); } if (err == 0) (void) pthread_mutex_unlock(&dpr->dpr_lock); (void) pthread_attr_destroy(&a); return (err); } struct ps_prochandle * dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv, proc_child_func *pcf, void *child_arg) { dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_t *dpr; int err; if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); #ifdef illumos - if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) { + dpr->dpr_proc = Pxcreate(file, argv, dtp->dt_proc_env, &err, NULL, 0); + if (dpr->dpr_proc == NULL) { + return (dt_proc_error(dtp, dpr, + "failed to execute %s: %s\n", file, Pcreate_error(err))); + } #else - if ((err = proc_create(file, argv, NULL, pcf, child_arg, + if ((err = proc_create(file, argv, dtp->dt_proc_env, pcf, child_arg, &dpr->dpr_proc)) != 0) { -#endif return (dt_proc_error(dtp, dpr, "failed to execute %s: %s\n", file, Pcreate_error(err))); } +#endif dpr->dpr_hdl = dtp; #ifdef illumos dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid; #else dpr->dpr_pid = proc_getpid(dpr->dpr_proc); #endif (void) Punsetflags(dpr->dpr_proc, PR_RLC); (void) Psetflags(dpr->dpr_proc, PR_KLC); if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0) return (NULL); /* dt_proc_error() has been called for us */ dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)]; dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr; dt_list_prepend(&dph->dph_lrulist, dpr); dt_dprintf("created pid %d\n", (int)dpr->dpr_pid); dpr->dpr_refs++; return (dpr->dpr_proc); } struct ps_prochandle * dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor) { dt_proc_hash_t *dph = dtp->dt_procs; uint_t h = pid & (dph->dph_hashlen - 1); dt_proc_t *dpr, *opr; int err; /* * Search the hash table for the pid. If it is already grabbed or * created, move the handle to the front of the lrulist, increment * the reference count, and return the existing ps_prochandle. */ for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) { if (dpr->dpr_pid == pid && !dpr->dpr_stale) { /* * If the cached handle was opened read-only and * this request is for a writeable handle, mark * the cached handle as stale and open a new handle. * Since it's stale, unmark it as cacheable. */ if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) { dt_dprintf("upgrading pid %d\n", (int)pid); dpr->dpr_stale = B_TRUE; dpr->dpr_cacheable = B_FALSE; dph->dph_lrucnt--; break; } dt_dprintf("grabbed pid %d (cached)\n", (int)pid); dt_list_delete(&dph->dph_lrulist, dpr); dt_list_prepend(&dph->dph_lrulist, dpr); dpr->dpr_refs++; return (dpr->dpr_proc); } } if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); #ifdef illumos if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) { #else if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) { #endif return (dt_proc_error(dtp, dpr, "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err))); } dpr->dpr_hdl = dtp; dpr->dpr_pid = pid; (void) Punsetflags(dpr->dpr_proc, PR_KLC); (void) Psetflags(dpr->dpr_proc, PR_RLC); /* * If we are attempting to grab the process without a monitor * thread, then mark the process cacheable only if it's being * grabbed read-only. If we're currently caching more process * handles than dph_lrulim permits, attempt to find the * least-recently-used handle that is currently unreferenced and * release it from the cache. Otherwise we are grabbing the process * for control: create a control thread for this process and store * its ID in dpr->dpr_tid. */ if (nomonitor || (flags & PGRAB_RDONLY)) { if (dph->dph_lrucnt >= dph->dph_lrulim) { for (opr = dt_list_prev(&dph->dph_lrulist); opr != NULL; opr = dt_list_prev(opr)) { if (opr->dpr_cacheable && opr->dpr_refs == 0) { dt_proc_destroy(dtp, opr->dpr_proc); break; } } } if (flags & PGRAB_RDONLY) { dpr->dpr_cacheable = B_TRUE; dpr->dpr_rdonly = B_TRUE; dph->dph_lrucnt++; } } else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0) return (NULL); /* dt_proc_error() has been called for us */ dpr->dpr_hash = dph->dph_hash[h]; dph->dph_hash[h] = dpr; dt_list_prepend(&dph->dph_lrulist, dpr); dt_dprintf("grabbed pid %d\n", (int)pid); dpr->dpr_refs++; return (dpr->dpr_proc); } void dt_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); dt_proc_hash_t *dph = dtp->dt_procs; assert(dpr != NULL); assert(dpr->dpr_refs != 0); if (--dpr->dpr_refs == 0 && (!dpr->dpr_cacheable || dph->dph_lrucnt > dph->dph_lrulim)) dt_proc_destroy(dtp, P); } void dt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); (void) pthread_mutex_lock(&dpr->dpr_lock); if (dpr->dpr_stop & DT_PROC_STOP_IDLE) { dpr->dpr_stop &= ~DT_PROC_STOP_IDLE; (void) pthread_cond_broadcast(&dpr->dpr_cv); } (void) pthread_mutex_unlock(&dpr->dpr_lock); } void dt_proc_lock(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); int err = pthread_mutex_lock(&dpr->dpr_lock); assert(err == 0); /* check for recursion */ } void dt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); int err = pthread_mutex_unlock(&dpr->dpr_lock); assert(err == 0); /* check for unheld lock */ } void -dt_proc_hash_create(dtrace_hdl_t *dtp) +dt_proc_init(dtrace_hdl_t *dtp) { + extern char **environ; + static char *envdef[] = { + "LD_NOLAZYLOAD=1", /* linker lazy loading hides funcs */ + NULL + }; + char **p; + int i; + if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) + - sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) != NULL) { + sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) == NULL) + return; - (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL); - (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL); + (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL); + (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL); - dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets; - dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim; + dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets; + dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim; + + /* + * Count how big our environment needs to be. + */ + for (i = 1, p = environ; *p != NULL; i++, p++) + continue; + for (p = envdef; *p != NULL; i++, p++) + continue; + + if ((dtp->dt_proc_env = dt_zalloc(dtp, sizeof (char *) * i)) == NULL) + return; + + for (i = 0, p = environ; *p != NULL; i++, p++) { + if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL) + goto err; } + for (p = envdef; *p != NULL; i++, p++) { + if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL) + goto err; + } + + return; + +err: + while (--i != 0) { + dt_free(dtp, dtp->dt_proc_env[i]); + } + dt_free(dtp, dtp->dt_proc_env); + dtp->dt_proc_env = NULL; } void -dt_proc_hash_destroy(dtrace_hdl_t *dtp) +dt_proc_fini(dtrace_hdl_t *dtp) { dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_t *dpr; + char **p; while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL) dt_proc_destroy(dtp, dpr->dpr_proc); dtp->dt_procs = NULL; dt_free(dtp, dph); + + for (p = dtp->dt_proc_env; *p != NULL; p++) + dt_free(dtp, *p); + + dt_free(dtp, dtp->dt_proc_env); + dtp->dt_proc_env = NULL; } struct ps_prochandle * dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv, proc_child_func *pcf, void *child_arg) { dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg); if (P != NULL && idp != NULL && idp->di_id == 0) { #ifdef illumos idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */ #else idp->di_id = proc_getpid(P); /* $target = created pid */ #endif } return (P); } struct ps_prochandle * dtrace_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags) { dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); struct ps_prochandle *P = dt_proc_grab(dtp, pid, flags, 0); if (P != NULL && idp != NULL && idp->di_id == 0) idp->di_id = pid; /* $target = grabbed pid */ return (P); } void dtrace_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_release(dtp, P); } void dtrace_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_continue(dtp, P); } Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h (revision 326498) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h (revision 326499) @@ -1,116 +1,118 @@ /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + #ifndef _DT_PROC_H #define _DT_PROC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct dt_proc { dt_list_t dpr_list; /* prev/next pointers for lru chain */ struct dt_proc *dpr_hash; /* next pointer for pid hash chain */ dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */ struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */ char dpr_errmsg[BUFSIZ]; /* error message */ rd_agent_t *dpr_rtld; /* rtld handle for librtld_db calls */ pthread_mutex_t dpr_lock; /* lock for manipulating dpr_hdl */ pthread_cond_t dpr_cv; /* cond for dpr_stop/quit/done */ pid_t dpr_pid; /* pid of process */ uint_t dpr_refs; /* reference count */ uint8_t dpr_cacheable; /* cache handle using lru list */ uint8_t dpr_stop; /* stop mask: see flag bits below */ uint8_t dpr_quit; /* quit flag: ctl thread should quit */ uint8_t dpr_done; /* done flag: ctl thread has exited */ uint8_t dpr_usdt; /* usdt flag: usdt initialized */ uint8_t dpr_stale; /* proc flag: been deprecated */ uint8_t dpr_rdonly; /* proc flag: opened read-only */ pthread_t dpr_tid; /* control thread (or zero if none) */ dt_list_t dpr_bps; /* list of dt_bkpt_t structures */ } dt_proc_t; typedef struct dt_proc_notify { dt_proc_t *dprn_dpr; /* process associated with the event */ char dprn_errmsg[BUFSIZ]; /* error message */ struct dt_proc_notify *dprn_next; /* next pointer */ } dt_proc_notify_t; #define DT_PROC_STOP_IDLE 0x01 /* idle on owner's stop request */ #define DT_PROC_STOP_CREATE 0x02 /* wait on dpr_cv at process exec */ #define DT_PROC_STOP_GRAB 0x04 /* wait on dpr_cv at process grab */ #define DT_PROC_STOP_PREINIT 0x08 /* wait on dpr_cv at rtld preinit */ #define DT_PROC_STOP_POSTINIT 0x10 /* wait on dpr_cv at rtld postinit */ #define DT_PROC_STOP_MAIN 0x20 /* wait on dpr_cv at a.out`main() */ typedef void dt_bkpt_f(dtrace_hdl_t *, dt_proc_t *, void *); typedef struct dt_bkpt { dt_list_t dbp_list; /* prev/next pointers for bkpt list */ dt_bkpt_f *dbp_func; /* callback function to execute */ void *dbp_data; /* callback function private data */ uintptr_t dbp_addr; /* virtual address of breakpoint */ ulong_t dbp_instr; /* saved instruction from breakpoint */ ulong_t dbp_hits; /* count of breakpoint hits for debug */ int dbp_active; /* flag indicating breakpoint is on */ } dt_bkpt_t; typedef struct dt_proc_hash { pthread_mutex_t dph_lock; /* lock protecting dph_notify list */ pthread_cond_t dph_cv; /* cond for waiting for dph_notify */ dt_proc_notify_t *dph_notify; /* list of pending proc notifications */ dt_list_t dph_lrulist; /* list of dt_proc_t's in lru order */ uint_t dph_lrulim; /* limit on number of procs to hold */ uint_t dph_lrucnt; /* count of cached process handles */ uint_t dph_hashlen; /* size of hash chains array */ dt_proc_t *dph_hash[1]; /* hash chains array */ } dt_proc_hash_t; extern struct ps_prochandle *dt_proc_create(dtrace_hdl_t *, const char *, char *const *, proc_child_func *, void *); extern struct ps_prochandle *dt_proc_grab(dtrace_hdl_t *, pid_t, int, int); extern void dt_proc_release(dtrace_hdl_t *, struct ps_prochandle *); extern void dt_proc_continue(dtrace_hdl_t *, struct ps_prochandle *); extern void dt_proc_lock(dtrace_hdl_t *, struct ps_prochandle *); extern void dt_proc_unlock(dtrace_hdl_t *, struct ps_prochandle *); extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, struct ps_prochandle *, int); -extern void dt_proc_hash_create(dtrace_hdl_t *); -extern void dt_proc_hash_destroy(dtrace_hdl_t *); +extern void dt_proc_init(dtrace_hdl_t *); +extern void dt_proc_fini(dtrace_hdl_t *); #ifdef __cplusplus } #endif #endif /* _DT_PROC_H */ Index: head/cddl/usr.sbin/dtrace/tests/common/Makefile =================================================================== --- head/cddl/usr.sbin/dtrace/tests/common/Makefile (revision 326498) +++ head/cddl/usr.sbin/dtrace/tests/common/Makefile (revision 326499) @@ -1,90 +1,91 @@ # $FreeBSD$ # We exclude several subdirectories: nfs and sysevent do not compile on # FreeBSD, and docsExamples doesn't seem amenable to automated testing. TESTSDIR= ${TESTSBASE}/cddl/usr.sbin/dtrace/common TESTS_SUBDIRS+= aggs \ arithmetic \ arrays \ assocs \ begin \ bitfields \ buffering \ builtinvar \ cg \ clauses \ cpc \ decls \ drops \ dtraceUtil \ end \ + env \ enum \ error \ exit \ fbtprovider \ funcs \ grammar \ include \ inline \ io \ ip \ java_api \ json \ lexer \ llquantize \ mdb \ mib \ misc \ multiaggs \ offsetof \ operators \ pid \ plockstat \ pointers \ pragma \ predicates \ preprocessor \ print \ printa \ printf \ privs \ probes \ proc \ profile-n \ providers \ raise \ rates \ safety \ scalars \ sched \ scripting \ sdt \ sizeof \ speculation \ stability \ stack \ stackdepth \ stop \ strlen \ strtoll \ struct \ sugar \ syscall \ tick-n \ trace \ tracemem \ translators \ typedef \ types \ uctf \ union \ usdt \ ustack \ vars \ version \ .PATH: ${.CURDIR:H:H:H:H:H}/tests KYUAFILE= YES .include Index: head/cddl/usr.sbin/dtrace/tests/common/probes/Makefile =================================================================== --- head/cddl/usr.sbin/dtrace/tests/common/probes/Makefile (revision 326498) +++ head/cddl/usr.sbin/dtrace/tests/common/probes/Makefile (revision 326499) @@ -1,39 +1,38 @@ # $FreeBSD$ # # This Makefile was generated by $srcdir/cddl/usr.sbin/dtrace/tests/tools/genmakefiles.sh. # PACKAGE= tests ${PACKAGE}FILES= \ err.D_PDESC_ZERO.probeqtn.d \ err.D_PDESC_ZERO.probestar.d \ err.D_PDESC_ZERO.tickstar.d \ err.D_SYNTAX.assign.d \ err.D_SYNTAX.declare.d \ err.D_SYNTAX.declarein.d \ err.D_SYNTAX.lbraces.d \ err.D_SYNTAX.probespec.d \ err.D_SYNTAX.rbraces.d \ err.D_SYNTAX.recdec.d \ tst.basic1.d \ tst.check.d \ tst.declare.d \ tst.declareafter.d \ tst.emptyprobe.d \ tst.pragma.d \ tst.pragmaaftertab.d \ tst.pragmainside.d \ tst.pragmaoutside.d \ tst.probestar.d \ TESTEXES= \ CFILES= \ tst.probestar.c \ - .include "../../dtrace.test.mk" Index: head/cddl/usr.sbin/dtrace/tests/common/speculation/Makefile =================================================================== --- head/cddl/usr.sbin/dtrace/tests/common/speculation/Makefile (revision 326498) +++ head/cddl/usr.sbin/dtrace/tests/common/speculation/Makefile (revision 326499) @@ -1,78 +1,77 @@ # $FreeBSD$ # # This Makefile was generated by $srcdir/cddl/usr.sbin/dtrace/tests/tools/genmakefiles.sh. # PACKAGE= tests ${PACKAGE}FILES= \ bug.1001148.SpecSizeVariations.d \ err.BufSizeVariations1.d \ err.BufSizeVariations2.d \ err.D_ACT_SPEC.SpeculateWithBreakPoint.d \ err.D_ACT_SPEC.SpeculateWithChill.d \ err.D_ACT_SPEC.SpeculateWithCopyOut.d \ err.D_ACT_SPEC.SpeculateWithCopyOutStr.d \ err.D_ACT_SPEC.SpeculateWithPanic.d \ err.D_ACT_SPEC.SpeculateWithRaise.d \ err.D_ACT_SPEC.SpeculateWithStop.d \ err.D_AGG_COMM.AggAftCommit.d \ err.D_AGG_SPEC.SpeculateWithAvg.d \ err.D_AGG_SPEC.SpeculateWithCount.d \ err.D_AGG_SPEC.SpeculateWithLquant.d \ err.D_AGG_SPEC.SpeculateWithMax.d \ err.D_AGG_SPEC.SpeculateWithMin.d \ err.D_AGG_SPEC.SpeculateWithQuant.d \ err.D_AGG_SPEC.SpeculateWithStddev.d \ err.D_AGG_SPEC.SpeculateWithSum.d \ err.D_COMM_COMM.CommitAftCommit.d \ err.D_COMM_COMM.DisjointCommit.d \ err.D_COMM_DREC.CommitAftDataRec.d \ err.D_DREC_COMM.DataRecAftCommit.d \ err.D_DREC_COMM.ExitAfterCommit.d \ err.D_EXIT_SPEC.ExitAftSpec.d \ err.D_PRAGMA_MALFORM.NspecExpr.d \ err.D_PRAGMA_OPTSET.HugeNspecValue.d \ err.D_PRAGMA_OPTSET.InvalidSpecSize.d \ err.D_PRAGMA_OPTSET.NegSpecSize.d \ err.D_PROTO_LEN.SpecNoId.d \ err.D_SPEC_COMM.SpecAftCommit.d \ err.D_SPEC_DREC.SpecAftDataRec.d \ err.D_SPEC_SPEC.SpecAftSpec.d \ err.NegativeBufSize.d \ err.NegativeNspec.d \ err.NegativeSpecSize.d \ err.SpecSizeVariations1.d \ err.SpecSizeVariations2.d \ tst.CommitAfterDiscard.d \ tst.CommitWithZero.d \ tst.DataRecAftDiscard.d \ tst.DiscardAftCommit.d \ tst.DiscardAftDataRec.d \ tst.DiscardAftDiscard.d \ tst.DiscardWithZero.d \ tst.ExitAftDiscard.d \ tst.NoSpecBuffer.d \ tst.SpecSizeVariations1.d \ tst.SpecSizeVariations2.d \ tst.SpecSizeVariations3.d \ tst.SpeculateWithRandom.d \ tst.SpeculationCommit.d \ tst.SpeculationDiscard.d \ tst.SpeculationID.d \ tst.SpeculationWithZero.d \ tst.TwoSpecBuffers.d \ tst.negcommit.d \ tst.negspec.d \ tst.zerosize.d \ TESTEXES= \ tst.NoSpecBuffer.exe \ - CFILES= \ .include "../../dtrace.test.mk" Index: head/etc/mtree/BSD.tests.dist =================================================================== --- head/etc/mtree/BSD.tests.dist (revision 326498) +++ head/etc/mtree/BSD.tests.dist (revision 326499) @@ -1,766 +1,768 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin cat .. chflags .. chmod .. date .. dd .. echo .. expr .. ln .. ls .. mkdir .. mv .. pax .. pkill .. pwait .. rmdir .. sh builtins .. errors .. execution .. expansion .. invocation .. parameters .. parser .. set-e .. .. sleep .. test .. .. cddl lib .. sbin .. usr.bin ctfconvert .. .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. + env + .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. .. zfsd .. .. .. etc rc.d .. .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. libarchive .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcam .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libkvm .. libmp .. libnv .. libproc .. librt .. libsbuf .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-sh .. .. rtld-elf .. .. sbin dhclient .. devd .. growfs .. ifconfig .. mdconfig .. pfctl files .. .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. plain .. tap .. .. .. zoneinfo .. .. sys acl .. aio .. fifo .. file .. fs tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. nop .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. portacl .. .. mqueue .. netinet .. netipsec tunnel .. .. netpfil pf .. .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. utimensat .. .. posixshm .. sys .. vfs .. vm .. .. usr.bin apply .. basename .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. compress .. cpio .. col .. comm .. csplit .. cut .. diff .. dirname .. du .. file2c .. fold .. getconf .. grep .. gzip .. head .. hexdump .. ident .. indent .. join .. jot .. lastcomm .. limits .. m4 .. mkimg .. ncal .. opensm .. pr .. printf .. procstat .. rs .. sdiff .. sed regress.multitest.out .. .. soelim .. stat .. tail .. tar .. timeout .. tr .. truncate .. units .. uudecode .. uuencode .. uniq .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. etcupdate .. extattr .. fstyp .. makefs .. newsyslog .. nmtree .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: