Dtrace: improve handling of library paths.

Merge changes from illumos

906 dtrace depends_on pragma should search all library paths, not just the
current one

949 dtrace should only include the first instance of a library found on
its library path

Illumos Revisions:	13353:936a1e45726c
			13354:2b2c36a81512

Reference:
https://www.illumos.org/issues/906
https://www.illumos.org/issues/949

Tested by:	Fabian Keil
Obtained from:	Illumos
MFC after:	3 weeks
This commit is contained in:
Pedro F. Giffuni 2012-07-17 19:57:34 +00:00
commit 694a0093a7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238558
4 changed files with 254 additions and 22 deletions

View File

@ -0,0 +1,76 @@
#
# 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) 2011, Joyent Inc. All rights reserved.
# Use is subject to license terms.
#
#
# This test verifies that we only use the first entry of a file with a given
# name in the library path
#
if [ $# != 1 ]; then
echo expected one argument: '<'dtrace-path'>'
exit 2
fi
firstinc=${TMPDIR:-/tmp}/firstinc.$$
secondinc=${TMPDIR:-/tmp}/secondinc.$$
expexit=23
setup_include()
{
mkdir $firstinc
mkdir $secondinc
cat > $firstinc/lib.d <<EOF
inline int foobar = $expexit;
#pragma D binding "1.0" foobar
EOF
cat > $secondinc/lib.d <<EOF
inline int foobar = 42;
#pragma D binding "1.0" foobar
EOF
}
clean()
{
rm -rf $firstinc
rm -rf $secondinc
}
fail()
{
echo "$@"
clean
exit 1
}
setup_include
dtrace -L$firstinc -L$secondinc -e -n 'BEGIN{ exit(foobar) }'
[[ $? != 0 ]] && fail "Failed to compile with same file in include path twice"
dtrace -L$firstinc -L$secondinc -n 'BEGIN{ exit(foobar) }'
status=$?
[[ $status != $expexit ]] && fail "Exited with unexpected status code: $status"
clean
exit 0

View File

@ -0,0 +1,76 @@
#
# 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) 2011, Joyent Inc. All rights reserved.
# Use is subject to license terms.
#
#
# Test to catch that we properly look for libraries dependencies in
# our full library parth
#
if [ $# != 1 ]; then
echo expected one argument: '<'dtrace-path'>'
exit 2
fi
libdira=${TMPDIR:-/tmp}/libdepa.$$
libdirb=${TMPDIR:-/tmp}/libdepb.$$
libdirc=${TMPDIR:-/tmp}/libdepc.$$
dtrace=$1
setup_libs()
{
mkdir $libdira
mkdir $libdirb
mkdir $libdirc
cat > $libdira/liba.$$.d <<EOF
#pragma D depends_on library libb.$$.d
#pragma D depends_on library libc.$$.d
#pragma D depends_on library libd.$$.d
EOF
cat > $libdirb/libb.$$.d <<EOF
#pragma D depends_on library libc.$$.d
EOF
cat > $libdirb/libc.$$.d <<EOF
EOF
cat > $libdirb/libd.$$.d <<EOF
EOF
cat > $libdirc/libe.$$.d <<EOF
#pragma D depends_on library liba.$$.d
EOF
cat > $libdirc/libf.$$.d <<EOF
EOF
}
setup_libs
$dtrace -L$libdira -L$libdirb -L$libdirc -e
status=$?
rm -rf $libdira
rm -rf $libdirb
rm -rf $libdirc
return $status

View File

@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
/*
@ -2150,25 +2151,23 @@ dt_lib_depend_free(dtrace_hdl_t *dtp)
}
}
/*
* Open all of the .d library files found in the specified directory and
* compile each one in topological order to cache its inlines and translators,
* etc. We silently ignore any missing directories and other files found
* therein. We only fail (and thereby fail dt_load_libs()) if we fail to
* compile a library and the error is something other than #pragma D depends_on.
* Dependency errors are silently ignored to permit a library directory to
* contain libraries which may not be accessible depending on our privileges.
* Open all the .d library files found in the specified directory and
* compile each one of them. We silently ignore any missing directories and
* other files found therein. We only fail (and thereby fail dt_load_libs()) if
* we fail to compile a library and the error is something other than #pragma D
* depends_on. Dependency errors are silently ignored to permit a library
* directory to contain libraries which may not be accessible depending on our
* privileges.
*/
static int
dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
{
struct dirent *dp;
const char *p;
const char *p, *end;
DIR *dirp;
char fname[PATH_MAX];
dtrace_prog_t *pgp;
FILE *fp;
void *rv;
dt_lib_depend_t *dld;
@ -2192,9 +2191,28 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
continue;
}
/*
* Skip files whose name match an already processed library
*/
for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;
dld = dt_list_next(dld)) {
end = strrchr(dld->dtld_library, '/');
/* dt_lib_depend_add ensures this */
assert(end != NULL);
if (strcmp(end + 1, dp->d_name) == 0)
break;
}
if (dld != NULL) {
dt_dprintf("skipping library %s, already processed "
"library with the same name: %s", dp->d_name,
dld->dtld_library);
continue;
}
dtp->dt_filetag = fname;
if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0)
goto err;
return (-1); /* preserve dt_errno */
rv = dt_compile(dtp, DT_CTX_DPROG,
DTRACE_PROBESPEC_NAME, NULL,
@ -2203,7 +2221,7 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
if (rv != NULL && dtp->dt_errno &&
(dtp->dt_errno != EDT_COMPILER ||
dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND)))
goto err;
return (-1); /* preserve dt_errno */
if (dtp->dt_errno)
dt_dprintf("error parsing library %s: %s\n",
@ -2214,6 +2232,27 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
}
(void) closedir(dirp);
return (0);
}
/*
* Perform a topological sorting of all the libraries found across the entire
* dt_lib_path. Once sorted, compile each one in topological order to cache its
* inlines and translators, etc. We silently ignore any missing directories and
* other files found therein. We only fail (and thereby fail dt_load_libs()) if
* we fail to compile a library and the error is something other than #pragma D
* depends_on. Dependency errors are silently ignored to permit a library
* directory to contain libraries which may not be accessible depending on our
* privileges.
*/
static int
dt_load_libs_sort(dtrace_hdl_t *dtp)
{
dtrace_prog_t *pgp;
FILE *fp;
dt_lib_depend_t *dld;
/*
* Finish building the graph containing the library dependencies
* and perform a topological sort to generate an ordered list
@ -2274,7 +2313,14 @@ dt_load_libs(dtrace_hdl_t *dtp)
dtp->dt_cflags |= DTRACE_C_NOLIBS;
for (dirp = dt_list_next(&dtp->dt_lib_path);
/*
* /usr/lib/dtrace is always at the head of the list. The rest of the
* list is specified in the precedence order the user requested. Process
* everything other than the head first. DTRACE_C_NOLIBS has already
* been spcified so dt_vopen will ensure that there is always one entry
* in dt_lib_path.
*/
for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path));
dirp != NULL; dirp = dt_list_next(dirp)) {
if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
@ -2282,6 +2328,16 @@ dt_load_libs(dtrace_hdl_t *dtp)
}
}
/* Handle /usr/lib/dtrace */
dirp = dt_list_next(&dtp->dt_lib_path);
if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {
dtp->dt_cflags &= ~DTRACE_C_NOLIBS;
return (-1); /* errno is set for us */
}
if (dt_load_libs_sort(dtp) < 0)
return (-1); /* errno is set for us */
return (0);
}

View File

@ -21,7 +21,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@ -31,9 +31,13 @@
#if defined(sun)
#include <alloca.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dt_parser.h>
#include <dt_impl.h>
#include <dt_provider.h>
@ -201,6 +205,29 @@ dt_pragma_binding(const char *prname, dt_node_t *dnp)
dtp->dt_globals->dh_defer = &dt_pragma_apply;
}
static void
dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib,
size_t len)
{
dt_dirpath_t *dirp;
struct stat sbuf;
int found = 0;
for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL;
dirp = dt_list_next(dirp)) {
(void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname);
if (stat(lib, &sbuf) == 0) {
found = 1;
break;
}
}
if (!found)
xyerror(D_PRAGMA_DEPEND,
"failed to find dependency in libpath: %s", lname);
}
/*
* The #pragma depends_on directive can be used to express a dependency on a
* module, provider or library which if not present will cause processing to
@ -230,16 +257,13 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp)
if (yypcb->pcb_cflags & DTRACE_C_CTL) {
assert(dtp->dt_filetag != NULL);
/*
* We have the file we are working on in dtp->dt_filetag
* so find that node and add the dependency in.
*/
dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
sizeof (lib));
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
lib)) != 0) {
xyerror(D_PRAGMA_DEPEND,
@ -261,8 +285,8 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp)
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
sizeof (lib));
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
lib);
assert(dld != NULL);