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");