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.
This commit is contained in:
Ulrich Drepper 1998-06-18 16:51:12 +00:00
parent 2827300fbe
commit 5ad49c0707
15 changed files with 159 additions and 24 deletions

View File

@ -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.

View 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.

View 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;
}

43
elf/dl-profstub.c Normal file
View File

@ -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);
}

View 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;

View 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 */

View 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 */

View 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;

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

View 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

View 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)
{

View File

@ -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;

View 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

View 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;
}

View 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. */