(linenum→info "unix/slp.c:2238")

glibc/2.7/dlfcn/dlerror.c

    1: /* Return error detail for failing <dlfcn.h> functions.
    2:    Copyright (C) 1995-2000,2002,2003,2004,2005 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <dlfcn.h>
   21: #include <libintl.h>
   22: #include <stdbool.h>
   23: #include <stdio.h>
   24: #include <stdlib.h>
   25: #include <string.h>
   26: #include <bits/libc-lock.h>
   27: #include <ldsodefs.h>
   28: 
   29: #if !defined SHARED && defined IS_IN_libdl
   30: 
   31: char *
   32: dlerror (void)
   33: {
   34:   return __dlerror ();
   35: }
   36: 
   37: #else
   38: 
   39: /* Type for storing results of dynamic loading actions.  */
   40: struct dl_action_result
   41:   {
   42:     int errcode;
   43:     int returned;
   44:     bool malloced;
   45:     const char *objname;
   46:     const char *errstring;
   47:   };
   48: static struct dl_action_result last_result;
   49: static struct dl_action_result *static_buf;
   50: 
   51: /* This is the key for the thread specific memory.  */
   52: static __libc_key_t key;
   53: __libc_once_define (static, once);
   54: 
   55: /* Destructor for the thread-specific data.  */
   56: static void init (void);
   57: static void free_key_mem (void *mem);
   58: 
   59: 
   60: char *
   61: __dlerror (void)
   62: {
   63:   char *buf = NULL;
   64:   struct dl_action_result *result;
   65: 
   66: # ifdef SHARED
   67:   if (__builtin_expect (_dlfcn_hook != NULL, 0))
   68:     return _dlfcn_hook->dlerror ();
   69: # endif
   70: 
   71:   /* If we have not yet initialized the buffer do it now.  */
   72:   __libc_once (once, init);
   73: 
   74:   /* Get error string.  */
   75:   result = (struct dl_action_result *) __libc_getspecific (key);
   76:   if (result == NULL)
   77:     result = &last_result;
   78: 
   79:   /* Test whether we already returned the string.  */
   80:   if (result->returned != 0)
   81:     {
   82:       /* We can now free the string.  */
   83:       if (result->errstring != NULL)
   84:         {
   85:           if (strcmp (result->errstring, "out of memory") != 0)
   86:             free ((char *) result->errstring);
   87:           result->errstring = NULL;
   88:         }
   89:     }
   90:   else if (result->errstring != NULL)
   91:     {
   92:       buf = (char *) result->errstring;
   93:       int n;
   94:       if (result->errcode == 0)
   95:         n = __asprintf (&buf, "%s%s%s",
   96:                         result->objname,
   97:                         result->objname[0] == '\0' ? "" : ": ",
   98:                         _(result->errstring));
   99:       else
  100:         n = __asprintf (&buf, "%s%s%s: %s",
  101:                         result->objname,
  102:                         result->objname[0] == '\0' ? "" : ": ",
  103:                         _(result->errstring),
  104:                         strerror (result->errcode));
  105:       if (n != -1)
  106:         {
  107:           /* We don't need the error string anymore.  */
  108:           if (strcmp (result->errstring, "out of memory") != 0)
  109:             free ((char *) result->errstring);
  110:           result->errstring = buf;
  111:         }
  112: 
  113:       /* Mark the error as returned.  */
  114:       result->returned = 1;
  115:     }
  116: 
  117:   return buf;
  118: }
  119: # ifdef SHARED
  120: strong_alias (__dlerror, dlerror)
  121: # endif
  122: 
  123: int
  124: internal_function
  125: _dlerror_run (void (*operate) (void *), void *args)
  126: {
  127:   struct dl_action_result *result;
  128: 
  129:   /* If we have not yet initialized the buffer do it now.  */
  130:   __libc_once (once, init);
  131: 
  132:   /* Get error string and number.  */
  133:   if (static_buf != NULL)
  134:     result = static_buf;
  135:   else
  136:     {
  137:       /* We don't use the static buffer and so we have a key.  Use it
  138:          to get the thread-specific buffer.  */
  139:       result = __libc_getspecific (key);
  140:       if (result == NULL)
  141:         {
  142:           result = (struct dl_action_result *) calloc (1, sizeof (*result));
  143:           if (result == NULL)
  144:             /* We are out of memory.  Since this is no really critical
  145:                situation we carry on by using the global variable.
  146:                This might lead to conflicts between the threads but
  147:                they soon all will have memory problems.  */
  148:             result = &last_result;
  149:           else
  150:             /* Set the tsd.  */
  151:             __libc_setspecific (key, result);
  152:         }
  153:     }
  154: 
  155:   if (result->errstring != NULL)
  156:     {
  157:       /* Free the error string from the last failed command.  This can
  158:          happen if `dlerror' was not run after an error was found.  */
  159:       if (result->malloced)
  160:         free ((char *) result->errstring);
  161:       result->errstring = NULL;
  162:     }
  163: 
  164:   result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
  165:                                           &result->malloced, operate, args);
  166: 
  167:   /* If no error we mark that no error string is available.  */
  168:   result->returned = result->errstring == NULL;
  169: 
  170:   return result->errstring != NULL;
  171: }
  172: 
  173: 
  174: /* Initialize buffers for results.  */
  175: static void
  176: init (void)
  177: {
  178:   if (__libc_key_create (&key, free_key_mem))
  179:     /* Creating the key failed.  This means something really went
  180:        wrong.  In any case use a static buffer which is better than
  181:        nothing.  */
  182:     static_buf = &last_result;
  183: }
  184: 
  185: 
  186: static void
  187: check_free (struct dl_action_result *rec)
  188: {
  189:   if (rec->errstring != NULL
  190:       && strcmp (rec->errstring, "out of memory") != 0)
  191:     {
  192:       /* We can free the string only if the allocation happened in the
  193:          C library used by the dynamic linker.  This means, it is
  194:          always the C library in the base namespave.  */
  195:       struct link_map *map = NULL;
  196:       Dl_info info;
  197:       if (_dl_addr (check_free, &info, &map, NULL) != 0
  198:           && map != NULL && map->l_ns == 0)
  199:         free ((char *) rec->errstring);
  200:     }
  201: }
  202: 
  203: 
  204: static void
  205: __attribute__ ((destructor))
  206: fini (void)
  207: {
  208:   check_free (&last_result);
  209: }
  210: 
  211: 
  212: /* Free the thread specific data, this is done if a thread terminates.  */
  213: static void
  214: free_key_mem (void *mem)
  215: {
  216:   check_free ((struct dl_action_result *) mem);
  217: 
  218:   free (mem);
  219:   __libc_setspecific (key, NULL);
  220: }
  221: 
  222: # ifdef SHARED
  223: 
  224: struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
  225: libdl_hidden_data_def (_dlfcn_hook)
  226: 
  227: # else
  228: 
  229: static struct dlfcn_hook _dlfcn_hooks =
  230:   {
  231:     .dlopen = __dlopen,
  232:     .dlclose = __dlclose,
  233:     .dlsym = __dlsym,
  234:     .dlvsym = __dlvsym,
  235:     .dlerror = __dlerror,
  236:     .dladdr = __dladdr,
  237:     .dladdr1 = __dladdr1,
  238:     .dlinfo = __dlinfo,
  239:     .dlmopen = __dlmopen
  240:   };
  241: 
  242: void
  243: __libc_register_dlfcn_hook (struct link_map *map)
  244: {
  245:   struct dlfcn_hook **hook;
  246: 
  247:   hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
  248:   if (hook != NULL)
  249:     *hook = &_dlfcn_hooks;
  250: }
  251: # endif
  252: #endif
Syntax (Markdown)