Diff below fixes "ldd /usr/lib/*.so.*" so that it outputs more than
just the first shared object's dependencies, like the behavior from
"ldd /usr/bin/*".

The issue is that dlopen(f, RTLD_TRACE) calls exit() after it's done.
I looked into changing this to properly cleanup and return, but
figured it was easier to just fork first like we already do for
exec()-based tracing.

ok?


Index: ldd/ldd.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/ldd/ldd.c,v
retrieving revision 1.14
diff -u -p ldd/ldd.c
--- ldd/ldd.c   2 Mar 2009 09:27:34 -0000       1.14
+++ ldd/ldd.c   8 Apr 2011 23:06:19 -0000
@@ -94,9 +94,9 @@ doit(char *name)
 {
        Elf_Ehdr ehdr;
        Elf_Phdr *phdr;
-       int fd, i, size, status, interp=0;
+       int fd, i, size, status, interp = 0;
        char buf[MAXPATHLEN];
-       void * dlhandle; 
+       void *dlhandle;
 
        if ((fd = open(name, O_RDONLY)) < 0) {
                warn("%s", name);
@@ -110,8 +110,9 @@ doit(char *name)
        }
 
        if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
-           ehdr.e_machine != ELF_TARG_MACH) {
-               warnx("%s: not an ELF executable", name);
+           ehdr.e_machine != ELF_TARG_MACH ||
+           (ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN)) {
+               warnx("%s: not an ELF executable or shared object", name);
                close(fd);
                return 1;
        }
@@ -133,26 +134,10 @@ doit(char *name)
                        break;
                }
 
-       if (ehdr.e_type == ET_DYN && !interp) {
-               printf("%s:\n", name);
-               if (realpath(name, buf) == NULL) {
-                       warn("realpath(%s)", name);
-                       return 1;
-               }
-               dlhandle = dlopen(buf, RTLD_TRACE);
-               if (dlhandle == NULL) {
-                       printf("%s\n", dlerror());
-                       return 1;
-               }
-               close(fd);
-               free(phdr);
-               return 0;
-       }
-
        close(fd);
        free(phdr);
 
-       if (i == ehdr.e_phnum) {
+       if (ehdr.e_type == ET_EXEC && !interp) {
                warnx("%s: not a dynamic executable", name);
                return 1;
        }
@@ -163,9 +148,16 @@ doit(char *name)
        case -1:
                err(1, "fork");
        case 0:
-               execl(name, name, (char *)NULL);
-               perror(name);
-               _exit(1);
+               if (interp) {
+                       execl(name, name, NULL);
+                       err(1, "execl(%s)", name);
+               } else {
+                       if (realpath(name, buf) == NULL)
+                               err(1, "realpath(%s)", name);
+                       if (dlopen(buf, RTLD_TRACE) == NULL)
+                               errx(1, "dlopen(%s): %s", buf, dlerror());
+                       _exit(1);
+               }
        default:
                if (wait(&status) < 0) {
                        warn("wait");

Reply via email to