Back to index

glibc  2.9
Classes | Defines | Typedefs | Enumerations | Functions | Variables
ldsodefs.h File Reference
#include <features.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <elf.h>
#include <dlfcn.h>
#include <fpu_control.h>
#include <sys/mman.h>
#include <link.h>
#include <dl-lookupcfg.h>
#include <dl-sysdep.h>
#include <bits/libc-lock.h>
#include <hp-timing.h>
#include <tls.h>
#include <kernel-features.h>
#include <dl-procinfo.c>

Go to the source code of this file.

Classes

struct  r_found_version
struct  r_search_path_elem
struct  r_strlenpair
struct  libname_list
struct  audit_ifaces
struct  dtv_slotinfo_list
struct  dtv_slotinfo_list::dtv_slotinfo
struct  dl_scope_free_list
union  audit_ifaces.__unnamed__
union  audit_ifaces.__unnamed__
union  audit_ifaces.__unnamed__

Defines

#define __need_size_t
#define __need_NULL
#define ELFW(type)   _ElfW (ELF, __ELF_NATIVE_CLASS, type)
#define D_PTR(map, i)   (map)->i->d_un.d_ptr
#define LOOKUP_VALUE(map)   map
#define LOOKUP_VALUE_ADDRESS(map)   ((map) ? (map)->l_addr : 0)
#define DL_SYMBOL_ADDRESS(map, ref)   (void *) (LOOKUP_VALUE_ADDRESS (map) + ref->st_value)
#define DL_LOOKUP_ADDRESS(addr)   ((ElfW(Addr)) (addr))
#define DL_DT_INIT_ADDRESS(map, start)   (start)
#define DL_DT_FINI_ADDRESS(map, start)   (start)
#define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR)
#define DL_UNMAP(map)
#define DL_STATIC_INIT(map)
#define ELF_RTYPE_CLASS_PLT   1
#define ELF_RTYPE_CLASS_COPY   2
#define PF_TO_PROT
#define EXTERN   extern
#define GL(name)   _##name
#define DL_NNS   1
#define TLS_SLOTINFO_SURPLUS   (62)
#define DTV_SURPLUS   (14)
#define GLRO(name)   _##name
#define DL_DEBUG_LIBS   (1 << 0)
#define DL_DEBUG_IMPCALLS   (1 << 1)
#define DL_DEBUG_BINDINGS   (1 << 2)
#define DL_DEBUG_SYMBOLS   (1 << 3)
#define DL_DEBUG_VERSIONS   (1 << 4)
#define DL_DEBUG_RELOC   (1 << 5)
#define DL_DEBUG_FILES   (1 << 6)
#define DL_DEBUG_STATISTICS   (1 << 7)
#define DL_DEBUG_UNUSED   (1 << 8)
#define DL_DEBUG_HELP   (1 << 9)
#define DL_DEBUG_PRELINK   (1 << 10)
#define PROCINFO_DECL
#define PROCINFO_CLASS   EXTERN
#define rtld_progname   _dl_argv[0]
#define _dl_printf(fmt, args...)   _dl_dprintf (STDOUT_FILENO, fmt, ##args)
#define _dl_error_printf(fmt, args...)   _dl_dprintf (STDERR_FILENO, fmt, ##args)
#define _dl_fatal_printf(fmt, args...)

Typedefs

typedef struct link_maplookup_t
typedef void(* receiver_fct )(int, const char *, const char *)

Enumerations

enum  r_dir_status { unknown, nonexisting, existing }
enum  allowmask { allow_libc = 1, allow_libdl = 2, allow_libpthread = 4, allow_ldso = 8 }
enum  { DL_LOOKUP_ADD_DEPENDENCY = 1, DL_LOOKUP_RETURN_NEWEST = 2, DL_LOOKUP_GSCOPE_LOCK = 4 }

Functions

int _dl_name_match_p (const char *__name, const struct link_map *__map) internal_function
 __rtld_lock_define_recursive (EXTERN, _dl_load_lock) EXTERN unsigned long long _dl_load_adds
EXTERN ElfW (Word) _dl_stack_flags
EXTERN ElfW (Addr) _dl_use_load_bias
int _dl_make_stack_executable (void **stack_endp) internal_function
 rtld_hidden_proto (_dl_make_stack_executable) extern void *__libc_stack_end attribute_relro
 rtld_hidden_proto (__libc_stack_end) extern int _dl_argc attribute_hidden attribute_relro
 weak_extern (_dl_starting_up) extern int _dl_sysdep_open_zero_fill(void)
void _dl_debug_printf (const char *fmt,...) __attribute__((__format__(__printf__
void _dl_debug_printf_c (const char *fmt,...) __attribute__((__format__(__printf__
void void _dl_dprintf (int fd, const char *fmt,...) __attribute__((__format__(__printf__
void _dl_signal_error (int errcode, const char *object, const char *occurred, const char *errstring) internal_function __attribute__((__noreturn__)) attribute_hidden
void _dl_signal_cerror (int errcode, const char *object, const char *occation, const char *errstring) internal_function
void _dl_receive_error (receiver_fct fct, void(*operate)(void *), void *args) internal_function
struct link_map_dl_map_object (struct link_map *loader, const char *name, int preloaded, int type, int trace_mode, int mode, Lmid_t nsid) internal_function attribute_hidden
void _dl_map_object_deps (struct link_map *map, struct link_map **preloads, unsigned int npreloads, int trace_mode, int open_mode) internal_function attribute_hidden
void _dl_setup_hash (struct link_map *map) internal_function attribute_hidden
void _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting) internal_function
lookup_t _dl_lookup_symbol_x (const char *undef, struct link_map *undef_map, const ElfW(Sym)**sym, struct r_scope_elem *symbol_scope[], const struct r_found_version *version, int type_class, int flags, struct link_map *skip_map) internal_function attribute_hidden
struct link_map_dl_new_object (char *realname, const char *libname, int type, struct link_map *loader, int mode, Lmid_t nsid) internal_function attribute_hidden
void _dl_relocate_object (struct link_map *map, struct r_scope_elem *scope[], int lazy, int consider_profiling) attribute_hidden
void _dl_protect_relro (struct link_map *map) internal_function attribute_hidden
void _dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt) internal_function __attribute__((__noreturn__))
void _dl_resolve_conflicts (struct link_map *l, ElfW(Rela)*conflict, ElfW(Rela)*conflictend)
int _dl_check_all_versions (struct link_map *map, int verbose, int trace_mode) internal_function
int _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) internal_function
void _dl_init (struct link_map *main_map, int argc, char **argv, char **env) internal_function attribute_hidden
void _dl_fini (void) internal_function
void _dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps, char *used, Lmid_t ns) internal_function
void _dl_debug_state (void)
 rtld_hidden_proto (_dl_debug_state) extern struct r_debug *_dl_debug_initialize(ElfW(Addr) ldbase
void _dl_init_paths (const char *library_path) internal_function
void _dl_start_profile (void) internal_function attribute_hidden
void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc)
void _dl_mcount_internal (ElfW(Addr) frompc, ElfW(Addr) selfpc) attribute_hidden
void _dl_mcount_wrapper (void *selfpc)
void _dl_show_auxv (void) internal_function
char * _dl_next_ld_env_entry (char ***position) internal_function
struct r_strlenpair_dl_important_hwcaps (const char *platform, size_t paltform_len, size_t *sz, size_t *max_capstrlen) internal_function
const char * _dl_load_cache_lookup (const char *name) internal_function
void _dl_unload_cache (void) attribute_hidden
void * _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot) internal_function attribute_hidden
void _dl_sysdep_start_cleanup (void) internal_function attribute_hidden
size_t _dl_next_tls_modid (void) internal_function attribute_hidden
void _dl_determine_tlsoffset (void) internal_function attribute_hidden
int _dl_tls_setup (void) internal_function
 rtld_hidden_proto (_dl_tls_setup) extern void *_dl_allocate_tls(void *mem) internal_function
 rtld_hidden_proto (_dl_allocate_tls) extern void _dl_get_tls_static_info(size_t *sizep
void _dl_allocate_static_tls (struct link_map *map) internal_function attribute_hidden
void * _dl_allocate_tls_storage (void) internal_function attribute_hidden
void * _dl_allocate_tls_init (void *) internal_function
 rtld_hidden_proto (_dl_allocate_tls_init) extern void _dl_deallocate_tls(void *tcb
 rtld_hidden_proto (_dl_deallocate_tls) extern void _dl_nothread_init_static_tls(struct link_map *) attribute_hidden
const char * _dl_get_origin (void) attribute_hidden
size_t _dl_dst_count (const char *name, int is_path) attribute_hidden
char * _dl_dst_substitute (struct link_map *l, const char *name, char *result, int is_path) attribute_hidden
int _dl_check_caller (const void *caller, enum allowmask mask) attribute_hidden
void * _dl_open (const char *name, int mode, const void *caller, Lmid_t nsid, int argc, char *argv[], char *env[]) attribute_hidden
int _dl_scope_free (void *) attribute_hidden
void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden
struct link_map_dl_update_slotinfo (unsigned long int req_modid)
void * _dl_tls_get_addr_soft (struct link_map *l) attribute_hidden
int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) internal_function attribute_hidden

Variables

EXTERN struct link_namespaces _dl_ns [DL_NNS]
EXTERN int _dl_zerofd
EXTERN struct link_map_dl_initfirst
EXTERN struct link_map_dl_profile_map
EXTERN unsigned long int _dl_num_relocations
EXTERN unsigned long int _dl_num_cache_relocations
EXTERN struct r_search_path_elem_dl_all_dirs
EXTERN struct link_map
EXTERN int(* _dl_make_stack_executable_hook )(void **) internal_function
EXTERN bool _dl_tls_dtv_gaps
EXTERN size_t _dl_tls_max_dtv_idx
EXTERN struct dtv_slotinfo_list_dl_tls_dtv_slotinfo_list
EXTERN size_t _dl_tls_static_nelem
EXTERN size_t _dl_tls_static_size
EXTERN size_t _dl_tls_static_used
EXTERN size_t _dl_tls_static_align
EXTERN void * _dl_initial_dtv
EXTERN size_t _dl_tls_generation
EXTERN void(* _dl_init_static_tls )(struct link_map *)
EXTERN void(* _dl_wait_lookup_done )(void)
EXTERN struct dl_scope_free_list_dl_scope_free_list
EXTERN int _dl_debug_mask
EXTERN unsigned int _dl_osversion
EXTERN const char * _dl_platform
EXTERN size_t _dl_platformlen
EXTERN size_t _dl_pagesize
EXTERN struct r_scope_elem
EXTERN int _dl_clktck
EXTERN int _dl_verbose
EXTERN int _dl_debug_fd
EXTERN int _dl_lazy
EXTERN int _dl_bind_not
EXTERN int _dl_dynamic_weak
EXTERN fpu_control_t _dl_fpu_control
EXTERN int _dl_correct_cache_id
EXTERN uint64_t _dl_hwcap
EXTERN uint64_t _dl_hwcap_mask
EXTERN const char * _dl_inhibit_rpath
EXTERN const char * _dl_origin_path
EXTERN const char * _dl_profile
EXTERN const char * _dl_profile_output
EXTERN const char * _dl_trace_prelink
EXTERN struct link_map_dl_trace_prelink_map
EXTERN struct r_search_path_elem_dl_init_all_dirs
char **_dl_argv attribute_relro
int _dl_starting_up
void attribute_hidden
const char *name internal_function
void(* dl_main )(const ElfW(Phdr)*phdr, ElfW(Word) phnum, ElfW(Addr)*user_entry)) attribute_hidden

Class Documentation

struct r_search_path_elem

Definition at line 141 of file ldsodefs.h.

Collaboration diagram for r_search_path_elem:
Class Members
const char * dirname
size_t dirnamelen
struct r_search_path_elem * next
const char * what
const char * where
struct r_strlenpair

Definition at line 158 of file ldsodefs.h.

Class Members
size_t len
const char * str
struct libname_list

Definition at line 166 of file ldsodefs.h.

Collaboration diagram for libname_list:
Class Members
int dont_free
const char * name
struct libname_list * next
struct link_namespaces

Definition at line 374 of file ldsodefs.h.

Collaboration diagram for link_namespaces:
Class Members
size_t _ns_global_scope_alloc
struct link_map * _ns_loaded
struct r_scope_elem * _ns_main_searchlist
unsigned int _ns_nloaded
struct dtv_slotinfo_list

Definition at line 455 of file ldsodefs.h.

Collaboration diagram for dtv_slotinfo_list:
Class Members
size_t len
struct dtv_slotinfo_list * next
struct dtv_slotinfo slotinfo
struct dtv_slotinfo_list::dtv_slotinfo

Definition at line 459 of file ldsodefs.h.

Collaboration diagram for dtv_slotinfo_list::dtv_slotinfo:
Class Members
size_t gen
struct link_map * map
struct dl_scope_free_list

Definition at line 492 of file ldsodefs.h.

Class Members
size_t count
void * list

Define Documentation

#define __need_NULL

Definition at line 27 of file ldsodefs.h.

#define __need_size_t

Definition at line 26 of file ldsodefs.h.

#define _dl_error_printf (   fmt,
  args... 
)    _dl_dprintf (STDERR_FILENO, fmt, ##args)

Definition at line 764 of file ldsodefs.h.

#define _dl_fatal_printf (   fmt,
  args... 
)
Value:
do                                                                   \
    {                                                                \
      _dl_dprintf (STDERR_FILENO, fmt, ##args);                             \
      _exit (127);                                                   \
    }                                                                \
  while (1)

Definition at line 769 of file ldsodefs.h.

#define _dl_printf (   fmt,
  args... 
)    _dl_dprintf (STDOUT_FILENO, fmt, ##args)

Definition at line 759 of file ldsodefs.h.

#define D_PTR (   map,
  i 
)    (map)->i->d_un.d_ptr

Definition at line 58 of file ldsodefs.h.

#define DL_ADDR_SYM_MATCH (   L,
  SYM,
  MATCHSYM,
  ADDR 
)
Value:
((ADDR) >= (L)->l_addr + (SYM)->st_value                       \
   && ((((SYM)->st_shndx == SHN_UNDEF || (SYM)->st_size == 0)         \
       && (ADDR) == (L)->l_addr + (SYM)->st_value)                    \
       || (ADDR) < (L)->l_addr + (SYM)->st_value + (SYM)->st_size)    \
   && ((MATCHSYM) == NULL || (MATCHSYM)->st_value < (SYM)->st_value))

Definition at line 78 of file ldsodefs.h.

#define DL_DEBUG_BINDINGS   (1 << 2)

Definition at line 532 of file ldsodefs.h.

#define DL_DEBUG_FILES   (1 << 6)

Definition at line 536 of file ldsodefs.h.

#define DL_DEBUG_HELP   (1 << 9)

Definition at line 540 of file ldsodefs.h.

#define DL_DEBUG_IMPCALLS   (1 << 1)

Definition at line 531 of file ldsodefs.h.

#define DL_DEBUG_LIBS   (1 << 0)

Definition at line 530 of file ldsodefs.h.

#define DL_DEBUG_PRELINK   (1 << 10)

Definition at line 541 of file ldsodefs.h.

#define DL_DEBUG_RELOC   (1 << 5)

Definition at line 535 of file ldsodefs.h.

#define DL_DEBUG_STATISTICS   (1 << 7)

Definition at line 537 of file ldsodefs.h.

#define DL_DEBUG_SYMBOLS   (1 << 3)

Definition at line 533 of file ldsodefs.h.

#define DL_DEBUG_UNUSED   (1 << 8)

Definition at line 538 of file ldsodefs.h.

#define DL_DEBUG_VERSIONS   (1 << 4)

Definition at line 534 of file ldsodefs.h.

#define DL_DT_FINI_ADDRESS (   map,
  start 
)    (start)

Definition at line 74 of file ldsodefs.h.

#define DL_DT_INIT_ADDRESS (   map,
  start 
)    (start)

Definition at line 73 of file ldsodefs.h.

#define DL_LOOKUP_ADDRESS (   addr)    ((ElfW(Addr)) (addr))

Definition at line 72 of file ldsodefs.h.

#define DL_NNS   1

Definition at line 372 of file ldsodefs.h.

#define DL_STATIC_INIT (   map)

Definition at line 95 of file ldsodefs.h.

#define DL_SYMBOL_ADDRESS (   map,
  ref 
)    (void *) (LOOKUP_VALUE_ADDRESS (map) + ref->st_value)

Definition at line 70 of file ldsodefs.h.

#define DL_UNMAP (   map)
Value:
__munmap ((void *) (map)->l_map_start,                                      \
          (map)->l_map_end - (map)->l_map_start)

Definition at line 87 of file ldsodefs.h.

#define DTV_SURPLUS   (14)

Definition at line 480 of file ldsodefs.h.

#define ELF_RTYPE_CLASS_COPY   2

Definition at line 107 of file ldsodefs.h.

#define ELF_RTYPE_CLASS_PLT   1

Definition at line 105 of file ldsodefs.h.

#define ELFW (   type)    _ElfW (ELF, __ELF_NATIVE_CLASS, type)

Definition at line 47 of file ldsodefs.h.

#define EXTERN   extern

Definition at line 353 of file ldsodefs.h.

#define GL (   name)    _##name

Definition at line 354 of file ldsodefs.h.

#define GLRO (   name)    _##name

Definition at line 517 of file ldsodefs.h.

#define LOOKUP_VALUE (   map)    map

Definition at line 63 of file ldsodefs.h.

#define LOOKUP_VALUE_ADDRESS (   map)    ((map) ? (map)->l_addr : 0)

Definition at line 64 of file ldsodefs.h.

#define PF_TO_PROT
Value:
((PROT_READ << (PF_R * 4))                                           \
   | (PROT_WRITE << (PF_W * 4))                                             \
   | (PROT_EXEC << (PF_X * 4))                                              \
   | ((PROT_READ | PROT_WRITE) << ((PF_R | PF_W) * 4))                      \
   | ((PROT_READ | PROT_EXEC) << ((PF_R | PF_X) * 4))                       \
   | ((PROT_WRITE | PROT_EXEC) << (PF_W | PF_X) * 4)                        \
   | ((PROT_READ | PROT_WRITE | PROT_EXEC) << ((PF_R | PF_W | PF_X) * 4)))

Definition at line 116 of file ldsodefs.h.

#define PROCINFO_CLASS   EXTERN

Definition at line 589 of file ldsodefs.h.

#define PROCINFO_DECL

Definition at line 587 of file ldsodefs.h.

#define rtld_progname   _dl_argv[0]

Definition at line 724 of file ldsodefs.h.

#define TLS_SLOTINFO_SURPLUS   (62)

Definition at line 477 of file ldsodefs.h.


Typedef Documentation

typedef struct link_map* lookup_t

Definition at line 62 of file ldsodefs.h.

typedef void(* receiver_fct)(int, const char *, const char *)

Definition at line 341 of file ldsodefs.h.


Enumeration Type Documentation

anonymous enum
Enumerator:
DL_LOOKUP_ADD_DEPENDENCY 
DL_LOOKUP_RETURN_NEWEST 
DL_LOOKUP_GSCOPE_LOCK 

Definition at line 847 of file ldsodefs.h.

  {
    /* If necessary add dependency between user and provider object.  */
    DL_LOOKUP_ADD_DEPENDENCY = 1,
    /* Return most recent version instead of default version for
       unversioned lookup.  */
    DL_LOOKUP_RETURN_NEWEST = 2,
    /* Set if dl_lookup* called with GSCOPE lock held.  */
    DL_LOOKUP_GSCOPE_LOCK = 4,
  };
enum allowmask
Enumerator:
allow_libc 
allow_libdl 
allow_libpthread 
allow_ldso 

Definition at line 177 of file ldsodefs.h.

Enumerator:
unknown 
nonexisting 
existing 

Definition at line 139 of file ldsodefs.h.


Function Documentation

__rtld_lock_define_recursive ( EXTERN  ,
_dl_load_lock   
)
void _dl_add_to_slotinfo ( struct link_map l)

Definition at line 819 of file dl-tls.c.

{
  /* Now that we know the object is loaded successfully add
     modules containing TLS data to the dtv info table.  We
     might have to increase its size.  */
  struct dtv_slotinfo_list *listp;
  struct dtv_slotinfo_list *prevp;
  size_t idx = l->l_tls_modid;

  /* Find the place in the dtv slotinfo list.  */
  listp = GL(dl_tls_dtv_slotinfo_list);
  prevp = NULL;             /* Needed to shut up gcc.  */
  do
    {
      /* Does it fit in the array of this list element?  */
      if (idx < listp->len)
       break;
      idx -= listp->len;
      prevp = listp;
      listp = listp->next;
    }
  while (listp != NULL);

  if (listp == NULL)
    {
      /* When we come here it means we have to add a new element
        to the slotinfo list.  And the new module must be in
        the first slot.  */
      assert (idx == 0);

      listp = prevp->next = (struct dtv_slotinfo_list *)
       malloc (sizeof (struct dtv_slotinfo_list)
              + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
      if (listp == NULL)
       {
         /* We ran out of memory.  We will simply fail this
            call but don't undo anything we did so far.  The
            application will crash or be terminated anyway very
            soon.  */

         /* We have to do this since some entries in the dtv
            slotinfo array might already point to this
            generation.  */
         ++GL(dl_tls_generation);

         _dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
cannot create TLS data structures"));
       }

      listp->len = TLS_SLOTINFO_SURPLUS;
      listp->next = NULL;
      memset (listp->slotinfo, '\0',
             TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
    }

  /* Add the information into the slotinfo data structure.  */
  listp->slotinfo[idx].map = l;
  listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _dl_addr_inside_object ( struct link_map l,
const ElfW(Addr)  addr 
)

Here is the caller graph for this function:

void _dl_allocate_static_tls ( struct link_map map)

Definition at line 116 of file dl-reloc.c.

{
  if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
      || _dl_try_allocate_static_tls (map))
    {
      _dl_signal_error (0, map->l_name, NULL, N_("\
cannot allocate memory in static TLS block"));
    }
}

Here is the call graph for this function:

void* _dl_allocate_tls_init ( void *  )

Definition at line 379 of file dl-tls.c.

{
  if (result == NULL)
    /* The memory allocation failed.  */
    return NULL;

  dtv_t *dtv = GET_DTV (result);
  struct dtv_slotinfo_list *listp;
  size_t total = 0;
  size_t maxgen = 0;

  /* We have to prepare the dtv for all currently loaded modules using
     TLS.  For those which are dynamically loaded we add the values
     indicating deferred allocation.  */
  listp = GL(dl_tls_dtv_slotinfo_list);
  while (1)
    {
      size_t cnt;

      for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
       {
         struct link_map *map;
         void *dest;

         /* Check for the total number of used slots.  */
         if (total + cnt > GL(dl_tls_max_dtv_idx))
           break;

         map = listp->slotinfo[cnt].map;
         if (map == NULL)
           /* Unused entry.  */
           continue;

         /* Keep track of the maximum generation number.  This might
            not be the generation counter.  */
         maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);

         if (map->l_tls_offset == NO_TLS_OFFSET
             || map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
           {
             /* For dynamically loaded modules we simply store
               the value indicating deferred allocation.  */
             dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
             dtv[map->l_tls_modid].pointer.is_static = false;
             continue;
           }

         assert (map->l_tls_modid == cnt);
         assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
#if TLS_TCB_AT_TP
         assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
         dest = (char *) result - map->l_tls_offset;
#elif TLS_DTV_AT_TP
         dest = (char *) result + map->l_tls_offset;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif

         /* Copy the initialization image and clear the BSS part.  */
         dtv[map->l_tls_modid].pointer.val = dest;
         dtv[map->l_tls_modid].pointer.is_static = true;
         memset (__mempcpy (dest, map->l_tls_initimage,
                          map->l_tls_initimage_size), '\0',
                map->l_tls_blocksize - map->l_tls_initimage_size);
       }

      total += cnt;
      if (total >= GL(dl_tls_max_dtv_idx))
       break;

      listp = listp->next;
      assert (listp != NULL);
    }

  /* The DTV version is up-to-date now.  */
  dtv[0].counter = maxgen;

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* _dl_allocate_tls_storage ( void  )

Definition at line 331 of file dl-tls.c.

{
  void *result;
  size_t size = GL(dl_tls_static_size);

#if TLS_DTV_AT_TP
  /* Memory layout is:
     [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
                       ^ This should be returned.  */
  size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
         & ~(GL(dl_tls_static_align) - 1);
#endif

  /* Allocate a correctly aligned chunk of memory.  */
  result = __libc_memalign (GL(dl_tls_static_align), size);
  if (__builtin_expect (result != NULL, 1))
    {
      /* Allocate the DTV.  */
      void *allocated = result;

#if TLS_TCB_AT_TP
      /* The TCB follows the TLS blocks.  */
      result = (char *) result + size - TLS_TCB_SIZE;

      /* Clear the TCB data structure.  We can't ask the caller (i.e.
        libpthread) to do it, because we will initialize the DTV et al.  */
      memset (result, '\0', TLS_TCB_SIZE);
#elif TLS_DTV_AT_TP
      result = (char *) result + size - GL(dl_tls_static_size);

      /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
        We can't ask the caller (i.e. libpthread) to do it, because we will
        initialize the DTV et al.  */
      memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
             TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
#endif

      result = allocate_dtv (result);
      if (result == NULL)
       free (allocated);
    }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _dl_check_all_versions ( struct link_map map,
int  verbose,
int  trace_mode 
)

Definition at line 382 of file dl-version.c.

{
  struct link_map *l;
  int result = 0;

  for (l = map; l != NULL; l = l->l_next)
    result |= (! l->l_faked
              && _dl_check_map_versions (l, verbose, trace_mode));

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _dl_check_caller ( const void *  caller,
enum allowmask  mask 
)

Definition at line 29 of file dl-caller.c.

{
  static const char expected1[] = LIBC_SO;
  static const char expected2[] = LIBDL_SO;
#ifdef LIBPTHREAD_SO
  static const char expected3[] = LIBPTHREAD_SO;
#endif
  static const char expected4[] = LD_SO;

  for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
    for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
        l = l->l_next)
      if (caller >= (const void *) l->l_map_start
         && caller < (const void *) l->l_text_end)
       {
         /* The address falls into this DSO's address range.  Check the
            name.  */
         if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0)
           return 0;
         if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0)
           return 0;
#ifdef LIBPTHREAD_SO
         if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0)
           return 0;
#endif
         if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0)
           return 0;

         struct libname_list *runp = l->l_libname;

         while (runp != NULL)
           {
             if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0)
              return 0;
             if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0)
              return 0;
#ifdef LIBPTHREAD_SO
             if ((mask & allow_libpthread)
                && strcmp (expected3, runp->name) == 0)
              return 0;
#endif
             if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0)
              return 0;

             runp = runp->next;
           }

         break;
       }

  /* Maybe the dynamic linker is not yet on the list.  */
  if ((mask & allow_ldso) != 0
      && caller >= (const void *) GL(dl_rtld_map).l_map_start
      && caller < (const void *) GL(dl_rtld_map).l_text_end)
    return 0;

  /* No valid caller.  */
  return 1;
}

Here is the call graph for this function:

int _dl_check_map_versions ( struct link_map map,
int  verbose,
int  trace_mode 
)

Definition at line 179 of file dl-version.c.

{
  int result = 0;
  const char *strtab;
  /* Pointer to section with needed versions.  */
  ElfW(Dyn) *dyn;
  /* Pointer to dynamic section with definitions.  */
  ElfW(Dyn) *def;
  /* We need to find out which is the highest version index used
    in a dependecy.  */
  unsigned int ndx_high = 0;
  /* Initialize to make the compiler happy.  */
  const char *errstring = NULL;
  int errval = 0;

  /* If we don't have a string table, we must be ok.  */
  if (map->l_info[DT_STRTAB] == NULL)
    return 0;
  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);

  dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
  def = map->l_info[VERSYMIDX (DT_VERDEF)];

  if (dyn != NULL)
    {
      /* This file requires special versions from its dependencies.  */
      ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);

      /* Currently the version number of the needed entry is 1.
        Make sure all we see is this version.  */
      if (__builtin_expect (ent->vn_version, 1) != 1)
       {
         char buf[20];
         buf[sizeof (buf) - 1] = '\0';
         /* XXX We cannot translate the message.  */
         errstring = make_string ("unsupported version ",
                               _itoa (ent->vn_version,
                                     &buf[sizeof (buf) - 1], 10, 0),
                               " of Verneed record\n");
       call_error:
         _dl_signal_error (errval, *map->l_name ? map->l_name : rtld_progname,
                         NULL, errstring);
       }

      while (1)
       {
         ElfW(Vernaux) *aux;
         struct link_map *needed = find_needed (strtab + ent->vn_file, map);

         /* If NEEDED is NULL this means a dependency was not found
            and no stub entry was created.  This should never happen.  */
         assert (needed != NULL);

         /* Make sure this is no stub we created because of a missing
            dependency.  */
         if (__builtin_expect (! trace_mode, 1)
             || ! __builtin_expect (needed->l_faked, 0))
           {
             /* NEEDED is the map for the file we need.  Now look for the
               dependency symbols.  */
             aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
             while (1)
              {
                /* Match the symbol.  */
                result |= match_symbol ((*map->l_name
                                      ? map->l_name : rtld_progname),
                                     map->l_ns, aux->vna_hash,
                                     strtab + aux->vna_name,
                                     needed->l_real, verbose,
                                     aux->vna_flags & VER_FLG_WEAK);

                /* Compare the version index.  */
                if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
                  ndx_high = aux->vna_other & 0x7fff;

                if (aux->vna_next == 0)
                  /* No more symbols.  */
                  break;

                /* Next symbol.  */
                aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
              }
           }

         if (ent->vn_next == 0)
           /* No more dependencies.  */
           break;

         /* Next dependency.  */
         ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
       }
    }

  /* We also must store the names of the defined versions.  Determine
     the maximum index here as well.

     XXX We could avoid the loop by just taking the number of definitions
     as an upper bound of new indeces.  */
  if (def != NULL)
    {
      ElfW(Verdef) *ent;
      ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
      while (1)
       {
         if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
           ndx_high = ent->vd_ndx & 0x7fff;

         if (ent->vd_next == 0)
           /* No more definitions.  */
           break;

         ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
       }
    }

  if (ndx_high > 0)
    {
      /* Now we are ready to build the array with the version names
        which can be indexed by the version index in the VERSYM
        section.  */
      map->l_versions = (struct r_found_version *)
       calloc (ndx_high + 1, sizeof (*map->l_versions));
      if (__builtin_expect (map->l_versions == NULL, 0))
       {
         errstring = N_("cannot allocate version reference table");
         errval = ENOMEM;
         goto call_error;
       }

      /* Store the number of available symbols.  */
      map->l_nversions = ndx_high + 1;

      /* Compute the pointer to the version symbols.  */
      map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);

      if (dyn != NULL)
       {
         ElfW(Verneed) *ent;
         ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
         while (1)
           {
             ElfW(Vernaux) *aux;
             aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
             while (1)
              {
                ElfW(Half) ndx = aux->vna_other & 0x7fff;
                map->l_versions[ndx].hash = aux->vna_hash;
                map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
                map->l_versions[ndx].name = &strtab[aux->vna_name];
                map->l_versions[ndx].filename = &strtab[ent->vn_file];

                if (aux->vna_next == 0)
                  /* No more symbols.  */
                  break;

                /* Advance to next symbol.  */
                aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
              }

             if (ent->vn_next == 0)
              /* No more dependencies.  */
              break;

             /* Advance to next dependency.  */
             ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
           }
       }

      /* And insert the defined versions.  */
      if (def != NULL)
       {
         ElfW(Verdef) *ent;
         ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
         while (1)
           {
             ElfW(Verdaux) *aux;
             aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);

             if ((ent->vd_flags & VER_FLG_BASE) == 0)
              {
                /* The name of the base version should not be
                   available for matching a versioned symbol.  */
                ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
                map->l_versions[ndx].hash = ent->vd_hash;
                map->l_versions[ndx].name = &strtab[aux->vda_name];
                map->l_versions[ndx].filename = NULL;
              }

             if (ent->vd_next == 0)
              /* No more definitions.  */
              break;

             ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
           }
       }
    }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_debug_printf ( const char *  fmt,
  ... 
)
void _dl_debug_printf_c ( const char *  fmt,
  ... 
)
void _dl_debug_state ( void  )

Definition at line 75 of file dl-debug.c.

{
}

Here is the caller graph for this function:

void _dl_determine_tlsoffset ( void  )

Here is the caller graph for this function:

void void _dl_dprintf ( int  fd,
const char *  fmt,
  ... 
)
size_t _dl_dst_count ( const char *  name,
int  is_path 
)

Definition at line 220 of file dl-load.c.

{
  const char *const start = name;
  size_t cnt = 0;

  do
    {
      size_t len;

      /* $ORIGIN is not expanded for SUID/GUID programs (except if it
        is $ORIGIN alone) and it must always appear first in path.  */
      ++name;
      if ((len = is_dst (start, name, "ORIGIN", is_path,
                      INTUSE(__libc_enable_secure))) != 0
         || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
         || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
       ++cnt;

      name = strchr (name + len, '$');
    }
  while (name != NULL);

  return cnt;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* _dl_dst_substitute ( struct link_map l,
const char *  name,
char *  result,
int  is_path 
)

Definition at line 247 of file dl-load.c.

{
  const char *const start = name;
  char *last_elem, *wp;

  /* Now fill the result path.  While copying over the string we keep
     track of the start of the last path element.  When we come accross
     a DST we copy over the value or (if the value is not available)
     leave the entire path element out.  */
  last_elem = wp = result;

  do
    {
      if (__builtin_expect (*name == '$', 0))
       {
         const char *repl = NULL;
         size_t len;

         ++name;
         if ((len = is_dst (start, name, "ORIGIN", is_path,
                          INTUSE(__libc_enable_secure))) != 0)
           {
#ifndef SHARED
             if (l == NULL)
              repl = _dl_get_origin ();
             else
#endif
              repl = l->l_origin;
           }
         else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
           repl = GLRO(dl_platform);
         else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
           repl = DL_DST_LIB;

         if (repl != NULL && repl != (const char *) -1)
           {
             wp = __stpcpy (wp, repl);
             name += len;
           }
         else if (len > 1)
           {
             /* We cannot use this path element, the value of the
               replacement is unknown.  */
             wp = last_elem;
             name += len;
             while (*name != '\0' && (!is_path || *name != ':'))
              ++name;
           }
         else
           /* No DST we recognize.  */
           *wp++ = '$';
       }
      else
       {
         *wp++ = *name++;
         if (is_path && *name == ':')
           last_elem = wp;
       }
    }
  while (*name != '\0');

  *wp = '\0';

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_fini ( void  )

Definition at line 120 of file dl-fini.c.

{
  /* Lots of fun ahead.  We have to call the destructors for all still
     loaded objects, in all namespaces.  The problem is that the ELF
     specification now demands that dependencies between the modules
     are taken into account.  I.e., the destructor for a module is
     called before the ones for any of its dependencies.

     To make things more complicated, we cannot simply use the reverse
     order of the constructors.  Since the user might have loaded objects
     using `dlopen' there are possibly several other modules with its
     dependencies to be taken into account.  Therefore we have to start
     determining the order of the modules once again from the beginning.  */
  struct link_map **maps = NULL;
  size_t maps_size = 0;

  /* We run the destructors of the main namespaces last.  As for the
     other namespaces, we pick run the destructors in them in reverse
     order of the namespace ID.  */
#ifdef SHARED
  int do_audit = 0;
 again:
#endif
  for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
    {
      /* Protect against concurrent loads and unloads.  */
      __rtld_lock_lock_recursive (GL(dl_load_lock));

      unsigned int nmaps = 0;
      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
      /* No need to do anything for empty namespaces or those used for
        auditing DSOs.  */
      if (nloaded == 0
#ifdef SHARED
         || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
#endif
         )
       goto out;

      /* XXX Could it be (in static binaries) that there is no object
        loaded?  */
      assert (ns != LM_ID_BASE || nloaded > 0);

      /* Now we can allocate an array to hold all the pointers and copy
        the pointers in.  */
      if (maps_size < nloaded * sizeof (struct link_map *))
       {
         if (maps_size == 0)
           {
             maps_size = nloaded * sizeof (struct link_map *);
             maps = (struct link_map **) alloca (maps_size);
           }
         else
           maps = (struct link_map **)
             extend_alloca (maps, maps_size,
                          nloaded * sizeof (struct link_map *));
       }

      unsigned int i;
      struct link_map *l;
      assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
      for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
       /* Do not handle ld.so in secondary namespaces.  */
       if (l == l->l_real)
         {
           assert (i < nloaded);

           maps[i] = l;
           l->l_idx = i;
           ++i;

           /* Bump l_direct_opencount of all objects so that they are
              not dlclose()ed from underneath us.  */
           ++l->l_direct_opencount;
         }
      assert (ns != LM_ID_BASE || i == nloaded);
      assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
      nmaps = i;

      if (nmaps != 0)
       /* Now we have to do the sorting.  */
       _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);

      /* We do not rely on the linked list of loaded object anymore from
        this point on.  We have our own list here (maps).  The various
        members of this list cannot vanish since the open count is too
        high and will be decremented in this loop.  So we release the
        lock so that some code which might be called from a destructor
        can directly or indirectly access the lock.  */
    out:
      __rtld_lock_unlock_recursive (GL(dl_load_lock));

      /* 'maps' now contains the objects in the right order.  Now call the
        destructors.  We have to process this array from the front.  */
      for (i = 0; i < nmaps; ++i)
       {
         l = maps[i];

         if (l->l_init_called)
           {
             /* Make sure nothing happens if we are called twice.  */
             l->l_init_called = 0;

             /* Is there a destructor function?  */
             if (l->l_info[DT_FINI_ARRAY] != NULL
                || l->l_info[DT_FINI] != NULL)
              {
                /* When debugging print a message first.  */
                if (__builtin_expect (GLRO(dl_debug_mask)
                                   & DL_DEBUG_IMPCALLS, 0))
                  _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
                                  l->l_name[0] ? l->l_name : rtld_progname,
                                  ns);

                /* First see whether an array is given.  */
                if (l->l_info[DT_FINI_ARRAY] != NULL)
                  {
                    ElfW(Addr) *array =
                     (ElfW(Addr) *) (l->l_addr
                                   + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
                    unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
                                   / sizeof (ElfW(Addr)));
                    while (i-- > 0)
                     ((fini_t) array[i]) ();
                  }

                /* Next try the old-style destructor.  */
                if (l->l_info[DT_FINI] != NULL)
                  ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
              }

#ifdef SHARED
             /* Auditing checkpoint: another object closed.  */
             if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
              {
                struct audit_ifaces *afct = GLRO(dl_audit);
                for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
                  {
                    if (afct->objclose != NULL)
                     /* Return value is ignored.  */
                     (void) afct->objclose (&l->l_audit[cnt].cookie);

                    afct = afct->next;
                  }
              }
#endif
           }

         /* Correct the previous increment.  */
         --l->l_direct_opencount;
       }
    }

#ifdef SHARED
  if (! do_audit && GLRO(dl_naudit) > 0)
    {
      do_audit = 1;
      goto again;
    }

  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
    _dl_debug_printf ("\nruntime linker statistics:\n"
                    "           final number of relocations: %lu\n"
                    "final number of relocations from cache: %lu\n",
                    GL(dl_num_relocations),
                    GL(dl_num_cache_relocations));
#endif
}

Here is the call graph for this function:

const char* _dl_get_origin ( void  )

Definition at line 30 of file dl-origin.c.

{
  char *result = (char *) -1;
  /* We use the environment variable LD_ORIGIN_PATH.  If it is set make
     a copy and strip out trailing slashes.  */
  if (GLRO(dl_origin_path) != NULL)
    {
      size_t len = strlen (GLRO(dl_origin_path));
      result = (char *) malloc (len + 1);
      if (result == NULL)
       result = (char *) -1;
      else
       {
         char *cp = __mempcpy (result, GLRO(dl_origin_path), len);
         while (cp > result + 1 && cp[-1] == '/')
           --cp;
         *cp = '\0';
       }
    }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct r_strlenpair* _dl_important_hwcaps ( const char *  platform,
size_t  paltform_len,
size_t sz,
size_t max_capstrlen 
) [read]

Definition at line 304 of file dl-support.c.

{
  static struct r_strlenpair result;
  static char buf[1];

  result.str = buf;  /* Does not really matter.  */
  result.len = 0;

  *sz = 1;
  return &result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_init ( struct link_map main_map,
int  argc,
char **  argv,
char **  env 
)

Definition at line 92 of file dl-init.c.

{
  ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
  ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
  unsigned int i;

  if (__builtin_expect (GL(dl_initfirst) != NULL, 0))
    {
      call_init (GL(dl_initfirst), argc, argv, env);
      GL(dl_initfirst) = NULL;
    }

  /* Don't do anything if there is no preinit array.  */
  if (__builtin_expect (preinit_array != NULL, 0)
      && preinit_array_size != NULL
      && (i = preinit_array_size->d_un.d_val / sizeof (ElfW(Addr))) > 0)
    {
      ElfW(Addr) *addrs;
      unsigned int cnt;

      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
       _dl_debug_printf ("\ncalling preinit: %s\n\n",
                       main_map->l_name[0]
                       ? main_map->l_name : rtld_progname);

      addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr + main_map->l_addr);
      for (cnt = 0; cnt < i; ++cnt)
       ((init_t) addrs[cnt]) (argc, argv, env);
    }

  /* Stupid users forced the ELF specification to be changed.  It now
     says that the dynamic loader is responsible for determining the
     order in which the constructors have to run.  The constructors
     for all dependencies of an object must run before the constructor
     for the object itself.  Circular dependencies are left unspecified.

     This is highly questionable since it puts the burden on the dynamic
     loader which has to find the dependencies at runtime instead of
     letting the user do it right.  Stupidity rules!  */

  i = main_map->l_searchlist.r_nlist;
  while (i-- > 0)
    call_init (main_map->l_initfini[i], argc, argv, env);

#ifndef HAVE_INLINED_SYSCALLS
  /* Finished starting up.  */
  INTUSE(_dl_starting_up) = 0;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_init_paths ( const char *  library_path)

Definition at line 629 of file dl-load.c.

{
  size_t idx;
  const char *strp;
  struct r_search_path_elem *pelem, **aelem;
  size_t round_size;
#ifdef SHARED
  struct link_map *l;
#endif
  /* Initialize to please the compiler.  */
  const char *errstring = NULL;

  /* Fill in the information about the application's RPATH and the
     directories addressed by the LD_LIBRARY_PATH environment variable.  */

  /* Get the capabilities.  */
  capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen),
                             &ncapstr, &max_capstrlen);

  /* First set up the rest of the default search directory entries.  */
  aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **)
    malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *));
  if (rtld_search_dirs.dirs == NULL)
    {
      errstring = N_("cannot create search path array");
    signal_error:
      _dl_signal_error (ENOMEM, NULL, NULL, errstring);
    }

  round_size = ((2 * sizeof (struct r_search_path_elem) - 1
               + ncapstr * sizeof (enum r_dir_status))
              / sizeof (struct r_search_path_elem));

  rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
    malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
           * round_size * sizeof (struct r_search_path_elem));
  if (rtld_search_dirs.dirs[0] == NULL)
    {
      errstring = N_("cannot create cache for search path");
      goto signal_error;
    }

  rtld_search_dirs.malloced = 0;
  pelem = GL(dl_all_dirs) = rtld_search_dirs.dirs[0];
  strp = system_dirs;
  idx = 0;

  do
    {
      size_t cnt;

      *aelem++ = pelem;

      pelem->what = "system search path";
      pelem->where = NULL;

      pelem->dirname = strp;
      pelem->dirnamelen = system_dirs_len[idx];
      strp += system_dirs_len[idx] + 1;

      /* System paths must be absolute.  */
      assert (pelem->dirname[0] == '/');
      for (cnt = 0; cnt < ncapstr; ++cnt)
       pelem->status[cnt] = unknown;

      pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size));

      pelem += round_size;
    }
  while (idx < nsystem_dirs_len);

  max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
  *aelem = NULL;

#ifdef SHARED
  /* This points to the map of the main object.  */
  l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
  if (l != NULL)
    {
      assert (l->l_type != lt_loaded);

      if (l->l_info[DT_RUNPATH])
       {
         /* Allocate room for the search path and fill in information
            from RUNPATH.  */
         decompose_rpath (&l->l_runpath_dirs,
                        (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                      + l->l_info[DT_RUNPATH]->d_un.d_val),
                        l, "RUNPATH");

         /* The RPATH is ignored.  */
         l->l_rpath_dirs.dirs = (void *) -1;
       }
      else
       {
         l->l_runpath_dirs.dirs = (void *) -1;

         if (l->l_info[DT_RPATH])
           {
             /* Allocate room for the search path and fill in information
               from RPATH.  */
             decompose_rpath (&l->l_rpath_dirs,
                            (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                          + l->l_info[DT_RPATH]->d_un.d_val),
                            l, "RPATH");
             l->l_rpath_dirs.malloced = 0;
           }
         else
           l->l_rpath_dirs.dirs = (void *) -1;
       }
    }
#endif /* SHARED */

  if (llp != NULL && *llp != '\0')
    {
      size_t nllp;
      const char *cp = llp;
      char *llp_tmp;

#ifdef SHARED
      /* Expand DSTs.  */
      size_t cnt = DL_DST_COUNT (llp, 1);
      if (__builtin_expect (cnt == 0, 1))
       llp_tmp = strdupa (llp);
      else
       {
         /* Determine the length of the substituted string.  */
         size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);

         /* Allocate the necessary memory.  */
         llp_tmp = (char *) alloca (total + 1);
         llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
       }
#else
      llp_tmp = strdupa (llp);
#endif

      /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
        elements it has.  */
      nllp = 1;
      while (*cp)
       {
         if (*cp == ':' || *cp == ';')
           ++nllp;
         ++cp;
       }

      env_path_list.dirs = (struct r_search_path_elem **)
       malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
      if (env_path_list.dirs == NULL)
       {
         errstring = N_("cannot create cache for search path");
         goto signal_error;
       }

      (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
                        INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH",
                        NULL);

      if (env_path_list.dirs[0] == NULL)
       {
         free (env_path_list.dirs);
         env_path_list.dirs = (void *) -1;
       }

      env_path_list.malloced = 0;
    }
  else
    env_path_list.dirs = (void *) -1;

  /* Remember the last search directory added at startup.  */
  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
}

Here is the call graph for this function:

const char* _dl_load_cache_lookup ( const char *  name)

Definition at line 170 of file dl-cache.c.

{
  int left, right, middle;
  int cmpres;
  const char *cache_data;
  uint32_t cache_data_size;
  const char *best;

  /* Print a message if the loading of libs is traced.  */
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
    _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);

  if (cache == NULL)
    {
      /* Read the contents of the file.  */
      void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
                                          PROT_READ);

      /* We can handle three different cache file formats here:
        - the old libc5/glibc2.0/2.1 format
        - the old format with the new format in it
        - only the new format
        The following checks if the cache contains any of these formats.  */
      if (file != MAP_FAILED && cachesize > sizeof *cache
         && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
       {
         size_t offset;
         /* Looks ok.  */
         cache = file;

         /* Check for new version.  */
         offset = ALIGN_CACHE (sizeof (struct cache_file)
                            + cache->nlibs * sizeof (struct file_entry));

         cache_new = (struct cache_file_new *) ((void *) cache + offset);
         if (cachesize < (offset + sizeof (struct cache_file_new))
             || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
                      sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
           cache_new = (void *) -1;
       }
      else if (file != MAP_FAILED && cachesize > sizeof *cache_new
              && memcmp (file, CACHEMAGIC_VERSION_NEW,
                       sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
       {
         cache_new = file;
         cache = file;
       }
      else
       {
         if (file != MAP_FAILED)
           __munmap (file, cachesize);
         cache = (void *) -1;
       }

      assert (cache != NULL);
    }

  if (cache == (void *) -1)
    /* Previously looked for the cache file and didn't find it.  */
    return NULL;

  best = NULL;

  if (cache_new != (void *) -1)
    {
      uint64_t platform;

      /* This is where the strings start.  */
      cache_data = (const char *) cache_new;

      /* Now we can compute how large the string table is.  */
      cache_data_size = (const char *) cache + cachesize - cache_data;

      platform = _dl_string_platform (GLRO(dl_platform));
      if (platform != (uint64_t) -1)
       platform = 1ULL << platform;

      /* Only accept hwcap if it's for the right platform.  */
#define _DL_HWCAP_TLS_MASK (1LL << 63)
#define HWCAP_CHECK \
      if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion))        \
       continue;                                                     \
      if (_DL_PLATFORMS_COUNT                                               \
         && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0                          \
         && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform)                  \
       continue;                                                     \
      if (lib->hwcap                                                 \
         & ~(GLRO(dl_hwcap) | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK))      \
       continue
      SEARCH_CACHE (cache_new);
    }
  else
    {
      /* This is where the strings start.  */
      cache_data = (const char *) &cache->libs[cache->nlibs];

      /* Now we can compute how large the string table is.  */
      cache_data_size = (const char *) cache + cachesize - cache_data;

#undef HWCAP_CHECK

Here is the caller graph for this function:

lookup_t _dl_lookup_symbol_x ( const char *  undef,
struct link_map undef_map,
const ElfW(Sym)**  sym,
struct r_scope_elem symbol_scope[],
const struct r_found_version version,
int  type_class,
int  flags,
struct link_map skip_map 
)

Definition at line 310 of file dl-lookup.c.

{
  const uint_fast32_t new_hash = dl_new_hash (undef_name);
  unsigned long int old_hash = 0xffffffff;
  struct sym_val current_value = { NULL, NULL };
  struct r_scope_elem **scope = symbol_scope;

  bump_num_relocations ();

  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
     is allowed if we look up a versioned symbol.  */
  assert (version == NULL
         || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
            == 0);

  size_t i = 0;
  if (__builtin_expect (skip_map != NULL, 0))
    /* Search the relevant loaded objects for a definition.  */
    while ((*scope)->r_list[i] != skip_map)
      ++i;

  /* Search the relevant loaded objects for a definition.  */
  for (size_t start = i; *scope != NULL; start = 0, ++scope)
    {
      int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
                          &current_value, *scope, start, version, flags,
                          skip_map, type_class);
      if (res > 0)
       break;

      if (__builtin_expect (res, 0) < 0 && skip_map == NULL)
       {
         /* Oh, oh.  The file named in the relocation entry does not
            contain the needed symbol.  This code is never reached
            for unversioned lookups.  */
         assert (version != NULL);
         const char *reference_name = undef_map ? undef_map->l_name : NULL;

         /* XXX We cannot translate the message.  */
         _dl_signal_cerror (0, (reference_name[0]
                             ? reference_name
                             : (rtld_progname ?: "<main program>")),
                          N_("relocation error"),
                          make_string ("symbol ", undef_name, ", version ",
                                     version->name,
                                     " not defined in file ",
                                     version->filename,
                                     " with link time reference",
                                     res == -2
                                     ? " (no version symbols)" : ""));
         *ref = NULL;
         return 0;
       }
    }

  if (__builtin_expect (current_value.s == NULL, 0))
    {
      if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
         && skip_map == NULL)
       {
         /* We could find no value for a strong reference.  */
         const char *reference_name = undef_map ? undef_map->l_name : "";
         const char *versionstr = version ? ", version " : "";
         const char *versionname = (version && version->name
                                 ? version->name : "");

         /* XXX We cannot translate the message.  */
         _dl_signal_cerror (0, (reference_name[0]
                             ? reference_name
                             : (rtld_progname ?: "<main program>")),
                          N_("symbol lookup error"),
                          make_string (undefined_msg, undef_name,
                                     versionstr, versionname));
       }
      *ref = NULL;
      return 0;
    }

  int protected = (*ref
                 && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
  if (__builtin_expect (protected != 0, 0))
    {
      /* It is very tricky.  We need to figure out what value to
         return for the protected symbol.  */
      if (type_class == ELF_RTYPE_CLASS_PLT)
       {
         if (current_value.s != NULL && current_value.m != undef_map)
           {
             current_value.s = *ref;
             current_value.m = undef_map;
           }
       }
      else
       {
         struct sym_val protected_value = { NULL, NULL };

         for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
           if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
                          &protected_value, *scope, i, version, flags,
                          skip_map, ELF_RTYPE_CLASS_PLT) != 0)
             break;

         if (protected_value.s != NULL && protected_value.m != undef_map)
           {
             current_value.s = *ref;
             current_value.m = undef_map;
           }
       }
    }

  /* We have to check whether this would bind UNDEF_MAP to an object
     in the global scope which was dynamically loaded.  In this case
     we have to prevent the latter from being unloaded unless the
     UNDEF_MAP object is also unloaded.  */
  if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
      /* Don't do this for explicit lookups as opposed to implicit
        runtime lookups.  */
      && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
      /* Add UNDEF_MAP to the dependencies.  */
      && add_dependency (undef_map, current_value.m, flags) < 0)
      /* Something went wrong.  Perhaps the object we tried to reference
        was just removed.  Try finding another definition.  */
      return _dl_lookup_symbol_x (undef_name, undef_map, ref,
                              (flags & DL_LOOKUP_GSCOPE_LOCK)
                              ? undef_map->l_scope : symbol_scope,
                              version, type_class, flags, skip_map);

  /* The object is used.  */
  current_value.m->l_used = 1;

  if (__builtin_expect (GLRO(dl_debug_mask)
                     & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
    _dl_debug_bindings (undef_name, undef_map, ref,
                     &current_value, version, type_class, protected);

  *ref = current_value.s;
  return LOOKUP_VALUE (current_value.m);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _dl_make_stack_executable ( void **  stack_endp)

Definition at line 28 of file dl-execstack.c.

{
  return ENOSYS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct link_map* _dl_map_object ( struct link_map loader,
const char *  name,
int  preloaded,
int  type,
int  trace_mode,
int  mode,
Lmid_t  nsid 
) [read]

Definition at line 1957 of file dl-load.c.

{
  int fd;
  char *realname;
  char *name_copy;
  struct link_map *l;
  struct filebuf fb;

  assert (nsid >= 0);
  assert (nsid < DL_NNS);

  /* Look for this name among those already loaded.  */
  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
    {
      /* If the requested name matches the soname of a loaded object,
        use that object.  Elide this check for names that have not
        yet been opened.  */
      if (__builtin_expect (l->l_faked, 0) != 0
         || __builtin_expect (l->l_removed, 0) != 0)
       continue;
      if (!_dl_name_match_p (name, l))
       {
         const char *soname;

         if (__builtin_expect (l->l_soname_added, 1)
             || l->l_info[DT_SONAME] == NULL)
           continue;

         soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
                  + l->l_info[DT_SONAME]->d_un.d_val);
         if (strcmp (name, soname) != 0)
           continue;

         /* We have a match on a new name -- cache it.  */
         add_name_to_object (l, soname);
         l->l_soname_added = 1;
       }

      /* We have a match.  */
      return l;
    }

  /* Display information if we are debugging.  */
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
      && loader != NULL)
    _dl_debug_printf ("\nfile=%s [%lu];  needed by %s [%lu]\n", name, nsid,
                           loader->l_name[0]
                           ? loader->l_name : rtld_progname, loader->l_ns);

#ifdef SHARED
  /* Give the auditing libraries a chance to change the name before we
     try anything.  */
  if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
      && (loader == NULL || loader->l_auditing == 0))
    {
      struct audit_ifaces *afct = GLRO(dl_audit);
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
       {
         if (afct->objsearch != NULL)
           {
             name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
                                  LA_SER_ORIG);
             if (name == NULL)
              {
                /* Do not try anything further.  */
                fd = -1;
                goto no_file;
              }
           }

         afct = afct->next;
       }
    }
#endif

  /* Will be true if we found a DSO which is of the other ELF class.  */
  bool found_other_class = false;

  if (strchr (name, '/') == NULL)
    {
      /* Search for NAME in several places.  */

      size_t namelen = strlen (name) + 1;

      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
       _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);

      fd = -1;

      /* When the object has the RUNPATH information we don't use any
         RPATHs.  */
      if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL)
       {
         /* This is the executable's map (if there is one).  Make sure that
            we do not look at it twice.  */
         struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
         bool did_main_map = false;

         /* First try the DT_RPATH of the dependent object that caused NAME
            to be loaded.  Then that object's dependent, and on up.  */
         for (l = loader; l; l = l->l_loader)
           if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
             {
              fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
                            &realname, &fb, loader, LA_SER_RUNPATH,
                            &found_other_class);
              if (fd != -1)
                break;

              did_main_map |= l == main_map;
             }

         /* If dynamically linked, try the DT_RPATH of the executable
             itself.  NB: we do this for lookups in any namespace.  */
         if (fd == -1 && !did_main_map
             && main_map != NULL && main_map->l_type != lt_loaded
             && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
                           "RPATH"))
           fd = open_path (name, namelen, preloaded, &main_map->l_rpath_dirs,
                         &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
                         &found_other_class);
       }

      /* Try the LD_LIBRARY_PATH environment variable.  */
      if (fd == -1 && env_path_list.dirs != (void *) -1)
       fd = open_path (name, namelen, preloaded, &env_path_list,
                     &realname, &fb,
                     loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
                     LA_SER_LIBPATH, &found_other_class);

      /* Look at the RUNPATH information for this binary.  */
      if (fd == -1 && loader != NULL
         && cache_rpath (loader, &loader->l_runpath_dirs,
                       DT_RUNPATH, "RUNPATH"))
       fd = open_path (name, namelen, preloaded,
                     &loader->l_runpath_dirs, &realname, &fb, loader,
                     LA_SER_RUNPATH, &found_other_class);

      if (fd == -1
         && (__builtin_expect (! preloaded, 1)
             || ! INTUSE(__libc_enable_secure)))
       {
         /* Check the list of libraries in the file /etc/ld.so.cache,
            for compatibility with Linux's ldconfig program.  */
         const char *cached = _dl_load_cache_lookup (name);

         if (cached != NULL)
           {
#ifdef SHARED
             // XXX Correct to unconditionally default to namespace 0?
             l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded;
#else
             l = loader;
#endif

             /* If the loader has the DF_1_NODEFLIB flag set we must not
               use a cache entry from any of these directories.  */
             if (
#ifndef SHARED
                /* 'l' is always != NULL for dynamically linked objects.  */
                l != NULL &&
#endif
                __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0))
              {
                const char *dirp = system_dirs;
                unsigned int cnt = 0;

                do
                  {
                    if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
                     {
                       /* The prefix matches.  Don't use the entry.  */
                       cached = NULL;
                       break;
                     }

                    dirp += system_dirs_len[cnt] + 1;
                    ++cnt;
                  }
                while (cnt < nsystem_dirs_len);
              }

             if (cached != NULL)
              {
                fd = open_verify (cached,
                                &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
                                LA_SER_CONFIG, &found_other_class, false);
                if (__builtin_expect (fd != -1, 1))
                  {
                    realname = local_strdup (cached);
                    if (realname == NULL)
                     {
                       __close (fd);
                       fd = -1;
                     }
                  }
              }
           }
       }

      /* Finally, try the default path.  */
      if (fd == -1
         && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
             || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
         && rtld_search_dirs.dirs != (void *) -1)
       fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
                     &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);

      /* Add another newline when we are tracing the library loading.  */
      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
        _dl_debug_printf ("\n");
    }
  else
    {
      /* The path may contain dynamic string tokens.  */
      realname = (loader
                ? expand_dynamic_string_token (loader, name)
                : local_strdup (name));
      if (realname == NULL)
       fd = -1;
      else
       {
         fd = open_verify (realname, &fb,
                         loader ?: GL(dl_ns)[nsid]._ns_loaded, 0,
                         &found_other_class, true);
         if (__builtin_expect (fd, 0) == -1)
           free (realname);
       }
    }

#ifdef SHARED
 no_file:
#endif
  /* In case the LOADER information has only been provided to get to
     the appropriate RUNPATH/RPATH information we do not need it
     anymore.  */
  if (mode & __RTLD_CALLMAP)
    loader = NULL;

  if (__builtin_expect (fd, 0) == -1)
    {
      if (trace_mode
         && __builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) == 0)
       {
         /* We haven't found an appropriate library.  But since we
            are only interested in the list of libraries this isn't
            so severe.  Fake an entry with all the information we
            have.  */
         static const Elf_Symndx dummy_bucket = STN_UNDEF;

         /* Enter the new object in the list of loaded objects.  */
         if ((name_copy = local_strdup (name)) == NULL
             || (l = _dl_new_object (name_copy, name, type, loader,
                                  mode, nsid)) == NULL)
           {
             free (name_copy);
             _dl_signal_error (ENOMEM, name, NULL,
                            N_("cannot create shared object descriptor"));
           }
         /* Signal that this is a faked entry.  */
         l->l_faked = 1;
         /* Since the descriptor is initialized with zero we do not
            have do this here.
         l->l_reserved = 0; */
         l->l_buckets = &dummy_bucket;
         l->l_nbuckets = 1;
         l->l_relocated = 1;

         return l;
       }
      else if (found_other_class)
       _dl_signal_error (0, name, NULL,
                       ELFW(CLASS) == ELFCLASS32
                       ? N_("wrong ELF class: ELFCLASS64")
                       : N_("wrong ELF class: ELFCLASS32"));
      else
       _dl_signal_error (errno, name, NULL,
                       N_("cannot open shared object file"));
    }

  void *stack_end = __libc_stack_end;
  return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
                             &stack_end, nsid);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_map_object_deps ( struct link_map map,
struct link_map **  preloads,
unsigned int  npreloads,
int  trace_mode,
int  open_mode 
)

Definition at line 145 of file dl-deps.c.

{
  struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
  struct list *runp, *tail;
  unsigned int nlist, i;
  /* Object name.  */
  const char *name;
  int errno_saved;
  int errno_reason;
  const char *errstring;
  const char *objname;

  auto inline void preload (struct link_map *map);

  inline void preload (struct link_map *map)
    {
      known[nlist].done = 0;
      known[nlist].map = map;
      known[nlist].next = &known[nlist + 1];

      ++nlist;
      /* We use `l_reserved' as a mark bit to detect objects we have
        already put in the search list and avoid adding duplicate
        elements later in the list.  */
      map->l_reserved = 1;
    }

  /* No loaded object so far.  */
  nlist = 0;

  /* First load MAP itself.  */
  preload (map);

  /* Add the preloaded items after MAP but before any of its dependencies.  */
  for (i = 0; i < npreloads; ++i)
    preload (preloads[i]);

  /* Terminate the lists.  */
  known[nlist - 1].next = NULL;

  /* Pointer to last unique object.  */
  tail = &known[nlist - 1];

  /* Process each element of the search list, loading each of its
     auxiliary objects and immediate dependencies.  Auxiliary objects
     will be added in the list before the object itself and
     dependencies will be appended to the list as we step through it.
     This produces a flat, ordered list that represents a
     breadth-first search of the dependency tree.

     The whole process is complicated by the fact that we better
     should use alloca for the temporary list elements.  But using
     alloca means we cannot use recursive function calls.  */
  errno_saved = errno;
  errno_reason = 0;
  errstring = NULL;
  errno = 0;
  name = NULL;
  for (runp = known; runp; )
    {
      struct link_map *l = runp->map;
      struct link_map **needed = NULL;
      unsigned int nneeded = 0;

      /* Unless otherwise stated, this object is handled.  */
      runp->done = 1;

      /* Allocate a temporary record to contain the references to the
        dependencies of this object.  */
      if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
         && l != map && l->l_ldnum > 0)
       needed = (struct link_map **) alloca (l->l_ldnum
                                         * sizeof (struct link_map *));

      if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
       {
         const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
         struct openaux_args args;
         struct list *orig;
         const ElfW(Dyn) *d;

         args.strtab = strtab;
         args.map = l;
         args.trace_mode = trace_mode;
         args.open_mode = open_mode;
         orig = runp;

         for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
           if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
             {
              /* Map in the needed object.  */
              struct link_map *dep;

              /* Recognize DSTs.  */
              name = expand_dst (l, strtab + d->d_un.d_val, 0);
              /* Store the tag in the argument structure.  */
              args.name = name;

              bool malloced;
              int err = _dl_catch_error (&objname, &errstring, &malloced,
                                      openaux, &args);
              if (__builtin_expect (errstring != NULL, 0))
                {
                  char *new_errstring = strdupa (errstring);
                  objname = strdupa (objname);
                  if (malloced)
                    free ((char *) errstring);
                  errstring = new_errstring;

                  if (err)
                    errno_reason = err;
                  else
                    errno_reason = -1;
                  goto out;
                }
              else
                dep = args.aux;

              if (! dep->l_reserved)
                {
                  /* Allocate new entry.  */
                  struct list *newp;

                  newp = alloca (sizeof (struct list));

                  /* Append DEP to the list.  */
                  newp->map = dep;
                  newp->done = 0;
                  newp->next = NULL;
                  tail->next = newp;
                  tail = newp;
                  ++nlist;
                  /* Set the mark bit that says it's already in the list.  */
                  dep->l_reserved = 1;
                }

              /* Remember this dependency.  */
              if (needed != NULL)
                needed[nneeded++] = dep;
             }
           else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
             {
              struct list *newp;

              /* Recognize DSTs.  */
              name = expand_dst (l, strtab + d->d_un.d_val,
                               d->d_tag == DT_AUXILIARY);
              /* Store the tag in the argument structure.  */
              args.name = name;

              if (d->d_tag == DT_AUXILIARY)
                {
                  /* Say that we are about to load an auxiliary library.  */
                  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
                                     0))
                    _dl_debug_printf ("load auxiliary object=%s"
                                   " requested by file=%s\n",
                                   name,
                                   l->l_name[0]
                                   ? l->l_name : rtld_progname);

                  /* We must be prepared that the addressed shared
                     object is not available.  */
                  bool malloced;
                  (void) _dl_catch_error (&objname, &errstring, &malloced,
                                       openaux, &args);
                  if (__builtin_expect (errstring != NULL, 0))
                    {
                     /* We are not interested in the error message.  */
                     assert (errstring != NULL);
                     if (malloced)
                       free ((char *) errstring);

                     /* Simply ignore this error and continue the work.  */
                     continue;
                    }
                }
              else
                {
                  /* Say that we are about to load an auxiliary library.  */
                  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
                                     0))
                    _dl_debug_printf ("load filtered object=%s"
                                   " requested by file=%s\n",
                                   name,
                                   l->l_name[0]
                                   ? l->l_name : rtld_progname);

                  /* For filter objects the dependency must be available.  */
                  bool malloced;
                  int err = _dl_catch_error (&objname, &errstring, &malloced,
                                          openaux, &args);
                  if (__builtin_expect (errstring != NULL, 0))
                    {
                     char *new_errstring = strdupa (errstring);
                     objname = strdupa (objname);
                     if (malloced)
                       free ((char *) errstring);
                     errstring = new_errstring;

                     if (err)
                       errno_reason = err;
                     else
                       errno_reason = -1;
                     goto out;
                    }
                }

              /* The auxiliary object is actually available.
                 Incorporate the map in all the lists.  */

              /* Allocate new entry.  This always has to be done.  */
              newp = alloca (sizeof (struct list));

              /* We want to insert the new map before the current one,
                 but we have no back links.  So we copy the contents of
                 the current entry over.  Note that ORIG and NEWP now
                 have switched their meanings.  */
              memcpy (newp, orig, sizeof (*newp));

              /* Initialize new entry.  */
              orig->done = 0;
              orig->map = args.aux;

              /* Remember this dependency.  */
              if (needed != NULL)
                needed[nneeded++] = args.aux;

              /* We must handle two situations here: the map is new,
                 so we must add it in all three lists.  If the map
                 is already known, we have two further possibilities:
                 - if the object is before the current map in the
                 search list, we do nothing.  It is already found
                 early
                 - if the object is after the current one, we must
                 move it just before the current map to make sure
                 the symbols are found early enough
              */
              if (args.aux->l_reserved)
                {
                  /* The object is already somewhere in the list.
                     Locate it first.  */
                  struct list *late;

                  /* This object is already in the search list we
                     are building.  Don't add a duplicate pointer.
                     Just added by _dl_map_object.  */
                  for (late = newp; late->next != NULL; late = late->next)
                    if (late->next->map == args.aux)
                     break;

                  if (late->next != NULL)
                    {
                     /* The object is somewhere behind the current
                        position in the search path.  We have to
                        move it to this earlier position.  */
                     orig->next = newp;

                     /* Now remove the later entry from the list
                        and adjust the tail pointer.  */
                     if (tail == late->next)
                       tail = late;
                     late->next = late->next->next;

                     /* We must move the object earlier in the chain.  */
                     if (args.aux->l_prev != NULL)
                       args.aux->l_prev->l_next = args.aux->l_next;
                     if (args.aux->l_next != NULL)
                       args.aux->l_next->l_prev = args.aux->l_prev;

                     args.aux->l_prev = newp->map->l_prev;
                     newp->map->l_prev = args.aux;
                     if (args.aux->l_prev != NULL)
                       args.aux->l_prev->l_next = args.aux;
                     args.aux->l_next = newp->map;
                    }
                  else
                    {
                     /* The object must be somewhere earlier in the
                        list.  Undo to the current list element what
                        we did above.  */
                     memcpy (orig, newp, sizeof (*newp));
                     continue;
                    }
                }
              else
                {
                  /* This is easy.  We just add the symbol right here.  */
                  orig->next = newp;
                  ++nlist;
                  /* Set the mark bit that says it's already in the list.  */
                  args.aux->l_reserved = 1;

                  /* The only problem is that in the double linked
                     list of all objects we don't have this new
                     object at the correct place.  Correct this here.  */
                  if (args.aux->l_prev)
                    args.aux->l_prev->l_next = args.aux->l_next;
                  if (args.aux->l_next)
                    args.aux->l_next->l_prev = args.aux->l_prev;

                  args.aux->l_prev = newp->map->l_prev;
                  newp->map->l_prev = args.aux;
                  if (args.aux->l_prev != NULL)
                    args.aux->l_prev->l_next = args.aux;
                  args.aux->l_next = newp->map;
                }

              /* Move the tail pointer if necessary.  */
              if (orig == tail)
                tail = newp;

              /* Move on the insert point.  */
              orig = newp;
             }
       }

      /* Terminate the list of dependencies and store the array address.  */
      if (needed != NULL)
       {
         needed[nneeded++] = NULL;

         struct link_map **l_initfini = (struct link_map **)
           malloc ((2 * nneeded + 1) * sizeof needed[0]);
         if (l_initfini == NULL)
           _dl_signal_error (ENOMEM, map->l_name, NULL,
                           N_("cannot allocate dependency list"));
         l_initfini[0] = l;
         memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
         memcpy (&l_initfini[nneeded + 1], l_initfini,
                nneeded * sizeof needed[0]);
         atomic_write_barrier ();
         l->l_initfini = l_initfini;
       }

      /* If we have no auxiliary objects just go on to the next map.  */
      if (runp->done)
       do
         runp = runp->next;
       while (runp != NULL && runp->done);
    }

 out:
  if (errno == 0 && errno_saved != 0)
    __set_errno (errno_saved);

  struct link_map **old_l_initfini = NULL;
  if (map->l_initfini != NULL && map->l_type == lt_loaded)
    {
      /* This object was previously loaded as a dependency and we have
        a separate l_initfini list.  We don't need it anymore.  */
      assert (map->l_searchlist.r_list == NULL);
      old_l_initfini = map->l_initfini;
    }

  /* Store the search list we built in the object.  It will be used for
     searches in the scope of this object.  */
  struct link_map **l_initfini =
    (struct link_map **) malloc ((2 * nlist + 1)
                             * sizeof (struct link_map *));
  if (l_initfini == NULL)
    _dl_signal_error (ENOMEM, map->l_name, NULL,
                    N_("cannot allocate symbol search list"));


  map->l_searchlist.r_list = &l_initfini[nlist + 1];
  map->l_searchlist.r_nlist = nlist;

  for (nlist = 0, runp = known; runp; runp = runp->next)
    {
      if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
       /* This can happen when we trace the loading.  */
       --map->l_searchlist.r_nlist;
      else
       map->l_searchlist.r_list[nlist++] = runp->map;

      /* Now clear all the mark bits we set in the objects on the search list
        to avoid duplicates, so the next call starts fresh.  */
      runp->map->l_reserved = 0;
    }

  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
      && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
    {
      /* If we are to compute conflicts, we have to build local scope
        for each library, not just the ultimate loader.  */
      for (i = 0; i < nlist; ++i)
       {
         struct link_map *l = map->l_searchlist.r_list[i];
         unsigned int j, cnt;

         /* The local scope has been already computed.  */
         if (l == map
             || (l->l_local_scope[0]
                && l->l_local_scope[0]->r_nlist) != 0)
           continue;

         if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
           {
             /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
               rewritten, no need to bother with prelinking the old
               implementation.  */
             _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
Filters not supported with LD_TRACE_PRELINKING"));
           }

         cnt = _dl_build_local_scope (l_initfini, l);
         assert (cnt <= nlist);
         for (j = 0; j < cnt; j++)
           l_initfini[j]->l_reserved = 0;

         l->l_local_scope[0] =
           (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
                                       + (cnt
                                          * sizeof (struct link_map *)));
         if (l->l_local_scope[0] == NULL)
           _dl_signal_error (ENOMEM, map->l_name, NULL,
                           N_("cannot allocate symbol search list"));
         l->l_local_scope[0]->r_nlist = cnt;
         l->l_local_scope[0]->r_list =
           (struct link_map **) (l->l_local_scope[0] + 1);
         memcpy (l->l_local_scope[0]->r_list, l_initfini,
                cnt * sizeof (struct link_map *));
       }
    }

  /* Maybe we can remove some relocation dependencies now.  */
  assert (map->l_searchlist.r_list[0] == map);
  struct link_map_reldeps *l_reldeps = NULL;
  if (map->l_reldeps != NULL)
    {
      for (i = 1; i < nlist; ++i)
       map->l_searchlist.r_list[i]->l_reserved = 1;

      struct link_map **list = &map->l_reldeps->list[0];
      for (i = 0; i < map->l_reldeps->act; ++i)
       if (list[i]->l_reserved)
         {
           /* Need to allocate new array of relocation dependencies.  */
           struct link_map_reldeps *l_reldeps;
           l_reldeps = malloc (sizeof (*l_reldeps)
                            + map->l_reldepsmax
                              * sizeof (struct link_map *));
           if (l_reldeps == NULL)
             /* Bad luck, keep the reldeps duplicated between
               map->l_reldeps->list and map->l_initfini lists.  */
             ;
           else
             {
              unsigned int j = i;
              memcpy (&l_reldeps->list[0], &list[0],
                     i * sizeof (struct link_map *));
              for (i = i + 1; i < map->l_reldeps->act; ++i)
                if (!list[i]->l_reserved)
                  l_reldeps->list[j++] = list[i];
              l_reldeps->act = j;
             }
         }

      for (i = 1; i < nlist; ++i)
       map->l_searchlist.r_list[i]->l_reserved = 0;
    }

  /* Now determine the order in which the initialization has to happen.  */
  memcpy (l_initfini, map->l_searchlist.r_list,
         nlist * sizeof (struct link_map *));
  /* We can skip looking for the binary itself which is at the front
     of the search list.  Look through the list backward so that circular
     dependencies are not changing the order.  */
  for (i = 1; i < nlist; ++i)
    {
      struct link_map *l = map->l_searchlist.r_list[i];
      unsigned int j;
      unsigned int k;

      /* Find the place in the initfini list where the map is currently
        located.  */
      for (j = 1; l_initfini[j] != l; ++j)
       ;

      /* Find all object for which the current one is a dependency and
        move the found object (if necessary) in front.  */
      for (k = j + 1; k < nlist; ++k)
       {
         struct link_map **runp;

         runp = l_initfini[k]->l_initfini;
         if (runp != NULL)
           {
             while (*runp != NULL)
              if (__builtin_expect (*runp++ == l, 0))
                {
                  struct link_map *here = l_initfini[k];

                  /* Move it now.  */
                  memmove (&l_initfini[j] + 1, &l_initfini[j],
                          (k - j) * sizeof (struct link_map *));
                  l_initfini[j] = here;

                  /* Don't insert further matches before the last
                     entry moved to the front.  */
                  ++j;

                  break;
                }
           }
       }
    }
  /* Terminate the list of dependencies.  */
  l_initfini[nlist] = NULL;
  atomic_write_barrier ();
  map->l_initfini = l_initfini;
  if (l_reldeps != NULL)
    {
      atomic_write_barrier ();
      void *old_l_reldeps = map->l_reldeps;
      map->l_reldeps = l_reldeps;
      _dl_scope_free (old_l_reldeps);
    }
  if (old_l_initfini != NULL)
    _dl_scope_free (old_l_initfini);

  if (errno_reason)
    _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname,
                    NULL, errstring);

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_mcount ( ElfW(Addr)  frompc,
ElfW(Addr)  selfpc 
)

Definition at line 450 of file dl-profile.c.

{
  volatile uint16_t *topcindex;
  size_t i, fromindex;
  struct here_fromstruct *fromp;

  if (! running)
    return;

  /* Compute relative addresses.  The shared object can be loaded at
     any address.  The value of frompc could be anything.  We cannot
     restrict it in any way, just set to a fixed value (0) in case it
     is outside the allowed range.  These calls show up as calls from
     <external> in the gprof output.  */
  frompc -= lowpc;
  if (frompc >= textsize)
    frompc = 0;
  selfpc -= lowpc;
  if (selfpc >= textsize)
    goto done;

  /* Getting here we now have to find out whether the location was
     already used.  If yes we are lucky and only have to increment a
     counter (this also has to be atomic).  If the entry is new things
     are getting complicated...  */

  /* Avoid integer divide if possible.  */
  if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)
    i = selfpc >> log_hashfraction;
  else
    i = selfpc / (HASHFRACTION * sizeof (*tos));

  topcindex = &tos[i];
  fromindex = *topcindex;

  if (fromindex == 0)
    goto check_new_or_add;

  fromp = &froms[fromindex];

  /* We have to look through the chain of arcs whether there is already
     an entry for our arc.  */
  while (fromp->here->from_pc != frompc)
    {
      if (fromp->link != 0)
       do
         fromp = &froms[fromp->link];
       while (fromp->link != 0 && fromp->here->from_pc != frompc);

      if (fromp->here->from_pc != frompc)
       {
         topcindex = &fromp->link;

       check_new_or_add:
         /* Our entry is not among the entries we read so far from the
            data file.  Now see whether we have to update the list.  */
         while (narcs != *narcsp && narcs < fromlimit)
           {
             size_t to_index;
             size_t newfromidx;
             to_index = (data[narcs].self_pc
                       / (HASHFRACTION * sizeof (*tos)));
             newfromidx = catomic_exchange_and_add (&fromidx, 1) + 1;
             froms[newfromidx].here = &data[narcs];
             froms[newfromidx].link = tos[to_index];
             tos[to_index] = newfromidx;
             catomic_increment (&narcs);
           }

         /* If we still have no entry stop searching and insert.  */
         if (*topcindex == 0)
           {
             uint_fast32_t newarc = catomic_exchange_and_add (narcsp, 1);

             /* In rare cases it could happen that all entries in FROMS are
               occupied.  So we cannot count this anymore.  */
             if (newarc >= fromlimit)
              goto done;

             *topcindex = catomic_exchange_and_add (&fromidx, 1) + 1;
             fromp = &froms[*topcindex];

             fromp->here = &data[newarc];
             data[newarc].from_pc = frompc;
             data[newarc].self_pc = selfpc;
             data[newarc].count = 0;
             fromp->link = 0;
             catomic_increment (&narcs);

             break;
           }

         fromp = &froms[*topcindex];
       }
      else
       /* Found in.  */
       break;
    }

  /* Increment the counter.  */
  catomic_increment (&fromp->here->count);

 done:
  ;
}
void _dl_mcount_internal ( ElfW(Addr)  frompc,
ElfW(Addr)  selfpc 
)
void _dl_mcount_wrapper ( void *  selfpc)

Definition at line 30 of file dl-profstub.c.

{
  GLRO(dl_mcount) ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc);
}
int _dl_name_match_p ( const char *  __name,
const struct link_map __map 
)

Definition at line 311 of file dl-misc.c.

{
  if (strcmp (name, map->l_name) == 0)
    return 1;

  struct libname_list *runp = map->l_libname;

  while (runp != NULL)
    if (strcmp (name, runp->name) == 0)
      return 1;
    else
      runp = runp->next;

  return 0;
}

Here is the caller graph for this function:

struct link_map* _dl_new_object ( char *  realname,
const char *  libname,
int  type,
struct link_map loader,
int  mode,
Lmid_t  nsid 
) [read]

Definition at line 34 of file dl-object.c.

{
  struct link_map *l;
  int idx;
  size_t libname_len = strlen (libname) + 1;
  struct link_map *new;
  struct libname_list *newname;
#ifdef SHARED
  /* We create the map for the executable before we know whether we have
     auditing libraries and if yes, how many.  Assume the worst.  */
  unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
                                       ? DL_NNS : 0);
  size_t audit_space = naudit * sizeof (new->l_audit[0]);
#else
# define audit_space 0
#endif

  new = (struct link_map *) calloc (sizeof (*new) + audit_space
                                + sizeof (struct link_map *)
                                + sizeof (*newname) + libname_len, 1);
  if (new == NULL)
    return NULL;

  new->l_real = new;
  new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
                                                     + audit_space);

  new->l_libname = newname
    = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
  newname->name = (char *) memcpy (newname + 1, libname, libname_len);
  /* newname->next = NULL;  We use calloc therefore not necessary.  */
  newname->dont_free = 1;

  new->l_name = realname;
  new->l_type = type;
  new->l_loader = loader;
#if NO_TLS_OFFSET != 0
  new->l_tls_offset = NO_TLS_OFFSET;
#endif
  new->l_ns = nsid;

#ifdef SHARED
  for (unsigned int cnt = 0; cnt < naudit; ++cnt)
    {
      new->l_audit[cnt].cookie = (uintptr_t) new;
      /* new->l_audit[cnt].bindflags = 0; */
    }
#endif

  /* new->l_global = 0;     We use calloc therefore not necessary.  */

  /* Use the 'l_scope_mem' array by default for the the 'l_scope'
     information.  If we need more entries we will allocate a large
     array dynamically.  */
  new->l_scope = new->l_scope_mem;
  new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);

  /* Counter for the scopes we have to handle.  */
  idx = 0;

  if (GL(dl_ns)[nsid]._ns_loaded != NULL)
    {
      l = GL(dl_ns)[nsid]._ns_loaded;
      while (l->l_next != NULL)
       l = l->l_next;
      new->l_prev = l;
      /* new->l_next = NULL;       Would be necessary but we use calloc.  */
      l->l_next = new;

      /* Add the global scope.  */
      new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
    }
  else
    GL(dl_ns)[nsid]._ns_loaded = new;
  ++GL(dl_ns)[nsid]._ns_nloaded;
  new->l_serial = GL(dl_load_adds);
  ++GL(dl_load_adds);

  /* If we have no loader the new object acts as it.  */
  if (loader == NULL)
    loader = new;
  else
    /* Determine the local scope.  */
    while (loader->l_loader != NULL)
      loader = loader->l_loader;

  /* Insert the scope if it isn't the global scope we already added.  */
  if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
    {
      if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
       {
         new->l_scope[1] = new->l_scope[0];
         idx = 0;
       }

      new->l_scope[idx] = &loader->l_searchlist;
    }

  new->l_local_scope[0] = &new->l_searchlist;

  /* Don't try to find the origin for the main map which has the name "".  */
  if (realname[0] != '\0')
    {
      size_t realname_len = strlen (realname) + 1;
      char *origin;
      char *cp;

      if (realname[0] == '/')
       {
         /* It is an absolute path.  Use it.  But we have to make a
            copy since we strip out the trailing slash.  */
         cp = origin = (char *) malloc (realname_len);
         if (origin == NULL)
           {
             origin = (char *) -1;
             goto out;
           }
       }
      else
       {
         size_t len = realname_len;
         char *result = NULL;

         /* Get the current directory name.  */
         origin = NULL;
         do
           {
             char *new_origin;

             len += 128;
             new_origin = (char *) realloc (origin, len);
             if (new_origin == NULL)
              /* We exit the loop.  Note that result == NULL.  */
              break;
             origin = new_origin;
           }
         while ((result = __getcwd (origin, len - realname_len)) == NULL
               && errno == ERANGE);

         if (result == NULL)
           {
             /* We were not able to determine the current directory.
                Note that free(origin) is OK if origin == NULL.  */
             free (origin);
             origin = (char *) -1;
             goto out;
           }

         /* Find the end of the path and see whether we have to add a
            slash.  We could use rawmemchr but this need not be
            fast.  */
         cp = (strchr) (origin, '\0');
         if (cp[-1] != '/')
           *cp++ = '/';
       }

      /* Add the real file name.  */
      cp = __mempcpy (cp, realname, realname_len);

      /* Now remove the filename and the slash.  Leave the slash if
        the name is something like "/foo".  */
      do
       --cp;
      while (*cp != '/');

      if (cp == origin)
       /* Keep the only slash which is the first character.  */
       ++cp;
      *cp = '\0';

    out:
      new->l_origin = origin;
    }

  return new;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* _dl_next_ld_env_entry ( char ***  position)

Definition at line 29 of file dl-environ.c.

{
  char **current = *position;
  char *result = NULL;

  while (*current != NULL)
    {
      if (__builtin_expect ((*current)[0] == 'L', 0)
         && (*current)[1] == 'D' && (*current)[2] == '_')
       {
         result = &(*current)[3];

         /* Save current position for next visit.  */
         *position = ++current;

         break;
       }

      ++current;
    }

  return result;
}

Here is the caller graph for this function:

Definition at line 53 of file dl-tls.c.

{
  size_t result;

  if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
    {
      size_t disp = 0;
      struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);

      /* Note that this branch will never be executed during program
        start since there are no gaps at that time.  Therefore it
        does not matter that the dl_tls_dtv_slotinfo is not allocated
        yet when the function is called for the first times.

        NB: the offset +1 is due to the fact that DTV[0] is used
        for something else.  */
      result = GL(dl_tls_static_nelem) + 1;
      if (result <= GL(dl_tls_max_dtv_idx))
       do
         {
           while (result - disp < runp->len)
             {
              if (runp->slotinfo[result - disp].map == NULL)
                break;

              ++result;
              assert (result <= GL(dl_tls_max_dtv_idx) + 1);
             }

           if (result - disp < runp->len)
             break;

           disp += runp->len;
         }
       while ((runp = runp->next) != NULL);

      if (result > GL(dl_tls_max_dtv_idx))
       {
         /* The new index must indeed be exactly one higher than the
            previous high.  */
         assert (result == GL(dl_tls_max_dtv_idx) + 1);
         /* There is no gap anymore.  */
         GL(dl_tls_dtv_gaps) = false;

         goto nogaps;
       }
    }
  else
    {
      /* No gaps, allocate a new entry.  */
    nogaps:

      result = ++GL(dl_tls_max_dtv_idx);
    }

  return result;
}

Here is the caller graph for this function:

void* _dl_open ( const char *  name,
int  mode,
const void *  caller,
Lmid_t  nsid,
int  argc,
char *  argv[],
char *  env[] 
)

Definition at line 544 of file dl-open.c.

{
  if ((mode & RTLD_BINDING_MASK) == 0)
    /* One of the flags must be set.  */
    _dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));

  /* Make sure we are alone.  */
  __rtld_lock_lock_recursive (GL(dl_load_lock));

  if (nsid == LM_ID_NEWLM)
    {
      /* Find a new namespace.  */
      for (nsid = 1; nsid < DL_NNS; ++nsid)
       if (GL(dl_ns)[nsid]._ns_loaded == NULL)
         break;

      if (nsid == DL_NNS)
       {
         /* No more namespace available.  */
         __rtld_lock_unlock_recursive (GL(dl_load_lock));

         _dl_signal_error (EINVAL, file, NULL, N_("\
no more namespaces available for dlmopen()"));
       }

      _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
    }
  /* Never allow loading a DSO in a namespace which is empty.  Such
     direct placements is only causing problems.  Also don't allow
     loading into a namespace used for auditing.  */
  else if (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER
          && (GL(dl_ns)[nsid]._ns_nloaded == 0
              || GL(dl_ns)[nsid]._ns_loaded->l_auditing))
    _dl_signal_error (EINVAL, file, NULL,
                    N_("invalid target namespace in dlmopen()"));

  struct dl_open_args args;
  args.file = file;
  args.mode = mode;
  args.caller_dlopen = caller_dlopen;
  args.caller_dl_open = RETURN_ADDRESS (0);
  args.map = NULL;
  args.nsid = nsid;
  args.argc = argc;
  args.argv = argv;
  args.env = env;

  const char *objname;
  const char *errstring;
  bool malloced;
  int errcode = _dl_catch_error (&objname, &errstring, &malloced,
                             dl_open_worker, &args);

#ifndef MAP_COPY
  /* We must munmap() the cache file.  */
  _dl_unload_cache ();
#endif

  /* See if an error occurred during loading.  */
  if (__builtin_expect (errstring != NULL, 0))
    {
      /* Remove the object from memory.  It may be in an inconsistent
        state if relocation failed, for example.  */
      if (args.map)
       {
         /* Maybe some of the modules which were loaded use TLS.
            Since it will be removed in the following _dl_close call
            we have to mark the dtv array as having gaps to fill the
            holes.  This is a pessimistic assumption which won't hurt
            if not true.  There is no need to do this when we are
            loading the auditing DSOs since TLS has not yet been set
            up.  */
         if ((mode & __RTLD_AUDIT) == 0)
           GL(dl_tls_dtv_gaps) = true;

         _dl_close_worker (args.map);
       }

      assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);

      /* Release the lock.  */
      __rtld_lock_unlock_recursive (GL(dl_load_lock));

      /* Make a local copy of the error string so that we can release the
        memory allocated for it.  */
      size_t len_errstring = strlen (errstring) + 1;
      char *local_errstring;
      if (objname == errstring + len_errstring)
       {
         size_t total_len = len_errstring + strlen (objname) + 1;
         local_errstring = alloca (total_len);
         memcpy (local_errstring, errstring, total_len);
         objname = local_errstring + len_errstring;
       }
      else
       {
         local_errstring = alloca (len_errstring);
         memcpy (local_errstring, errstring, len_errstring);
       }

      if (malloced)
       free ((char *) errstring);

      /* Reraise the error.  */
      _dl_signal_error (errcode, objname, NULL, local_errstring);
    }

  assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);

  /* Release the lock.  */
  __rtld_lock_unlock_recursive (GL(dl_load_lock));

#ifndef SHARED
  DL_STATIC_INIT (args.map);
#endif

  return args.map;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_protect_relro ( struct link_map map)

Definition at line 319 of file dl-reloc.c.

{
  ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
                    & ~(GLRO(dl_pagesize) - 1));
  ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
                  & ~(GLRO(dl_pagesize) - 1));

  if (start != end
      && __mprotect ((void *) start, end - start, PROT_READ) < 0)
    {
      static const char errstring[] = N_("\
cannot apply additional memory protection after relocation");
      _dl_signal_error (errno, l->l_name, NULL, errstring);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_receive_error ( receiver_fct  fct,
void(*)(void *)  operate,
void *  args 
)

Definition at line 197 of file dl-error.c.

{
  struct catch **const catchp = &CATCH_HOOK;
  struct catch *old_catch;
  receiver_fct old_receiver;

  old_catch = *catchp;
  old_receiver = receiver;

  /* Set the new values.  */
  *catchp = NULL;
  receiver = fct;

  (*operate) (args);

  *catchp = old_catch;
  receiver = old_receiver;
}

Here is the call graph for this function:

void _dl_reloc_bad_type ( struct link_map map,
unsigned int  type,
int  plt 
)

Definition at line 337 of file dl-reloc.c.

{
  extern const char INTUSE(_itoa_lower_digits)[] attribute_hidden;
#define DIGIT(b)     INTUSE(_itoa_lower_digits)[(b) & 0xf];

  /* XXX We cannot translate these messages.  */
  static const char msg[2][32
#if __ELF_NATIVE_CLASS == 64
                        + 6
#endif
  ] = { "unexpected reloc type 0x",
       "unexpected PLT reloc type 0x" };
  char msgbuf[sizeof (msg[0])];
  char *cp;

  cp = __stpcpy (msgbuf, msg[plt]);
#if __ELF_NATIVE_CLASS == 64
  if (__builtin_expect(type > 0xff, 0))
    {
      *cp++ = DIGIT (type >> 28);
      *cp++ = DIGIT (type >> 24);
      *cp++ = DIGIT (type >> 20);
      *cp++ = DIGIT (type >> 16);
      *cp++ = DIGIT (type >> 12);
      *cp++ = DIGIT (type >> 8);
    }
#endif
  *cp++ = DIGIT (type >> 4);
  *cp++ = DIGIT (type);
  *cp = '\0';

  _dl_signal_error (0, map->l_name, NULL, msgbuf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_relocate_object ( struct link_map map,
struct r_scope_elem scope[],
int  lazy,
int  consider_profiling 
)

Definition at line 153 of file dl-reloc.c.

{
  struct textrels
  {
    caddr_t start;
    size_t len;
    int prot;
    struct textrels *next;
  } *textrels = NULL;
  /* Initialize it to make the compiler happy.  */
  const char *errstring = NULL;

#ifdef SHARED
  /* If we are auditing, install the same handlers we need for profiling.  */
  consider_profiling |= GLRO(dl_audit) != NULL;
#elif defined PROF
  /* Never use dynamic linker profiling for gprof profiling code.  */
# define consider_profiling 0
#endif

  if (l->l_relocated)
    return;

  /* If DT_BIND_NOW is set relocate all references in this object.  We
     do not do this if we are profiling, of course.  */
  // XXX Correct for auditing?
  if (!consider_profiling
      && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
    lazy = 0;

  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0))
    _dl_debug_printf ("\nrelocation processing: %s%s\n",
                    l->l_name[0] ? l->l_name : rtld_progname,
                    lazy ? " (lazy)" : "");

  /* DT_TEXTREL is now in level 2 and might phase out at some time.
     But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
     testing easier and therefore it will be available at all time.  */
  if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
    {
      /* Bletch.  We must make read-only segments writable
        long enough to relocate them.  */
      const ElfW(Phdr) *ph;
      for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
       if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
         {
           struct textrels *newp;

           newp = (struct textrels *) alloca (sizeof (*newp));
           newp->len = (((ph->p_vaddr + ph->p_memsz + GLRO(dl_pagesize) - 1)
                       & ~(GLRO(dl_pagesize) - 1))
                      - (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
           newp->start = ((ph->p_vaddr & ~(GLRO(dl_pagesize) - 1))
                        + (caddr_t) l->l_addr);

           if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
             {
              errstring = N_("cannot make segment writable for relocation");
             call_error:
              _dl_signal_error (errno, l->l_name, NULL, errstring);
             }

#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
           newp->prot = (PF_TO_PROT
                       >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
#else
           newp->prot = 0;
           if (ph->p_flags & PF_R)
             newp->prot |= PROT_READ;
           if (ph->p_flags & PF_W)
             newp->prot |= PROT_WRITE;
           if (ph->p_flags & PF_X)
             newp->prot |= PROT_EXEC;
#endif
           newp->next = textrels;
           textrels = newp;
         }
    }

  {
    /* Do the actual relocation of the object's GOT and other data.  */

    /* String table object symbols.  */
    const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);

    /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
#define RESOLVE_MAP(ref, version, r_type) \
    (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL                           \
     ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0)              \
        && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class)  \
       ? (bump_num_cache_relocations (),                             \
          (*ref) = l->l_lookup_cache.ret,                            \
          l->l_lookup_cache.value)                                   \
       : ({ lookup_t _lr;                                            \
            int _tc = elf_machine_type_class (r_type);                      \
            l->l_lookup_cache.type_class = _tc;                      \
            l->l_lookup_cache.sym = (*ref);                                 \
            const struct r_found_version *v = NULL;                         \
            int flags = DL_LOOKUP_ADD_DEPENDENCY;                           \
            if ((version) != NULL && (version)->hash != 0)                  \
              {                                                      \
               v = (version);                                               \
               flags = 0;                                            \
              }                                                      \
            _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref),   \
                                   scope, v, _tc, flags, NULL);             \
            l->l_lookup_cache.ret = (*ref);                                 \
            l->l_lookup_cache.value = _lr; }))                              \
     : l)

#include "dynamic-link.h"

    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);

#ifndef PROF
    if (__builtin_expect (consider_profiling, 0))
      {
       /* Allocate the array which will contain the already found
          relocations.  If the shared object lacks a PLT (for example
          if it only contains lead function) the l_info[DT_PLTRELSZ]
          will be NULL.  */
       if (l->l_info[DT_PLTRELSZ] == NULL)
         {
           errstring = N_("%s: no PLTREL found in object %s\n");
         fatal:
           _dl_fatal_printf (errstring,
                           rtld_progname ?: "<program name unknown>",
                           l->l_name);
         }

       l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
                                l->l_info[DT_PLTRELSZ]->d_un.d_val);
       if (l->l_reloc_result == NULL)
         {
           errstring = N_("\
%s: out of memory to store relocation results for %s\n");
           goto fatal;
         }
      }
#endif
  }

  /* Mark the object so we know this work has been done.  */
  l->l_relocated = 1;

  /* Undo the segment protection changes.  */
  while (__builtin_expect (textrels != NULL, 0))
    {
      if (__mprotect (textrels->start, textrels->len, textrels->prot) < 0)
       {
         errstring = N_("cannot restore segment prot after reloc");
         goto call_error;
       }

      textrels = textrels->next;
    }

  /* In case we can protect the data now that the relocations are
     done, do it.  */
  if (l->l_relro_size != 0)
    _dl_protect_relro (l);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_resolve_conflicts ( struct link_map l,
ElfW(Rela)*  conflict,
ElfW(Rela)*  conflictend 
)

Definition at line 32 of file dl-conflict.c.

{
#if ! ELF_MACHINE_NO_RELA
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0))
    _dl_debug_printf ("\nconflict processing: %s\n",
                    l->l_name[0] ? l->l_name : rtld_progname);

  {
    /* Do the conflict relocation of the object and library GOT and other
       data.  */

    /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, NULL)
#define RESOLVE(ref, version, flags) (*ref = NULL, 0)
#define RESOLVE_CONFLICT_FIND_MAP(map, r_offset) \
  do {                                                               \
    while ((resolve_conflict_map->l_map_end < (ElfW(Addr)) (r_offset))             \
          || (resolve_conflict_map->l_map_start > (ElfW(Addr)) (r_offset)))  \
      resolve_conflict_map = resolve_conflict_map->l_next;                  \
                                                                     \
    (map) = resolve_conflict_map;                                    \
  } while (0)

    /* Prelinking makes no sense for anything but the main namespace.  */
    assert (l->l_ns == LM_ID_BASE);
    struct link_map *resolve_conflict_map __attribute__ ((__unused__))
      = GL(dl_ns)[LM_ID_BASE]._ns_loaded;

#include "dynamic-link.h"

    /* Override these, defined in dynamic-link.h.  */
#undef CHECK_STATIC_TLS
#define CHECK_STATIC_TLS(ref_map, sym_map) ((void) 0)
#undef TRY_STATIC_TLS
#define TRY_STATIC_TLS(ref_map, sym_map) (0)

    GL(dl_num_cache_relocations) += conflictend - conflict;

    for (; conflict < conflictend; ++conflict)
      elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset);
  }
#endif
}

Here is the call graph for this function:

void _dl_rtld_di_serinfo ( struct link_map loader,
Dl_serinfo *  si,
bool  counting 
)

Definition at line 2246 of file dl-load.c.

{
  if (counting)
    {
      si->dls_cnt = 0;
      si->dls_size = 0;
    }

  unsigned int idx = 0;
  char *allocptr = (char *) &si->dls_serpath[si->dls_cnt];
  void add_path (const struct r_search_path_struct *sps, unsigned int flags)
# define add_path(sps, flags) add_path(sps, 0) /* XXX */
    {
      if (sps->dirs != (void *) -1)
       {
         struct r_search_path_elem **dirs = sps->dirs;
         do
           {
             const struct r_search_path_elem *const r = *dirs++;
             if (counting)
              {
                si->dls_cnt++;
                si->dls_size += MAX (2, r->dirnamelen);
              }
             else
              {
                Dl_serpath *const sp = &si->dls_serpath[idx++];
                sp->dls_name = allocptr;
                if (r->dirnamelen < 2)
                  *allocptr++ = r->dirnamelen ? '/' : '.';
                else
                  allocptr = __mempcpy (allocptr,
                                     r->dirname, r->dirnamelen - 1);
                *allocptr++ = '\0';
                sp->dls_flags = flags;
              }
           }
         while (*dirs != NULL);
       }
    }

  /* When the object has the RUNPATH information we don't use any RPATHs.  */
  if (loader->l_info[DT_RUNPATH] == NULL)
    {
      /* First try the DT_RPATH of the dependent object that caused NAME
        to be loaded.  Then that object's dependent, and on up.  */

      struct link_map *l = loader;
      do
       {
         if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
           add_path (&l->l_rpath_dirs, XXX_RPATH);
         l = l->l_loader;
       }
      while (l != NULL);

      /* If dynamically linked, try the DT_RPATH of the executable itself.  */
      if (loader->l_ns == LM_ID_BASE)
       {
         l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
         if (l != NULL && l->l_type != lt_loaded && l != loader)
           if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
             add_path (&l->l_rpath_dirs, XXX_RPATH);
       }
    }

  /* Try the LD_LIBRARY_PATH environment variable.  */
  add_path (&env_path_list, XXX_ENV);

  /* Look at the RUNPATH information for this binary.  */
  if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH"))
    add_path (&loader->l_runpath_dirs, XXX_RUNPATH);

  /* XXX
     Here is where ld.so.cache gets checked, but we don't have
     a way to indicate that in the results for Dl_serinfo.  */

  /* Finally, try the default path.  */
  if (!(loader->l_flags_1 & DF_1_NODEFLIB))
    add_path (&rtld_search_dirs, XXX_default);

  if (counting)
    /* Count the struct size before the string area, which we didn't
       know before we completed dls_cnt.  */
    si->dls_size += (char *) &si->dls_serpath[si->dls_cnt] - (char *) si;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _dl_scope_free ( void *  )

Definition at line 169 of file dl-open.c.

{
  struct dl_scope_free_list *fsl;
#define DL_SCOPE_FREE_LIST_SIZE (sizeof (fsl->list) / sizeof (fsl->list[0]))

  if (RTLD_SINGLE_THREAD_P)
    free (old);
  else if ((fsl = GL(dl_scope_free_list)) == NULL)
    {
      GL(dl_scope_free_list) = fsl = malloc (sizeof (*fsl));
      if (fsl == NULL)
       {
         THREAD_GSCOPE_WAIT ();
         free (old);
         return 1;
       }
      else
       {
         fsl->list[0] = old;
         fsl->count = 1;
       }
    }
  else if (fsl->count < DL_SCOPE_FREE_LIST_SIZE)
    fsl->list[fsl->count++] = old;
  else
    {
      THREAD_GSCOPE_WAIT ();
      while (fsl->count > 0)
       free (fsl->list[--fsl->count]);
      return 1;
    }
  return 0;
}

Here is the caller graph for this function:

void _dl_setup_hash ( struct link_map map)

Definition at line 458 of file dl-lookup.c.

{
  Elf_Symndx *hash;
  Elf_Symndx nchain;

  if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
                                + DT_THISPROCNUM + DT_VERSIONTAGNUM
                                + DT_EXTRANUM + DT_VALNUM] != NULL, 1))
    {
      Elf32_Word *hash32
       = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
                                  + DT_THISPROCNUM + DT_VERSIONTAGNUM
                                  + DT_EXTRANUM + DT_VALNUM]);
      map->l_nbuckets = *hash32++;
      Elf32_Word symbias = *hash32++;
      Elf32_Word bitmask_nwords = *hash32++;
      /* Must be a power of two.  */
      assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
      map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
      map->l_gnu_shift = *hash32++;

      map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
      hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;

      map->l_gnu_buckets = hash32;
      hash32 += map->l_nbuckets;
      map->l_gnu_chain_zero = hash32 - symbias;
      return;
    }

  if (!map->l_info[DT_HASH])
    return;
  hash = (void *) D_PTR (map, l_info[DT_HASH]);

  map->l_nbuckets = *hash++;
  nchain = *hash++;
  map->l_buckets = hash;
  hash += map->l_nbuckets;
  map->l_chain = hash;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_show_auxv ( void  )

Definition at line 251 of file dl-sysdep.c.

{
  char buf[64];
  ElfW(auxv_t) *av;

  /* Terminate string.  */
  buf[63] = '\0';

  /* The following code assumes that the AT_* values are encoded
     starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
     close by (otherwise the array will be too large).  In case we have
     to support a platform where these requirements are not fulfilled
     some alternative implementation has to be used.  */
  for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
    {
      static const struct
      {
       const char label[20];
       enum { unknown = 0, dec, hex, str, ignore } form;
      } auxvars[] =
       {
         [AT_EXECFD - 2] =         { "AT_EXECFD:       ", dec },
         [AT_EXECFN - 2] =         { "AT_EXECFN:       ", str },
         [AT_PHDR - 2] =           { "AT_PHDR:         0x", hex },
         [AT_PHENT - 2] =          { "AT_PHENT:        ", dec },
         [AT_PHNUM - 2] =          { "AT_PHNUM:        ", dec },
         [AT_PAGESZ - 2] =         { "AT_PAGESZ:       ", dec },
         [AT_BASE - 2] =           { "AT_BASE:         0x", hex },
         [AT_FLAGS - 2] =          { "AT_FLAGS:        0x", hex },
         [AT_ENTRY - 2] =          { "AT_ENTRY:        0x", hex },
         [AT_NOTELF - 2] =         { "AT_NOTELF:       ", hex },
         [AT_UID - 2] =            { "AT_UID:          ", dec },
         [AT_EUID - 2] =           { "AT_EUID:         ", dec },
         [AT_GID - 2] =            { "AT_GID:          ", dec },
         [AT_EGID - 2] =           { "AT_EGID:         ", dec },
         [AT_PLATFORM - 2] =              { "AT_PLATFORM:     ", str },
         [AT_HWCAP - 2] =          { "AT_HWCAP:        ", hex },
         [AT_CLKTCK - 2] =         { "AT_CLKTCK:       ", dec },
         [AT_FPUCW - 2] =          { "AT_FPUCW:        ", hex },
         [AT_DCACHEBSIZE - 2] =    { "AT_DCACHEBSIZE:  0x", hex },
         [AT_ICACHEBSIZE - 2] =    { "AT_ICACHEBSIZE:  0x", hex },
         [AT_UCACHEBSIZE - 2] =    { "AT_UCACHEBSIZE:  0x", hex },
         [AT_IGNOREPPC - 2] =             { "AT_IGNOREPPC", ignore },
         [AT_SECURE - 2] =         { "AT_SECURE:       ", dec },
         [AT_SYSINFO - 2] =        { "AT_SYSINFO:      0x", hex },
         [AT_SYSINFO_EHDR - 2] =   { "AT_SYSINFO_EHDR: 0x", hex },
       };
      unsigned int idx = (unsigned int) (av->a_type - 2);

      if ((unsigned int) av->a_type < 2u || auxvars[idx].form == ignore)
       continue;

      assert (AT_NULL == 0);
      assert (AT_IGNORE == 1);

      if (av->a_type == AT_HWCAP)
       {
         /* This is handled special.  */
         if (_dl_procinfo (av->a_un.a_val) == 0)
           continue;
       }

      if (idx < sizeof (auxvars) / sizeof (auxvars[0])
         && auxvars[idx].form != unknown)
       {
         const char *val = (char *) av->a_un.a_val;

         if (__builtin_expect (auxvars[idx].form, dec) == dec)
           val = _itoa ((unsigned long int) av->a_un.a_val,
                      buf + sizeof buf - 1, 10, 0);
         else if (__builtin_expect (auxvars[idx].form, hex) == hex)
           val = _itoa ((unsigned long int) av->a_un.a_val,
                      buf + sizeof buf - 1, 16, 0);

         _dl_printf ("%s%s\n", auxvars[idx].label, val);

         continue;
       }

      /* Unknown value: print a generic line.  */
      char buf2[17];
      buf[sizeof (buf2) - 1] = '\0';
      const char *val2 = _itoa ((unsigned long int) av->a_un.a_val,
                            buf2 + sizeof buf2 - 1, 16, 0);
      const char *val =  _itoa ((unsigned long int) av->a_type,
                            buf + sizeof buf - 1, 16, 0);
      _dl_printf ("AT_??? (0x%s): 0x%s\n", val, val2);
    }
}

Here is the caller graph for this function:

void _dl_signal_cerror ( int  errcode,
const char *  object,
const char *  occation,
const char *  errstring 
)

Definition at line 136 of file dl-error.c.

{
  if (__builtin_expect (GLRO(dl_debug_mask)
                     & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
    _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
                    errstring, receiver ? "continued" : "fatal");

  if (receiver)
    {
      /* We are inside _dl_receive_error.  Call the user supplied
        handler and resume the work.  The receiver will still be
        installed.  */
      (*receiver) (errcode, objname, errstring);
    }
  else
    _dl_signal_error (errcode, objname, occation, errstring);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_signal_error ( int  errcode,
const char *  object,
const char *  occurred,
const char *  errstring 
)

Definition at line 71 of file dl-error.c.

{
  struct catch *lcatch;

  if (! errstring)
    errstring = N_("DYNAMIC LINKER BUG!!!");

  lcatch = CATCH_HOOK;
  if (objname == NULL)
    objname = "";
  if (lcatch != NULL)
    {
      /* We are inside _dl_catch_error.  Return to it.  We have to
        duplicate the error string since it might be allocated on the
        stack.  The object name is always a string constant.  */
      size_t len_objname = strlen (objname) + 1;
      size_t len_errstring = strlen (errstring) + 1;

      lcatch->errstring = (char *) malloc (len_objname + len_errstring);
      if (lcatch->errstring != NULL)
       {
         /* Make a copy of the object file name and the error string.  */
         lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring,
                                          errstring, len_errstring),
                                objname, len_objname);

         /* If the main executable is relocated it means the libc's malloc
            is used.  */
#ifdef SHARED
         lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
                           && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated
                              != 0));
#else
         lcatch->malloced = true;
#endif
       }
      else
       {
         /* This is better than nothing.  */
         lcatch->objname = "";
         lcatch->errstring = _dl_out_of_memory;
         lcatch->malloced = false;
       }
      /* We do not restore the signal mask because none was saved.  */
      __longjmp (lcatch->env[0].__jmpbuf, errcode ?: -1);
    }
  else
    {
      /* Lossage while resolving the program's own symbols is always fatal.  */
      char buffer[1024];
      _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
                     rtld_progname ?: "<program name unknown>",
                     occation ?: N_("error while loading shared libraries"),
                     objname, *objname ? ": " : "",
                     errstring, errcode ? ": " : "",
                     (errcode
                      ? __strerror_r (errcode, buffer, sizeof buffer)
                      : ""));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_sort_fini ( struct link_map l,
struct link_map **  maps,
size_t  nmaps,
char *  used,
Lmid_t  ns 
)

Definition at line 32 of file dl-fini.c.

{
  if (ns == LM_ID_BASE)
    /* The main executable always comes first.  */
    l = l->l_next;

  for (; l != NULL; l = l->l_next)
    /* Do not handle ld.so in secondary namespaces and object which
       are not removed.  */
    if (l == l->l_real && l->l_idx != -1)
      {
       /* Find the place in the 'maps' array.  */
       unsigned int j;
       for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
         assert (j < nmaps);

       /* Find all object for which the current one is a dependency
          and move the found object (if necessary) in front.  */
       for (unsigned int k = j + 1; k < nmaps; ++k)
         {
           struct link_map **runp = maps[k]->l_initfini;
           if (runp != NULL)
             {
              while (*runp != NULL)
                if (*runp == l)
                  {
                    struct link_map *here = maps[k];

                    /* Move it now.  */
                    memmove (&maps[j] + 1,
                            &maps[j], (k - j) * sizeof (struct link_map *));
                    maps[j] = here;

                    if (used != NULL)
                     {
                       char here_used = used[k];

                       memmove (&used[j] + 1,
                               &used[j], (k - j) * sizeof (char));
                       used[j] = here_used;
                     }

                    ++j;

                    break;
                  }
                else
                  ++runp;
             }

           if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
             {
              unsigned int m = maps[k]->l_reldeps->act;
              struct link_map **relmaps = &maps[k]->l_reldeps->list[0];

              while (m-- > 0)
                {
                  if (relmaps[m] == l)
                    {
                     struct link_map *here = maps[k];

                     /* Move it now.  */
                     memmove (&maps[j] + 1,
                             &maps[j],
                             (k - j) * sizeof (struct link_map *));
                     maps[j] = here;

                     if (used != NULL)
                       {
                         char here_used = used[k];

                         memmove (&used[j] + 1,
                                 &used[j], (k - j) * sizeof (char));
                         used[j] = here_used;
                       }

                     break;
                    }
                }
             }
         }
      }
}

Here is the caller graph for this function:

void _dl_start_profile ( void  )

Definition at line 173 of file dl-profile.c.

{
  char *filename;
  int fd;
  struct stat64 st;
  const ElfW(Phdr) *ph;
  ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
  ElfW(Addr) mapend = 0;
  struct gmon_hdr gmon_hdr;
  struct gmon_hist_hdr hist_hdr;
  char *hist, *cp;
  size_t idx;
  size_t tossize;
  size_t fromssize;
  uintptr_t highpc;
  uint16_t *kcount;
  size_t kcountsize;
  struct gmon_hdr *addr = NULL;
  off_t expected_size;
  /* See profil(2) where this is described.  */
  int s_scale;
#define SCALE_1_TO_1 0x10000L
  const char *errstr = NULL;

  /* Compute the size of the sections which contain program code.  */
  for (ph = GL(dl_profile_map)->l_phdr;
       ph < &GL(dl_profile_map)->l_phdr[GL(dl_profile_map)->l_phnum]; ++ph)
    if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
      {
       ElfW(Addr) start = (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1));
       ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + GLRO(dl_pagesize) - 1)
                       & ~(GLRO(dl_pagesize) - 1));

       if (start < mapstart)
         mapstart = start;
       if (end > mapend)
         mapend = end;
      }

  /* Now we can compute the size of the profiling data.  This is done
     with the same formulars as in `monstartup' (see gmon.c).  */
  running = 0;
  lowpc = ROUNDDOWN (mapstart + GL(dl_profile_map)->l_addr,
                   HISTFRACTION * sizeof (HISTCOUNTER));
  highpc = ROUNDUP (mapend + GL(dl_profile_map)->l_addr,
                  HISTFRACTION * sizeof (HISTCOUNTER));
  textsize = highpc - lowpc;
  kcountsize = textsize / HISTFRACTION;
  if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)
    {
      /* If HASHFRACTION is a power of two, mcount can use shifting
        instead of integer division.  Precompute shift amount.

        This is a constant but the compiler cannot compile the
        expression away since the __ffs implementation is not known
        to the compiler.  Help the compiler by precomputing the
        usual cases.  */
      assert (HASHFRACTION == 2);

      if (sizeof (*froms) == 8)
       log_hashfraction = 4;
      else if (sizeof (*froms) == 16)
       log_hashfraction = 5;
      else
       log_hashfraction = __ffs (HASHFRACTION * sizeof (*froms)) - 1;
    }
  else
    log_hashfraction = -1;
  tossize = textsize / HASHFRACTION;
  fromlimit = textsize * ARCDENSITY / 100;
  if (fromlimit < MINARCS)
    fromlimit = MINARCS;
  if (fromlimit > MAXARCS)
    fromlimit = MAXARCS;
  fromssize = fromlimit * sizeof (struct here_fromstruct);

  expected_size = (sizeof (struct gmon_hdr)
                 + 4 + sizeof (struct gmon_hist_hdr) + kcountsize
                 + 4 + 4 + fromssize * sizeof (struct here_cg_arc_record));

  /* Create the gmon_hdr we expect or write.  */
  memset (&gmon_hdr, '\0', sizeof (struct gmon_hdr));
  memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
  *(int32_t *) gmon_hdr.version = GMON_SHOBJ_VERSION;

  /* Create the hist_hdr we expect or write.  */
  *(char **) hist_hdr.low_pc = (char *) mapstart;
  *(char **) hist_hdr.high_pc = (char *) mapend;
  *(int32_t *) hist_hdr.hist_size = kcountsize / sizeof (HISTCOUNTER);
  *(int32_t *) hist_hdr.prof_rate = __profile_frequency ();
  if (sizeof (hist_hdr.dimen) >= sizeof ("seconds"))
    {
      memcpy (hist_hdr.dimen, "seconds", sizeof ("seconds"));
      memset (hist_hdr.dimen + sizeof ("seconds"), '\0',
             sizeof (hist_hdr.dimen) - sizeof ("seconds"));
    }
  else
    strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
  hist_hdr.dimen_abbrev = 's';

  /* First determine the output name.  We write in the directory
     OUTPUT_DIR and the name is composed from the shared objects
     soname (or the file name) and the ending ".profile".  */
  filename = (char *) alloca (strlen (GLRO(dl_profile_output)) + 1
                           + strlen (GLRO(dl_profile)) + sizeof ".profile");
  cp = __stpcpy (filename, GLRO(dl_profile_output));
  *cp++ = '/';
  __stpcpy (__stpcpy (cp, GLRO(dl_profile)), ".profile");

#ifdef O_NOFOLLOW
# define EXTRA_FLAGS | O_NOFOLLOW
#else
# define EXTRA_FLAGS
#endif
  fd = __open (filename, O_RDWR | O_CREAT EXTRA_FLAGS, DEFFILEMODE);
  if (fd == -1)
    {
      char buf[400];
      int errnum;

      /* We cannot write the profiling data so don't do anything.  */
      errstr = "%s: cannot open file: %s\n";
    print_error:
      errnum = errno;
      if (fd != -1)
       __close (fd);
      _dl_error_printf (errstr, filename,
                     __strerror_r (errnum, buf, sizeof buf));
      return;
    }

  if (__fxstat64 (_STAT_VER, fd, &st) < 0 || !S_ISREG (st.st_mode))
    {
      /* Not stat'able or not a regular file => don't use it.  */
      errstr = "%s: cannot stat file: %s\n";
      goto print_error;
    }

  /* Test the size.  If it does not match what we expect from the size
     values in the map MAP we don't use it and warn the user.  */
  if (st.st_size == 0)
    {
      /* We have to create the file.  */
      char buf[GLRO(dl_pagesize)];

      memset (buf, '\0', GLRO(dl_pagesize));

      if (__lseek (fd, expected_size & ~(GLRO(dl_pagesize) - 1), SEEK_SET) == -1)
       {
       cannot_create:
         errstr = "%s: cannot create file: %s\n";
         goto print_error;
       }

      if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size
                                                & (GLRO(dl_pagesize)
                                                  - 1))))
         < 0)
       goto cannot_create;
    }
  else if (st.st_size != expected_size)
    {
      __close (fd);
    wrong_format:

      if (addr != NULL)
       __munmap ((void *) addr, expected_size);

      _dl_error_printf ("%s: file is no correct profile data file for `%s'\n",
                     filename, GLRO(dl_profile));
      return;
    }

  addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE,
                                 MAP_SHARED|MAP_FILE, fd, 0);
  if (addr == (struct gmon_hdr *) MAP_FAILED)
    {
      errstr = "%s: cannot map file: %s\n";
      goto print_error;
    }

  /* We don't need the file descriptor anymore.  */
  __close (fd);

  /* Pointer to data after the header.  */
  hist = (char *) (addr + 1);
  kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t)
                      + sizeof (struct gmon_hist_hdr));

  /* Compute pointer to array of the arc information.  */
  narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t));
  data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t));

  if (st.st_size == 0)
    {
      /* Create the signature.  */
      memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr));

      *(uint32_t *) hist = GMON_TAG_TIME_HIST;
      memcpy (hist + sizeof (uint32_t), &hist_hdr,
             sizeof (struct gmon_hist_hdr));

      narcsp[-1] = GMON_TAG_CG_ARC;
    }
  else
    {
      /* Test the signature in the file.  */
      if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
         || *(uint32_t *) hist != GMON_TAG_TIME_HIST
         || memcmp (hist + sizeof (uint32_t), &hist_hdr,
                   sizeof (struct gmon_hist_hdr)) != 0
         || narcsp[-1] != GMON_TAG_CG_ARC)
       goto wrong_format;
    }

  /* Allocate memory for the froms data and the pointer to the tos records.  */
  tos = (uint16_t *) calloc (tossize + fromssize, 1);
  if (tos == NULL)
    {
      __munmap ((void *) addr, expected_size);
      _dl_fatal_printf ("Out of memory while initializing profiler\n");
      /* NOTREACHED */
    }

  froms = (struct here_fromstruct *) ((char *) tos + tossize);
  fromidx = 0;

  /* Now we have to process all the arc count entries.  BTW: it is
     not critical whether the *NARCSP value changes meanwhile.  Before
     we enter a new entry in to toset we will check that everything is
     available in TOS.  This happens in _dl_mcount.

     Loading the entries in reverse order should help to get the most
     frequently used entries at the front of the list.  */
  for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; )
    {
      size_t to_index;
      size_t newfromidx;
      --idx;
      to_index = (data[idx].self_pc / (HASHFRACTION * sizeof (*tos)));
      newfromidx = fromidx++;
      froms[newfromidx].here = &data[idx];
      froms[newfromidx].link = tos[to_index];
      tos[to_index] = newfromidx;
    }

  /* Setup counting data.  */
  if (kcountsize < highpc - lowpc)
    {
#if 0
      s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1;
#else
      size_t range = highpc - lowpc;
      size_t quot = range / kcountsize;

      if (quot >= SCALE_1_TO_1)
       s_scale = 1;
      else if (quot >= SCALE_1_TO_1 / 256)
       s_scale = SCALE_1_TO_1 / quot;
      else if (range > ULONG_MAX / 256)
       s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256));
      else
       s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize);
#endif
    }
  else
    s_scale = SCALE_1_TO_1;

  /* Start the profiler.  */
  __profil ((void *) kcount, kcountsize, lowpc, s_scale);

  /* Turn on profiling.  */
  running = 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* _dl_sysdep_read_whole_file ( const char *  file,
size_t sizep,
int  prot 
)

Definition at line 54 of file dl-misc.c.

{
  void *result = MAP_FAILED;
  struct stat64 st;
  int fd = __open (file, O_RDONLY);
  if (fd >= 0)
    {
      if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
       {
         *sizep = st.st_size;

         /* No need to map the file if it is empty.  */
         if (*sizep != 0)
           /* Map a copy of the file contents.  */
           result = __mmap (NULL, *sizep, prot,
#ifdef MAP_COPY
                          MAP_COPY
#else
                          MAP_PRIVATE
#endif
#ifdef MAP_FILE
                          | MAP_FILE
#endif
                          , fd, 0);
       }
      __close (fd);
    }
  return result;
}

Here is the call graph for this function:

void _dl_sysdep_start_cleanup ( void  )

Definition at line 245 of file dl-sysdep.c.

{
}

Here is the call graph for this function:

void* _dl_tls_get_addr_soft ( struct link_map l)
int _dl_tls_setup ( void  )

Definition at line 228 of file libc-tls.c.

{
  init_slotinfo ();
  init_static_tls (
#if TLS_TCB_AT_TP
                 TLS_TCB_SIZE,
#else
                 0,
#endif
                 TLS_TCB_ALIGN);
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _dl_unload_cache ( void  )

Definition at line 288 of file dl-cache.c.

{

Here is the caller graph for this function:

struct link_map* _dl_update_slotinfo ( unsigned long int  req_modid) [read]

Here is the caller graph for this function:

EXTERN ElfW ( Word  )
EXTERN ElfW ( Addr  )
rtld_hidden_proto ( _dl_allocate_tls  )
rtld_hidden_proto ( _dl_deallocate_tls  )

Variable Documentation

Definition at line 423 of file ldsodefs.h.

Definition at line 568 of file ldsodefs.h.

Definition at line 556 of file ldsodefs.h.

Definition at line 578 of file ldsodefs.h.

Definition at line 562 of file ldsodefs.h.

Definition at line 529 of file ldsodefs.h.

Definition at line 572 of file ldsodefs.h.

Definition at line 575 of file ldsodefs.h.

Definition at line 581 of file ldsodefs.h.

Definition at line 584 of file ldsodefs.h.

Definition at line 594 of file ldsodefs.h.

Definition at line 614 of file ldsodefs.h.

EXTERN void(* _dl_init_static_tls)(struct link_map *)

Definition at line 487 of file ldsodefs.h.

Definition at line 408 of file ldsodefs.h.

Definition at line 483 of file ldsodefs.h.

Definition at line 565 of file ldsodefs.h.

Definition at line 445 of file ldsodefs.h.

Definition at line 420 of file ldsodefs.h.

Definition at line 419 of file ldsodefs.h.

Definition at line 597 of file ldsodefs.h.

Definition at line 544 of file ldsodefs.h.

Definition at line 550 of file ldsodefs.h.

Definition at line 546 of file ldsodefs.h.

Definition at line 547 of file ldsodefs.h.

Definition at line 605 of file ldsodefs.h.

Definition at line 416 of file ldsodefs.h.

Definition at line 607 of file ldsodefs.h.

Definition at line 117 of file rtld.c.

Definition at line 451 of file ldsodefs.h.

Definition at line 485 of file ldsodefs.h.

Definition at line 453 of file ldsodefs.h.

Definition at line 472 of file ldsodefs.h.

Definition at line 466 of file ldsodefs.h.

Definition at line 468 of file ldsodefs.h.

Definition at line 470 of file ldsodefs.h.

Definition at line 609 of file ldsodefs.h.

Definition at line 611 of file ldsodefs.h.

Definition at line 559 of file ldsodefs.h.

Definition at line 489 of file ldsodefs.h.

Definition at line 404 of file ldsodefs.h.

void void attribute_hidden

Definition at line 742 of file ldsodefs.h.

Definition at line 37 of file libc-start.c.

static void dl_main

Definition at line 997 of file ldsodefs.h.

bool dealloc_tcb internal_function

Definition at line 871 of file ldsodefs.h.

EXTERN struct link_map

Definition at line 431 of file ldsodefs.h.

Definition at line 553 of file ldsodefs.h.