dlopen/libssl bugs?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

dlopen/libssl bugs?

Cédric Berger-2
Hi,

Consider the following:

# cat test.c
#include <dlfcn.h>
main()
{
         dlopen("libssl.so", DL_LAZY);
}
# gcc test.c
# ./a.out
./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_free'
./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'X509_free'
./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'i2d_DHparams'
./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'i2d_DHparams'
./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'd2i_DHparams'
./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'd2i_DHparams'
./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_NAME_free'
./a.out: /usr/lib/libssl.so.10.0: can't resolve reference  
'X509_NAME_free'

What is the issue here?
Also:

# ldd /usr/lib/libssl.so.10.0
/usr/lib/libssl.so.10.0:
/usr/lib/libssl.so.10.0: Permission denied
/usr/lib/libssl.so.10.0: exit status 1

At the risk of being flamed, both the test program and ldd command  
works fine on linux:

[root@duron]~# ldd /usr/lib/libssl.so
         libgssapi_krb5.so.2 => /usr/kerberos/lib/libgssapi_krb5.so.2  
(0x00535000)
         libkrb5.so.3 => /usr/kerberos/lib/libkrb5.so.3 (0x00461000)
         libcom_err.so.3 => /usr/kerberos/lib/libcom_err.so.3  
(0x00b10000)
         libk5crypto.so.3 => /usr/kerberos/lib/libk5crypto.so.3  
(0x00111000)
         libresolv.so.2 => /lib/libresolv.so.2 (0x00515000)
         libcrypto.so.4 => /lib/libcrypto.so.4 (0x005ba000)
         libdl.so.2 => /lib/libdl.so.2 (0x002a5000)
         libz.so.1 => /usr/lib/libz.so.1 (0x00822000)
         libc.so.6 => /lib/tls/libc.so.6 (0x0096e000)
         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00d46000)

Could someone explain the issues here, and if there is a workaround
to dlopen libssl?

Thanks,
Cedric

Reply | Threaded
Open this post in threaded view
|

Re: dlopen/libssl bugs?

Dale Rahn
On Wed, May 10, 2006 at 02:50:57PM +0200, Cidric Berger wrote:

> Hi,
>
> Consider the following:
>
> # cat test.c
> #include <dlfcn.h>
> main()
> {
>         dlopen("libssl.so", DL_LAZY);
> }
> # gcc test.c
> # ./a.out
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'X509_free'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'i2d_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'i2d_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'd2i_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'd2i_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_NAME_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference  
> 'X509_NAME_free'
>
> What is the issue here?
> Also:
>
> # ldd /usr/lib/libssl.so.10.0
> /usr/lib/libssl.so.10.0:
> /usr/lib/libssl.so.10.0: Permission denied
> /usr/lib/libssl.so.10.0: exit status 1

The OpenBSD ldd currently does not support listing dependancies on libraries
objdump -p will provide that information
$ objdump -p /usr/lib/libssl.so.10.0 | grep NEEDED

libssl is not built to have a direct dependancy on libcrypto.so it is
expected the binary using libssl would also link against libcrypto
(as would be necessary on static linking)

to make libcrypto.so available to a dlopened libssl, dlopen libcrypto first
with the RTLD_GLOBAL flag

#include <dlfcn.h>
main()
{
        dlopen("libcrypto.so", DL_LAZY|RTLD_GLOBAL);
        dlopen("libssl.so", DL_LAZY);
}


Dale Rahn [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: dlopen/libssl bugs?

Cédric Berger-2
Dale Rahn wrote:

> On Wed, May 10, 2006 at 02:50:57PM +0200, Cidric Berger wrote:
>> Hi,
>>
>> Consider the following:
>>
>> # cat test.c
>> #include <dlfcn.h>
>> main()
>> {
>>         dlopen("libssl.so", DL_LAZY);
>> }
>> # gcc test.c
>> # ./a.out
>> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_free'
>> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'X509_free'
>> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'i2d_DHparams'
>> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'i2d_DHparams'
>> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'd2i_DHparams'
>> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'd2i_DHparams'
>> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_NAME_free'
>> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference  
>> 'X509_NAME_free'
>>
>> What is the issue here?
>> Also:
>>
>> # ldd /usr/lib/libssl.so.10.0
>> /usr/lib/libssl.so.10.0:
>> /usr/lib/libssl.so.10.0: Permission denied
>> /usr/lib/libssl.so.10.0: exit status 1
>
> The OpenBSD ldd currently does not support listing dependancies on libraries
> objdump -p will provide that information
> $ objdump -p /usr/lib/libssl.so.10.0 | grep NEEDED
>
> libssl is not built to have a direct dependancy on libcrypto.so it is
> expected the binary using libssl would also link against libcrypto
> (as would be necessary on static linking)
>
> to make libcrypto.so available to a dlopened libssl, dlopen libcrypto first
> with the RTLD_GLOBAL flag
>
> #include <dlfcn.h>
> main()
> {
>         dlopen("libcrypto.so", DL_LAZY|RTLD_GLOBAL);
>         dlopen("libssl.so", DL_LAZY);
> }
>

Thanks a lot for the explanation and the workaround!

Actually, it seem to work without the RTLD_GLOBAL flag,
which is not documented in the manpage btw :)

Is there a reason (beside lack of time) why libssl is not
build with libcrypto as a dependency? is it hard?

Cedric

Reply | Threaded
Open this post in threaded view
|

Re: dlopen/libssl bugs?

Matt Provost
In reply to this post by Cédric Berger-2
On Wed, May 10, 2006 at 02:50:57PM +0200, C?dric Berger wrote:

> Hi,
>
> Consider the following:
>
> # cat test.c
> #include <dlfcn.h>
> main()
> {
>         dlopen("libssl.so", DL_LAZY);
> }
> # gcc test.c
> # ./a.out
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'X509_free'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'i2d_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'i2d_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'd2i_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'd2i_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_NAME_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference  
> 'X509_NAME_free'
>
> What is the issue here?
> Also:
>
> # ldd /usr/lib/libssl.so.10.0
> /usr/lib/libssl.so.10.0:
> /usr/lib/libssl.so.10.0: Permission denied
> /usr/lib/libssl.so.10.0: exit status 1
>
> At the risk of being flamed, both the test program and ldd command  
> works fine on linux:
>
> [root@duron]~# ldd /usr/lib/libssl.so
>         libgssapi_krb5.so.2 => /usr/kerberos/lib/libgssapi_krb5.so.2  
> (0x00535000)
>         libkrb5.so.3 => /usr/kerberos/lib/libkrb5.so.3 (0x00461000)
>         libcom_err.so.3 => /usr/kerberos/lib/libcom_err.so.3  
> (0x00b10000)
>         libk5crypto.so.3 => /usr/kerberos/lib/libk5crypto.so.3  
> (0x00111000)
>         libresolv.so.2 => /lib/libresolv.so.2 (0x00515000)
>         libcrypto.so.4 => /lib/libcrypto.so.4 (0x005ba000)
>         libdl.so.2 => /lib/libdl.so.2 (0x002a5000)
>         libz.so.1 => /usr/lib/libz.so.1 (0x00822000)
>         libc.so.6 => /lib/tls/libc.so.6 (0x0096e000)
>         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00d46000)
>
> Could someone explain the issues here, and if there is a workaround
> to dlopen libssl?
>

Here's a patch that adds support for listing shared library dependencies
to ldd. I've been meaning to do some more testing on it but since the
topic came up, maybe other people can take a look at it.

It complains about undefined symbols as you noticed, but that comes from
ld.so and not ldd itself. It would be possible to make it quieter if
you're tracing it, but that maybe defeats the purpose?

Anyway the patch works fine for me, give it a shot.

Matt


Index: include/dlfcn.h
===================================================================
RCS file: /cvs/src/include/dlfcn.h,v
retrieving revision 1.9
diff -u -r1.9 dlfcn.h
--- include/dlfcn.h 11 Aug 2004 19:14:56 -0000 1.9
+++ include/dlfcn.h 7 May 2006 00:57:12 -0000
@@ -64,6 +64,7 @@
 #define RTLD_GLOBAL 0x100
 #define RTLD_LOCAL 0x000
 #define DL_LAZY RTLD_LAZY /* Compat */
+#define RTLD_TRACE 0x200
 
 /*
  * Special handle arguments for dlsym().
Index: libexec/ld.so//dlfcn.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/dlfcn.c,v
retrieving revision 1.72
diff -u -r1.72 dlfcn.c
--- libexec/ld.so//dlfcn.c 3 May 2006 15:44:56 -0000 1.72
+++ libexec/ld.so//dlfcn.c 7 May 2006 00:57:40 -0000
@@ -53,6 +53,10 @@
  if (libname == NULL)
  return RTLD_DEFAULT;
 
+ if ((flags & RTLD_TRACE) == RTLD_TRACE) {
+ _dl_traceld = "true";
+ }
+
  DL_DEB(("dlopen: loading: %s\n", libname));
 
  _dl_thread_kern_stop();
@@ -96,7 +100,7 @@
  int err;
  DL_DEB(("tail %s\n", object->load_name ));
  err = _dl_rtld(object);
- if (err != 0) {
+ if (err != 0 && !(_dl_traceld)) {
  _dl_real_close(object);
  _dl_errno = DL_CANT_LOAD_OBJ;
  object = 0;
@@ -119,6 +123,11 @@
  DL_DEB(("dlopen: %s: done (%s).\n", libname,
     failed ? "failed" : "success"));
 
+ if ((flags & RTLD_TRACE) == RTLD_TRACE) {
+ _dl_show_objects();
+ _dl_exit(0);
+ }
+
  return((void *)object);
 }
 
@@ -365,13 +374,23 @@
  objtypename = "rtld";
  break;
  case OBJTYPE_EXE:
- objtypename = "exe ";
+ if (_dl_debug)
+ objtypename = "exe ";
+ else {
+ object = object->next;
+ continue;
+ }
  break;
  case OBJTYPE_LIB:
  objtypename = "rlib";
  break;
  case OBJTYPE_DLO:
- objtypename = "dlib";
+ if (_dl_debug)
+ objtypename = "dlib";
+ else {
+ object = object->next;
+ continue;
+ }
  break;
  default:
  objtypename = "????";
Index: libexec/ld.so//ldd/ldd.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/ldd/ldd.c,v
retrieving revision 1.11
diff -u -r1.11 ldd.c
--- libexec/ld.so//ldd/ldd.c 10 Jul 2003 00:04:28 -0000 1.11
+++ libexec/ld.so//ldd/ldd.c 7 May 2006 00:57:41 -0000
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
 #include <sys/stat.h>
 #include <sys/mman.h>
@@ -94,7 +95,6 @@
  Elf_Phdr *phdr;
  int fd, i, size, status;
 
- printf("%s:\n", name);
 
  if ((fd = open(name, O_RDONLY)) < 0) {
  warn("%s", name);
@@ -114,6 +114,13 @@
  return 1;
  }
 
+ if (ehdr.e_type == ET_DYN) {
+ printf("%s:\n", name);
+ dlopen(name, RTLD_TRACE | RTLD_NOW);
+ close(fd);
+ return 0;
+ }
+
  size = ehdr.e_phnum * sizeof(Elf_Phdr);
  if ((phdr = malloc(size)) == NULL)
  err(1, "malloc");
@@ -135,6 +142,7 @@
  return 1;
  }
 
+ printf("%s:\n", name);
  fflush(stdout);
  switch (fork()) {
  case -1:

Reply | Threaded
Open this post in threaded view
|

Re: dlopen/libssl bugs?

Matt Provost
In reply to this post by Cédric Berger-2
On Wed, May 10, 2006 at 02:50:57PM +0200, C?dric Berger wrote:

> Hi,
>
> Consider the following:
>
> # cat test.c
> #include <dlfcn.h>
> main()
> {
>         dlopen("libssl.so", DL_LAZY);
> }
> # gcc test.c
> # ./a.out
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'X509_free'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'i2d_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'i2d_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'd2i_DHparams'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference 'd2i_DHparams'
> ./a.out:/usr/lib/libssl.so.10.0: undefined symbol 'X509_NAME_free'
> ./a.out: /usr/lib/libssl.so.10.0: can't resolve reference  
> 'X509_NAME_free'
>
> What is the issue here?
> Also:
>
> # ldd /usr/lib/libssl.so.10.0
> /usr/lib/libssl.so.10.0:
> /usr/lib/libssl.so.10.0: Permission denied
> /usr/lib/libssl.so.10.0: exit status 1
>
> At the risk of being flamed, both the test program and ldd command  
> works fine on linux:
>
> [root@duron]~# ldd /usr/lib/libssl.so
>         libgssapi_krb5.so.2 => /usr/kerberos/lib/libgssapi_krb5.so.2  
> (0x00535000)
>         libkrb5.so.3 => /usr/kerberos/lib/libkrb5.so.3 (0x00461000)
>         libcom_err.so.3 => /usr/kerberos/lib/libcom_err.so.3  
> (0x00b10000)
>         libk5crypto.so.3 => /usr/kerberos/lib/libk5crypto.so.3  
> (0x00111000)
>         libresolv.so.2 => /lib/libresolv.so.2 (0x00515000)
>         libcrypto.so.4 => /lib/libcrypto.so.4 (0x005ba000)
>         libdl.so.2 => /lib/libdl.so.2 (0x002a5000)
>         libz.so.1 => /usr/lib/libz.so.1 (0x00822000)
>         libc.so.6 => /lib/tls/libc.so.6 (0x0096e000)
>         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00d46000)
>
> Could someone explain the issues here, and if there is a workaround
> to dlopen libssl?
>

Here's a quick patch that disables the warnings from ldd. It's only for
i386 because that's all I have at the moment. I'm not sure if passing
the entire flags around is the way to do it, or maybe just passing a
warn variable would be clearer (or if this is the correct solution at
all).

Matt


Index: libexec/ld.so//dlfcn.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/dlfcn.c,v
retrieving revision 1.73
diff -u -r1.73 dlfcn.c
--- libexec/ld.so//dlfcn.c 8 May 2006 20:34:36 -0000 1.73
+++ libexec/ld.so//dlfcn.c 11 May 2006 05:40:12 -0000
@@ -53,6 +53,10 @@
  if (libname == NULL)
  return RTLD_DEFAULT;
 
+ if ((flags & RTLD_TRACE) == RTLD_TRACE) {
+ _dl_traceld = "true";
+ }
+
  DL_DEB(("dlopen: loading: %s\n", libname));
 
  _dl_thread_kern_stop();
@@ -96,7 +100,7 @@
  int err;
  DL_DEB(("tail %s\n", object->load_name ));
  err = _dl_rtld(object);
- if (err != 0) {
+ if (err != 0 && !(_dl_traceld)) {
  _dl_real_close(object);
  _dl_errno = DL_CANT_LOAD_OBJ;
  object = 0;
@@ -119,6 +123,11 @@
  DL_DEB(("dlopen: %s: done (%s).\n", libname,
     failed ? "failed" : "success"));
 
+ if ((flags & RTLD_TRACE) == RTLD_TRACE) {
+ _dl_show_objects();
+ _dl_exit(0);
+ }
+
  return((void *)object);
 }
 
@@ -365,13 +374,23 @@
  objtypename = "rtld";
  break;
  case OBJTYPE_EXE:
- objtypename = "exe ";
+ if (_dl_debug)
+ objtypename = "exe ";
+ else {
+ object = object->next;
+ continue;
+ }
  break;
  case OBJTYPE_LIB:
  objtypename = "rlib";
  break;
  case OBJTYPE_DLO:
- objtypename = "dlib";
+ if (_dl_debug)
+ objtypename = "dlib";
+ else {
+ object = object->next;
+ continue;
+ }
  break;
  default:
  objtypename = "????";
Index: libexec/ld.so//loader.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/loader.c,v
retrieving revision 1.103
diff -u -r1.103 loader.c
--- libexec/ld.so//loader.c 8 May 2006 20:37:01 -0000 1.103
+++ libexec/ld.so//loader.c 11 May 2006 05:40:14 -0000
@@ -743,6 +743,14 @@
 {
  size_t sz;
  int fails = 0;
+ int flags;
+
+ flags = SYM_SEARCH_ALL;
+ if (_dl_traceld) {
+ flags |= SYM_NOWARNNOTFOUND;
+ } else {
+ flags |= SYM_WARNNOTFOUND;
+ }
 
  if (object->next)
  fails += _dl_rtld(object->next);
@@ -774,11 +782,11 @@
  /*
  * Do relocation information first, then GOT.
  */
- fails =_dl_md_reloc(object, DT_REL, DT_RELSZ);
- fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ);
+ fails =_dl_md_reloc(object, DT_REL, DT_RELSZ, flags);
+ fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ, flags);
  prebind_symcache(object, SYM_PLT);
  _dl_md_reloc_got(object, !(_dl_bindnow ||
-    object->obj_flags & RTLD_NOW));
+    object->obj_flags & RTLD_NOW), flags);
 
  if (_dl_symcache != NULL) {
  if (sz != 0)
Index: libexec/ld.so//resolve.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.h,v
retrieving revision 1.51
diff -u -r1.51 resolve.h
--- libexec/ld.so//resolve.h 3 May 2006 16:10:51 -0000 1.51
+++ libexec/ld.so//resolve.h 11 May 2006 05:40:14 -0000
@@ -160,8 +160,8 @@
 elf_object_t *_dl_load_shlib(const char *, elf_object_t *, int, int);
 elf_object_t *_dl_tryload_shlib(const char *libname, int type, int flags);
 
-int  _dl_md_reloc(elf_object_t *object, int rel, int relsz);
-void _dl_md_reloc_got(elf_object_t *object, int lazy);
+int  _dl_md_reloc(elf_object_t *object, int rel, int relsz, int flags);
+void _dl_md_reloc_got(elf_object_t *object, int lazy, int flags);
 
 Elf_Addr _dl_find_symbol(const char *name, const Elf_Sym **this,
     int flags, const Elf_Sym *ref_sym, elf_object_t *object,
Index: libexec/ld.so//i386/rtld_machine.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/i386/rtld_machine.c,v
retrieving revision 1.19
diff -u -r1.19 rtld_machine.c
--- libexec/ld.so//i386/rtld_machine.c 22 Sep 2005 01:33:08 -0000 1.19
+++ libexec/ld.so//i386/rtld_machine.c 11 May 2006 05:40:15 -0000
@@ -167,7 +167,7 @@
 void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value);
 
 int
-_dl_md_reloc(elf_object_t *object, int rel, int relsz)
+_dl_md_reloc(elf_object_t *object, int rel, int relsz, int flags)
 {
  long i;
  long numrel;
@@ -228,8 +228,7 @@
  this = NULL;
  ooff = _dl_find_symbol_bysym(object,
     ELF_R_SYM(rels->r_info), &this,
-    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
-    ((type == R_TYPE(JUMP_SLOT))?
+    flags|((type == R_TYPE(JUMP_SLOT))?
  SYM_PLT:SYM_NOTPLT),
     sym, NULL);
  if (this == NULL) {
@@ -382,7 +381,7 @@
 }
 
 void
-_dl_md_reloc_got(elf_object_t *object, int lazy)
+_dl_md_reloc_got(elf_object_t *object, int lazy, int flags)
 {
  extern void _dl_bind_start(void); /* XXX */
  Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
@@ -424,7 +423,7 @@
  }
 
  if (!lazy) {
- _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
+ _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ, flags);
  } else {
  rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
  num = (object->Dyn.info[DT_PLTRELSZ]);
Index: libexec/ld.so//ldd/ldd.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/ldd/ldd.c,v
retrieving revision 1.11
diff -u -r1.11 ldd.c
--- libexec/ld.so//ldd/ldd.c 10 Jul 2003 00:04:28 -0000 1.11
+++ libexec/ld.so//ldd/ldd.c 11 May 2006 05:40:15 -0000
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
 #include <sys/stat.h>
 #include <sys/mman.h>
@@ -94,7 +95,6 @@
  Elf_Phdr *phdr;
  int fd, i, size, status;
 
- printf("%s:\n", name);
 
  if ((fd = open(name, O_RDONLY)) < 0) {
  warn("%s", name);
@@ -114,6 +114,13 @@
  return 1;
  }
 
+ if (ehdr.e_type == ET_DYN) {
+ printf("%s:\n", name);
+ dlopen(name, RTLD_TRACE);
+ close(fd);
+ return 0;
+ }
+
  size = ehdr.e_phnum * sizeof(Elf_Phdr);
  if ((phdr = malloc(size)) == NULL)
  err(1, "malloc");
@@ -135,6 +142,7 @@
  return 1;
  }
 
+ printf("%s:\n", name);
  fflush(stdout);
  switch (fork()) {
  case -1: