+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.
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.
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;
}
--- /dev/null
+/* 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);
+}
/* 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;
/* 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
} 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 */
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;
/* 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;
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 */
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;
#include <assert.h>
#include <gconv.h>
#include <sys/param.h>
+#include <elf/ldsodefs.h>
int
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;
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);
#include <stdlib.h>
#include <string.h>
#include <bits/libc-lock.h>
+#include <elf/ldsodefs.h>
#include <gconv_int.h>
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);
/* 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;
}
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
#define __need_size_t
#define __need_NULL
#include <stddef.h>
+#include <elf/ldsodefs.h>
/* The direction objects. */
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
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)
{
# 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;
__xstat64; __fxstat64; __lxstat64;
__pread64; __pwrite64;
__backtrace; __backtrace_symbols;
+ _dl_mcount; _dl_mcount_wrapper;
# helper functions
__libc_current_sigrtmin; __libc_current_sigrtmax; __libc_allocate_rtsig;
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
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);
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. */
{
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
(void **) &sfct);
if (! no_more)
- status = (*sfct) (STAYOPEN_TMPVAR);
+ status = _CALL_DL_FCT (sfct, (STAYOPEN_TMPVAR));
else
status = NSS_STATUS_NOTFOUND;
}
-/* 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
#include <nss.h>
#include <resolv.h>
#include <search.h>
+#include <elf/ldsodefs.h>
/* Actions performed after lookup finished. */