Back to index

glibc  2.9
Classes | Functions | Variables
dlerror.c File Reference
#include <dlfcn.h>
#include <libintl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bits/libc-lock.h>
#include <ldsodefs.h>
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  dl_action_result

Functions

 __libc_once_define (static, once)
static void init (void)
static void free_key_mem (void *mem)
char * __dlerror (void)
int internal_function _dlerror_run (void(*operate)(void *), void *args)
static void check_free (struct dl_action_result *rec)
static void __attribute__ ((destructor))
void __libc_register_dlfcn_hook (struct link_map *map)

Variables

static struct dl_action_result
static struct dl_action_resultstatic_buf
static __libc_key_t key
static struct dlfcn_hook

Class Documentation

struct dl_action_result

Definition at line 40 of file dlerror.c.

Class Members
int errcode
const char * errstring
bool malloced
const char * objname
int returned

Function Documentation

static void __attribute__ ( (destructor)  ) [static]

Definition at line 205 of file dlerror.c.

{
  check_free (&last_result);
}

Here is the call graph for this function:

char* __dlerror ( void  )

Definition at line 61 of file dlerror.c.

{
  char *buf = NULL;
  struct dl_action_result *result;

# ifdef SHARED
  if (__builtin_expect (_dlfcn_hook != NULL, 0))
    return _dlfcn_hook->dlerror ();
# endif

  /* If we have not yet initialized the buffer do it now.  */
  __libc_once (once, init);

  /* Get error string.  */
  result = (struct dl_action_result *) __libc_getspecific (key);
  if (result == NULL)
    result = &last_result;

  /* Test whether we already returned the string.  */
  if (result->returned != 0)
    {
      /* We can now free the string.  */
      if (result->errstring != NULL)
       {
         if (strcmp (result->errstring, "out of memory") != 0)
           free ((char *) result->errstring);
         result->errstring = NULL;
       }
    }
  else if (result->errstring != NULL)
    {
      buf = (char *) result->errstring;
      int n;
      if (result->errcode == 0)
       n = __asprintf (&buf, "%s%s%s",
                     result->objname,
                     result->objname[0] == '\0' ? "" : ": ",
                     _(result->errstring));
      else
       n = __asprintf (&buf, "%s%s%s: %s",
                     result->objname,
                     result->objname[0] == '\0' ? "" : ": ",
                     _(result->errstring),
                     strerror (result->errcode));
      if (n != -1)
       {
         /* We don't need the error string anymore.  */
         if (strcmp (result->errstring, "out of memory") != 0)
           free ((char *) result->errstring);
         result->errstring = buf;
       }

      /* Mark the error as returned.  */
      result->returned = 1;
    }

  return buf;
}

Here is the call graph for this function:

__libc_once_define ( static  ,
once   
)
void __libc_register_dlfcn_hook ( struct link_map map)

Definition at line 243 of file dlerror.c.

{
  struct dlfcn_hook **hook;

  hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
  if (hook != NULL)
    *hook = &_dlfcn_hooks;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int internal_function _dlerror_run ( void(*)(void *)  operate,
void *  args 
)

Definition at line 125 of file dlerror.c.

{
  struct dl_action_result *result;

  /* If we have not yet initialized the buffer do it now.  */
  __libc_once (once, init);

  /* Get error string and number.  */
  if (static_buf != NULL)
    result = static_buf;
  else
    {
      /* We don't use the static buffer and so we have a key.  Use it
        to get the thread-specific buffer.  */
      result = __libc_getspecific (key);
      if (result == NULL)
       {
         result = (struct dl_action_result *) calloc (1, sizeof (*result));
         if (result == NULL)
           /* We are out of memory.  Since this is no really critical
              situation we carry on by using the global variable.
              This might lead to conflicts between the threads but
              they soon all will have memory problems.  */
           result = &last_result;
         else
           /* Set the tsd.  */
           __libc_setspecific (key, result);
       }
    }

  if (result->errstring != NULL)
    {
      /* Free the error string from the last failed command.  This can
        happen if `dlerror' was not run after an error was found.  */
      if (result->malloced)
       free ((char *) result->errstring);
      result->errstring = NULL;
    }

  result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
                                     &result->malloced, operate, args);

  /* If no error we mark that no error string is available.  */
  result->returned = result->errstring == NULL;

  return result->errstring != NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_free ( struct dl_action_result rec) [static]

Definition at line 187 of file dlerror.c.

{
  if (rec->errstring != NULL
      && strcmp (rec->errstring, "out of memory") != 0)
    {
      /* We can free the string only if the allocation happened in the
        C library used by the dynamic linker.  This means, it is
        always the C library in the base namespave.  */
      struct link_map *map = NULL;
      Dl_info info;
      if (_dl_addr (check_free, &info, &map, NULL) != 0
         && map != NULL && map->l_ns == 0)
       free ((char *) rec->errstring);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void free_key_mem ( void *  mem) [static]

Definition at line 214 of file dlerror.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void init ( void  ) [static]

Definition at line 176 of file dlerror.c.

{
  if (__libc_key_create (&key, free_key_mem))
    /* Creating the key failed.  This means something really went
       wrong.  In any case use a static buffer which is better than
       nothing.  */
    static_buf = &last_result;
}

Here is the call graph for this function:


Variable Documentation

struct dl_action_result [static]

Definition at line 48 of file dlerror.c.

struct dlfcn_hook [static]
Initial value:
  {
    .dlopen = __dlopen,
    .dlclose = __dlclose,
    .dlsym = __dlsym,
    .dlvsym = __dlvsym,
    .dlerror = __dlerror,
    .dladdr = __dladdr,
    .dladdr1 = __dladdr1,
    .dlinfo = __dlinfo,
    .dlmopen = __dlmopen
  }

Definition at line 229 of file dlerror.c.

__libc_key_t key [static]

Definition at line 52 of file dlerror.c.

struct dl_action_result* static_buf [static]

Definition at line 49 of file dlerror.c.