Hi all,

I have found an issue with how DTrace handles the #pragma D depends_on option when using dtrace -Lpath to add additional directories. I have confirmed that this is a problem on illumos and OS X 10.6.6. Presumably it also affects FreeBSD.

When looking for a dependency it does not search the entire path to try and resolve it, but rather only the local directory. So if you have a file with the following:

#pragma D depends_on procfs.d

that was in another directory, say, /home/rm/local/lib/dtrace, DTrace will only look for procfs.d in /home/rm/local/lib/dtrace/procfs.d and never anywhere else on the library path, which includes /usr/lib/dtrace where the file resides.

Attached is a patch that applies cleanly to Illumos. This patch searches the entire libdir path for the file using the first one that it finds. This patch also adds a DTest that catches this issue.

This patch was developed at Joyent with review from Bryan Cantrill. It is copyright by Joyent and licensed under the CDDL. It should apply cleanly to the Mac OS X and FreeBSD codebases. If people from the respective communities would like me to file bugs or there is some other process to facilitate this fix getting out there, please let me know.

Thanks,
Robert
diff --git a/usr/src/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh 
b/usr/src/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh
new file mode 100644
index 0000000..ced6584
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/pragma/tst.libdepsepdir.ksh
@@ -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
+
diff --git a/usr/src/lib/libdtrace/common/dt_cc.c 
b/usr/src/lib/libdtrace/common/dt_cc.c
index 24a386b..d972aba 100644
--- a/usr/src/lib/libdtrace/common/dt_cc.c
+++ b/usr/src/lib/libdtrace/common/dt_cc.c
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 /*
@@ -1913,15 +1914,14 @@ 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)
@@ -1931,10 +1931,8 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
        DIR *dirp;
 
        char fname[PATH_MAX];
-       dtrace_prog_t *pgp;
        FILE *fp;
        void *rv;
-       dt_lib_depend_t *dld;
 
        if ((dirp = opendir(path)) == NULL) {
                dt_dprintf("skipping lib dir %s: %s\n", path, strerror(errno));
@@ -1957,7 +1955,7 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)
 
                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,
@@ -1966,7 +1964,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",
@@ -1977,6 +1975,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
@@ -2045,6 +2064,9 @@ dt_load_libs(dtrace_hdl_t *dtp)
                }
        }
 
+       if (dt_load_libs_sort(dtp) < 0)
+               return (-1); /* errno is set for us */
+
        return (0);
 }
 
diff --git a/usr/src/lib/libdtrace/common/dt_pragma.c 
b/usr/src/lib/libdtrace/common/dt_pragma.c
index 9cb3c3b..285d781 100644
--- a/usr/src/lib/libdtrace/common/dt_pragma.c
+++ b/usr/src/lib/libdtrace/common/dt_pragma.c
@@ -21,14 +21,19 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 #include <assert.h>
 #include <strings.h>
 #include <alloca.h>
+#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>
@@ -196,6 +201,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
@@ -225,16 +253,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,
@@ -256,8 +281,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);

_______________________________________________
dtrace-discuss mailing list
dtrace-discuss@opensolaris.org

Reply via email to