Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 18 Jun 1998 16:51:12 +0000 (16:51 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 18 Jun 1998 16:51:12 +0000 (16:51 +0000)
1998-06-18 16:40  Ulrich Drepper  <drepper@cygnus.com>

* libc.map: Add _dl_profile_map, _dl_profile_output, _dl_start_profile,
_dl_mcount, _dl_mcount_wrapper.
* elf/Makefile (routines): Add dl-profstub.
* elf/dl-profstub.c: New file.
* elf/dl-support.c: Don't define _dl_profile_map.
* elf/rtld.c: Likewise.
* elf/dlfcn.h: Define DL_CALL_FCT macro.
* elf/ldsodefs.h: Declare _dl_profile_output, _dl_mcount_wrapper.
Define _CALL_DL_FCT.
* iconv/gconv.c: Use _CALL_DL_FCT to call function from dynamically
loaded object.
* iconv/gconv_db.c: Likewise.
* iconv/skeleton.c: Likewise.
* nss/getXXbyYY_r.c: Likewise.
* nss/getXXent_r.c: Likewise.
* nss/nsswitch.c: Likewise.

15 files changed:
ChangeLog
elf/Makefile
elf/dl-open.c
elf/dl-profstub.c [new file with mode: 0644]
elf/dl-support.c
elf/dlfcn.h
elf/ldsodefs.h
elf/rtld.c
iconv/gconv.c
iconv/gconv_db.c
iconv/skeleton.c
libc.map
nss/getXXbyYY_r.c
nss/getXXent_r.c
nss/nsswitch.h

index 42651f5..f6592af 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+1998-06-18 16:40  Ulrich Drepper  <drepper@cygnus.com>
+
+       * libc.map: Add _dl_profile_map, _dl_profile_output, _dl_start_profile,
+       _dl_mcount, _dl_mcount_wrapper.
+       * elf/Makefile (routines): Add dl-profstub.
+       * elf/dl-profstub.c: New file.
+       * elf/dl-support.c: Don't define _dl_profile_map.
+       * elf/rtld.c: Likewise.
+       * elf/dlfcn.h: Define DL_CALL_FCT macro.
+       * elf/ldsodefs.h: Declare _dl_profile_output, _dl_mcount_wrapper.
+       Define _CALL_DL_FCT.
+       * iconv/gconv.c: Use _CALL_DL_FCT to call function from dynamically
+       loaded object.
+       * iconv/gconv_db.c: Likewise.
+       * iconv/skeleton.c: Likewise.
+       * nss/getXXbyYY_r.c: Likewise.
+       * nss/getXXent_r.c: Likewise.
+       * nss/nsswitch.c: Likewise.
+
 1998-06-18 12:29  Ulrich Drepper  <drepper@cygnus.com>
 
        * sysdeps/libm-i387/e_scalb.S: Fix bug in FPU stack handling.
index b2ea241..dedc3d5 100644 (file)
@@ -22,7 +22,7 @@ subdir                := elf
 
 headers                = elf.h bits/elfclass.h bits/dlfcn.h link.h dlfcn.h
 routines       = $(dl-routines) dl-open dl-close dl-symbol dl-support \
-                 dl-addr enbl-secure
+                 dl-addr enbl-secure dl-profstub
 
 # The core dynamic linking functions are in libc for the static and
 # profiled libraries.
index 4c4c8ab..2b95909 100644 (file)
@@ -101,9 +101,27 @@ _dl_open (const char *file, int mode)
             magic ward.  */
          asm ("" : "=r" (reloc) : "0" (reloc));
 
-         (*reloc) (l, _dl_object_relocation_scope (l),
-                   ((mode & RTLD_BINDING_MASK) == RTLD_LAZY
-                    || _dl_profile != NULL), _dl_profile != NULL);
+#ifdef PIC
+         if (_dl_profile != NULL)
+           {
+             /* If this here is the shared object which we want to profile
+                make sure the profile is started.  We can find out whether
+                this is necessary or not by observing the `_dl_profile_map'
+                variable.  If was NULL but is not NULL afterwars we must
+                start the profiling.  */
+             struct link_map *old_profile_map = _dl_profile_map;
+
+             (*reloc) (l, _dl_object_relocation_scope (l), 1, 1);
+
+             if (old_profile_map == NULL && _dl_profile_map != NULL)
+               /* We must prepare the profiling.  */
+               _dl_start_profile (_dl_profile_map, _dl_profile_output);
+           }
+         else
+#endif
+           (*reloc) (l, _dl_object_relocation_scope (l),
+                     (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
+
          *_dl_global_scope_end = NULL;
        }
 
diff --git a/elf/dl-profstub.c b/elf/dl-profstub.c
new file mode 100644 (file)
index 0000000..9740c6a
--- /dev/null
@@ -0,0 +1,43 @@
+/* Helper definitions for profiling of shared libraries.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <elf/ldsodefs.h>
+
+/* This is the map for the shared object we profile.  It is defined here
+   only because we test for this value being NULL or not.  */
+struct link_map *_dl_profile_map;
+
+
+void
+_dl_mcount_wrapper (ElfW(Addr) selfpc)
+{
+  _dl_mcount ((ElfW(Addr)) __builtin_return_address (0), selfpc);
+}
+
+
+void
+_dl_mcount_wrapper_check (void *selfpc)
+{
+  if (_dl_profile_map != NULL)
+    _dl_mcount ((ElfW(Addr)) __builtin_return_address (0),
+               (ElfW(Addr)) selfpc);
+}
index 85f656c..73c90c2 100644 (file)
@@ -53,7 +53,6 @@ struct r_search_path *_dl_search_paths;
 
 /* We never do profiling.  */
 const char *_dl_profile;
-struct link_map *_dl_profile_map;
 
 /* Names of shared object for which the RPATHs should be ignored.  */
 const char *_dl_inhibit_rpath;
index 825b484..e0b17d3 100644 (file)
@@ -1,5 +1,5 @@
 /* User functions for run-time dynamic loading.
-   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -70,6 +70,34 @@ typedef struct
   } Dl_info;
 extern int dladdr __P ((const void *__address, Dl_info *__info));
 
+#ifdef __USE_GNU
+/* To support profiling of shared objects it is a good idea to call
+   the function found using `dlsym' using the following macro since
+   these calls do not use the PLT.  But this would mean the dynamic
+   loader has no chance to find out when the function is called.  The
+   macro applies the necessary magic so that profiling is possible.
+   Rewrite
+       foo = (*fctp) (arg1, arg2);
+   into
+        foo = DL_CALL_FCT (fctp, (arg1, arg2));
+*/
+# if __GNUC__ >= 2
+/* Do not ever use this variable directly, it is internal!  */
+extern struct link_map *_dl_profile_map;
+
+#  define DL_CALL_FCT(fctp, args) \
+  (__extension__ ({ if (_dl_profile_map != NULL)                             \
+                     _dl_mcount_wrapper_check (fctp);                        \
+                   (*fctp) args; })
+# else
+/* This feature is not available without GCC.  */
+#  define DL_CALL_FCT(fctp, args) (*fctp) args
+# endif
+
+/* This function calls the profiling functions.  */
+extern void _dl_mcount_wrapper_check __P ((void *__selfpc));
+#endif
+
 __END_DECLS
 
 #endif /* dlfcn.h */
index 45c2a5e..6814f25 100644 (file)
@@ -127,6 +127,8 @@ extern int _dl_zerofd;
 extern const char *_dl_profile;
 /* Map of shared object to be profiled.  */
 extern struct link_map *_dl_profile_map;
+/* Filename of the output file.  */
+extern const char *_dl_profile_output;
 
 /* If nonzero the appropriate debug information is printed.  */
 extern int _dl_debug_libs;
@@ -409,6 +411,11 @@ extern void _dl_start_profile (struct link_map *map, const char *output_dir)
 /* The actual functions used to keep book on the calls.  */
 extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc);
 
+/* This function is simply a wrapper around the _dl_mcount function
+   which does not require a FROMPC parameter since this is the
+   calling function.  */
+extern void _dl_mcount_wrapper (ElfW(Addr) selfpc);
+
 
 /* Show the members of the auxiliary array passed up from the kernel.  */
 extern void _dl_show_auxv (void) internal_function;
@@ -424,6 +431,18 @@ extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform,
                                                        size_t *max_capstrlen)
      internal_function;
 
+
+/* When we do profiling we have the problem that uses of `dlopen'ed
+   objects don't use the PLT but instead use a pointer to the function.
+   We still want to have profiling data and in these cases we must do
+   the work of calling `_dl_mcount' ourself.  The following macros
+   helps do it.  */
+#define _CALL_DL_FCT(fctp, args) \
+  ({ if (_dl_profile_map != NULL)                                            \
+       _dl_mcount_wrapper ((ElfW(Addr)) fctp);                               \
+     (*fctp) args;                                                           \
+  })
+
 __END_DECLS
 
 #endif /* ldsodefs.h */
index 028467f..5bd4b7c 100644 (file)
@@ -73,7 +73,6 @@ unsigned long _dl_hwcap;
 struct r_search_path *_dl_search_paths;
 const char *_dl_profile;
 const char *_dl_profile_output;
-struct link_map *_dl_profile_map;
 int _dl_debug_libs;
 int _dl_debug_impcalls;
 int _dl_debug_bindings;
index 24dc21e..9484fc8 100644 (file)
@@ -22,6 +22,7 @@
 #include <assert.h>
 #include <gconv.h>
 #include <sys/param.h>
+#include <elf/ldsodefs.h>
 
 
 int
@@ -40,7 +41,8 @@ __gconv (gconv_t cd, const char **inbuf, const char *inbufend, char **outbuf,
 
   if (inbuf == NULL || *inbuf == NULL)
     /* We just flush.  */
-    result = (*cd->steps->fct) (cd->steps, cd->data, NULL, NULL, converted, 1);
+    result = _CALL_DL_FCT (cd->steps->fct,
+                          (cd->steps, cd->data, NULL, NULL, converted, 1));
   else
     {
       const char *last_start;
@@ -52,8 +54,9 @@ __gconv (gconv_t cd, const char **inbuf, const char *inbufend, char **outbuf,
       do
        {
          last_start = *inbuf;
-         result = (*cd->steps->fct) (cd->steps, cd->data, inbuf, inbufend,
-                                     converted, 0);
+         result = _CALL_DL_FCT (cd->steps->fct,
+                                (cd->steps, cd->data, inbuf, inbufend,
+                                 converted, 0));
        }
       while (result == GCONV_EMPTY_INPUT && last_start != *inbuf
             && *inbuf + cd->steps->min_needed_from <= inbufend);
index b98cc8f..2c66249 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <bits/libc-lock.h>
+#include <elf/ldsodefs.h>
 
 #include <gconv_int.h>
 
@@ -154,7 +155,7 @@ free_derivation (void *p)
 
   for (cnt = 0; cnt < deriv->nsteps; ++cnt)
     if (deriv->steps[cnt].end_fct)
-      (*deriv->steps[cnt].end_fct) (&deriv->steps[cnt]);
+      _CALL_DL_FCT (deriv->steps[cnt].end_fct, (&deriv->steps[cnt]));
 
   free ((struct gconv_step *) deriv->steps);
   free (deriv);
@@ -220,7 +221,7 @@ gen_steps (struct derivation_step *best, const char *toset,
 
          /* Call the init function.  */
          if (result[step_cnt].init_fct != NULL)
-           (*result[step_cnt].init_fct) (&result[step_cnt]);
+           _CALL_DL_FCT (result[step_cnt].init_fct, (&result[step_cnt]));
 
          current = current->last;
        }
@@ -231,7 +232,7 @@ gen_steps (struct derivation_step *best, const char *toset,
          while (++step_cnt < *nsteps)
            {
              if (result[step_cnt].end_fct != NULL)
-               (*result[step_cnt].end_fct) (&result[step_cnt]);
+               _CALL_DL_FCT (result[step_cnt].end_fct, (&result[step_cnt]));
 #ifndef STATIC_GCONV
              __gconv_release_shlib (result[step_cnt].shlib_handle);
 #endif
index 418247f..19e737a 100644 (file)
@@ -82,6 +82,7 @@
 #define __need_size_t
 #define __need_NULL
 #include <stddef.h>
+#include <elf/ldsodefs.h>
 
 
 /* The direction objects.  */
@@ -218,7 +219,8 @@ FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
          if (status == GCONV_OK)
 #endif
            /* Give the modules below the same chance.  */
-           status = (*fct) (next_step, next_data, NULL, NULL, written, 1);
+           status = _CALL_DL_FCT (fct, (next_step, next_data, NULL, NULL,
+                                        written, 1));
        }
     }
   else
@@ -284,8 +286,8 @@ FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
              const char *outerr = data->outbuf;
              int result;
 
-             result = (*fct) (next_step, next_data, &outerr, outbuf,
-                              written, 0);
+             result = _CALL_DL_FCT (fct, (next_step, next_data, &outerr,
+                                          outbuf, written, 0));
 
              if (result != GCONV_EMPTY_INPUT)
                {
index f6c3b65..3093109 100644 (file)
--- a/libc.map
+++ b/libc.map
@@ -474,7 +474,8 @@ GLIBC_2.1 {
     # global variables
     _IO_2_1_stdin_; _IO_2_1_stdout_; _IO_2_1_stderr_;
     __gconv_alias_db; __gconv_nmodules; __gconv_modules_db;
-    _dl_profile; __libc_stack_end;
+    _dl_profile; _dl_profile_map; _dl_profile_output; _dl_start_profile;
+    __libc_stack_end;
 
     # This is for ix86 only.
     _fp_hw;
@@ -491,6 +492,7 @@ GLIBC_2.1 {
     __xstat64; __fxstat64; __lxstat64;
     __pread64; __pwrite64;
     __backtrace; __backtrace_symbols;
+    _dl_mcount; _dl_mcount_wrapper;
 
     # helper functions
     __libc_current_sigrtmin; __libc_current_sigrtmax; __libc_allocate_rtsig;
index 2e5cc81..c8d6b08 100644 (file)
@@ -161,8 +161,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 
   while (no_more == 0)
     {
-      status = (*fct) (ADD_VARIABLES, resbuf, buffer, buflen,
-                      &errno H_ERRNO_VAR);
+      status = _CALL_DL_FCT (fct, (ADD_VARIABLES, resbuf, buffer, buflen,
+                                  &errno H_ERRNO_VAR));
 
       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
         provided buffer is too small.  In this case we should give
index 4906461..02a723d 100644 (file)
@@ -164,7 +164,7 @@ SETFUNC_NAME (STAYOPEN)
   while (! no_more)
     {
       int is_last_nip = nip == last_nip;
-      enum nss_status status = (*fct) (STAYOPEN_VAR);
+      enum nss_status status = _CALL_DL_FCT (fct, (STAYOPEN_VAR));
 
       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
                            status, 0);
@@ -201,7 +201,7 @@ ENDFUNC_NAME (void)
   while (! no_more)
     {
       /* Ignore status, we force check in __NSS_NEXT.  */
-      (void) (*fct) ();
+      _CALL_DL_FCT (fct, ());
 
       if (nip == last_nip)
        /* We have processed all services which were used.  */
@@ -245,7 +245,8 @@ INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
     {
       int is_last_nip = nip == last_nip;
 
-      status = (*fct) (resbuf, buffer, buflen, &errno H_ERRNO_VAR);
+      status = _CALL_DL_FCT (fct,
+                            (resbuf, buffer, buflen, &errno H_ERRNO_VAR));
 
       /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
         provided buffer is too small.  In this case we should give
@@ -276,7 +277,7 @@ INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
                                      (void **) &sfct);
 
              if (! no_more)
-               status = (*sfct) (STAYOPEN_TMPVAR);
+               status = _CALL_DL_FCT (sfct, (STAYOPEN_TMPVAR));
              else
                status = NSS_STATUS_NOTFOUND;
            }
index 8ba0294..4129369 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -26,6 +26,7 @@
 #include <nss.h>
 #include <resolv.h>
 #include <search.h>
+#include <elf/ldsodefs.h>
 
 
 /* Actions performed after lookup finished.  */