Back to index

glibc  2.9
dlerror.c
Go to the documentation of this file.
00001 /* Return error detail for failing <dlfcn.h> functions.
00002    Copyright (C) 1995-2000,2002,2003,2004,2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <dlfcn.h>
00021 #include <libintl.h>
00022 #include <stdbool.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <bits/libc-lock.h>
00027 #include <ldsodefs.h>
00028 
00029 #if !defined SHARED && defined IS_IN_libdl
00030 
00031 char *
00032 dlerror (void)
00033 {
00034   return __dlerror ();
00035 }
00036 
00037 #else
00038 
00039 /* Type for storing results of dynamic loading actions.  */
00040 struct dl_action_result
00041   {
00042     int errcode;
00043     int returned;
00044     bool malloced;
00045     const char *objname;
00046     const char *errstring;
00047   };
00048 static struct dl_action_result last_result;
00049 static struct dl_action_result *static_buf;
00050 
00051 /* This is the key for the thread specific memory.  */
00052 static __libc_key_t key;
00053 __libc_once_define (static, once);
00054 
00055 /* Destructor for the thread-specific data.  */
00056 static void init (void);
00057 static void free_key_mem (void *mem);
00058 
00059 
00060 char *
00061 __dlerror (void)
00062 {
00063   char *buf = NULL;
00064   struct dl_action_result *result;
00065 
00066 # ifdef SHARED
00067   if (__builtin_expect (_dlfcn_hook != NULL, 0))
00068     return _dlfcn_hook->dlerror ();
00069 # endif
00070 
00071   /* If we have not yet initialized the buffer do it now.  */
00072   __libc_once (once, init);
00073 
00074   /* Get error string.  */
00075   result = (struct dl_action_result *) __libc_getspecific (key);
00076   if (result == NULL)
00077     result = &last_result;
00078 
00079   /* Test whether we already returned the string.  */
00080   if (result->returned != 0)
00081     {
00082       /* We can now free the string.  */
00083       if (result->errstring != NULL)
00084        {
00085          if (strcmp (result->errstring, "out of memory") != 0)
00086            free ((char *) result->errstring);
00087          result->errstring = NULL;
00088        }
00089     }
00090   else if (result->errstring != NULL)
00091     {
00092       buf = (char *) result->errstring;
00093       int n;
00094       if (result->errcode == 0)
00095        n = __asprintf (&buf, "%s%s%s",
00096                      result->objname,
00097                      result->objname[0] == '\0' ? "" : ": ",
00098                      _(result->errstring));
00099       else
00100        n = __asprintf (&buf, "%s%s%s: %s",
00101                      result->objname,
00102                      result->objname[0] == '\0' ? "" : ": ",
00103                      _(result->errstring),
00104                      strerror (result->errcode));
00105       if (n != -1)
00106        {
00107          /* We don't need the error string anymore.  */
00108          if (strcmp (result->errstring, "out of memory") != 0)
00109            free ((char *) result->errstring);
00110          result->errstring = buf;
00111        }
00112 
00113       /* Mark the error as returned.  */
00114       result->returned = 1;
00115     }
00116 
00117   return buf;
00118 }
00119 # ifdef SHARED
00120 strong_alias (__dlerror, dlerror)
00121 # endif
00122 
00123 int
00124 internal_function
00125 _dlerror_run (void (*operate) (void *), void *args)
00126 {
00127   struct dl_action_result *result;
00128 
00129   /* If we have not yet initialized the buffer do it now.  */
00130   __libc_once (once, init);
00131 
00132   /* Get error string and number.  */
00133   if (static_buf != NULL)
00134     result = static_buf;
00135   else
00136     {
00137       /* We don't use the static buffer and so we have a key.  Use it
00138         to get the thread-specific buffer.  */
00139       result = __libc_getspecific (key);
00140       if (result == NULL)
00141        {
00142          result = (struct dl_action_result *) calloc (1, sizeof (*result));
00143          if (result == NULL)
00144            /* We are out of memory.  Since this is no really critical
00145               situation we carry on by using the global variable.
00146               This might lead to conflicts between the threads but
00147               they soon all will have memory problems.  */
00148            result = &last_result;
00149          else
00150            /* Set the tsd.  */
00151            __libc_setspecific (key, result);
00152        }
00153     }
00154 
00155   if (result->errstring != NULL)
00156     {
00157       /* Free the error string from the last failed command.  This can
00158         happen if `dlerror' was not run after an error was found.  */
00159       if (result->malloced)
00160        free ((char *) result->errstring);
00161       result->errstring = NULL;
00162     }
00163 
00164   result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
00165                                      &result->malloced, operate, args);
00166 
00167   /* If no error we mark that no error string is available.  */
00168   result->returned = result->errstring == NULL;
00169 
00170   return result->errstring != NULL;
00171 }
00172 
00173 
00174 /* Initialize buffers for results.  */
00175 static void
00176 init (void)
00177 {
00178   if (__libc_key_create (&key, free_key_mem))
00179     /* Creating the key failed.  This means something really went
00180        wrong.  In any case use a static buffer which is better than
00181        nothing.  */
00182     static_buf = &last_result;
00183 }
00184 
00185 
00186 static void
00187 check_free (struct dl_action_result *rec)
00188 {
00189   if (rec->errstring != NULL
00190       && strcmp (rec->errstring, "out of memory") != 0)
00191     {
00192       /* We can free the string only if the allocation happened in the
00193         C library used by the dynamic linker.  This means, it is
00194         always the C library in the base namespave.  */
00195       struct link_map *map = NULL;
00196       Dl_info info;
00197       if (_dl_addr (check_free, &info, &map, NULL) != 0
00198          && map != NULL && map->l_ns == 0)
00199        free ((char *) rec->errstring);
00200     }
00201 }
00202 
00203 
00204 static void
00205 __attribute__ ((destructor))
00206 fini (void)
00207 {
00208   check_free (&last_result);
00209 }
00210 
00211 
00212 /* Free the thread specific data, this is done if a thread terminates.  */
00213 static void
00214 free_key_mem (void *mem)
00215 {
00216   check_free ((struct dl_action_result *) mem);
00217 
00218   free (mem);
00219   __libc_setspecific (key, NULL);
00220 }
00221 
00222 # ifdef SHARED
00223 
00224 struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
00225 libdl_hidden_data_def (_dlfcn_hook)
00226 
00227 # else
00228 
00229 static struct dlfcn_hook _dlfcn_hooks =
00230   {
00231     .dlopen = __dlopen,
00232     .dlclose = __dlclose,
00233     .dlsym = __dlsym,
00234     .dlvsym = __dlvsym,
00235     .dlerror = __dlerror,
00236     .dladdr = __dladdr,
00237     .dladdr1 = __dladdr1,
00238     .dlinfo = __dlinfo,
00239     .dlmopen = __dlmopen
00240   };
00241 
00242 void
00243 __libc_register_dlfcn_hook (struct link_map *map)
00244 {
00245   struct dlfcn_hook **hook;
00246 
00247   hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
00248   if (hook != NULL)
00249     *hook = &_dlfcn_hooks;
00250 }
00251 # endif
00252 #endif