diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | elf/Makefile | 2 | ||||
-rw-r--r-- | elf/dl-open.c | 24 | ||||
-rw-r--r-- | elf/dl-profstub.c | 43 | ||||
-rw-r--r-- | elf/dl-support.c | 1 | ||||
-rw-r--r-- | elf/dlfcn.h | 30 | ||||
-rw-r--r-- | elf/ldsodefs.h | 19 | ||||
-rw-r--r-- | elf/rtld.c | 1 | ||||
-rw-r--r-- | iconv/gconv.c | 9 | ||||
-rw-r--r-- | iconv/gconv_db.c | 7 | ||||
-rw-r--r-- | iconv/skeleton.c | 8 | ||||
-rw-r--r-- | libc.map | 4 | ||||
-rw-r--r-- | nss/getXXbyYY_r.c | 4 | ||||
-rw-r--r-- | nss/getXXent_r.c | 9 | ||||
-rw-r--r-- | nss/nsswitch.h | 3 |
15 files changed, 159 insertions, 24 deletions
@@ -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. diff --git a/elf/Makefile b/elf/Makefile index b2ea241808..dedc3d5074 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -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. diff --git a/elf/dl-open.c b/elf/dl-open.c index 4c4c8abdc5..2b9590913f 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -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 index 0000000000..9740c6adc4 --- /dev/null +++ b/elf/dl-profstub.c @@ -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); +} diff --git a/elf/dl-support.c b/elf/dl-support.c index 85f656c2fd..73c90c2f42 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -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; diff --git a/elf/dlfcn.h b/elf/dlfcn.h index 825b4843c1..e0b17d392a 100644 --- a/elf/dlfcn.h +++ b/elf/dlfcn.h @@ -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 */ diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h index 45c2a5ec64..6814f25556 100644 --- a/elf/ldsodefs.h +++ b/elf/ldsodefs.h @@ -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 */ diff --git a/elf/rtld.c b/elf/rtld.c index 028467f6f8..5bd4b7cd97 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -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; diff --git a/iconv/gconv.c b/iconv/gconv.c index 24dc21e2c2..9484fc8881 100644 --- a/iconv/gconv.c +++ b/iconv/gconv.c @@ -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); diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c index b98cc8f4f2..2c66249cc5 100644 --- a/iconv/gconv_db.c +++ b/iconv/gconv_db.c @@ -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 diff --git a/iconv/skeleton.c b/iconv/skeleton.c index 418247f769..19e737ac3e 100644 --- a/iconv/skeleton.c +++ b/iconv/skeleton.c @@ -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) { @@ -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; diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 2e5cc81a2b..c8d6b08009 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -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 diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c index 49064619ae..02a723d6bc 100644 --- a/nss/getXXent_r.c +++ b/nss/getXXent_r.c @@ -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; } diff --git a/nss/nsswitch.h b/nss/nsswitch.h index 8ba0294ae5..412936976a 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -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. */ |