[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/libc/glibc/glibc-2.22/dlfcn/dlerror.c b/ap/libc/glibc/glibc-2.22/dlfcn/dlerror.c
new file mode 100644
index 0000000..5d3bd03
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.22/dlfcn/dlerror.c
@@ -0,0 +1,254 @@
+/* Return error detail for failing <dlfcn.h> functions.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#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>
+
+#if !defined SHARED && IS_IN (libdl)
+
+char *
+dlerror (void)
+{
+ return __dlerror ();
+}
+
+#else
+
+/* Type for storing results of dynamic loading actions. */
+struct dl_action_result
+ {
+ int errcode;
+ int returned;
+ bool malloced;
+ const char *objname;
+ const char *errstring;
+ };
+static struct dl_action_result last_result;
+static struct dl_action_result *static_buf;
+
+/* This is the key for the thread specific memory. */
+static __libc_key_t key;
+__libc_once_define (static, once);
+
+/* Destructor for the thread-specific data. */
+static void init (void);
+static void free_key_mem (void *mem);
+
+
+char *
+__dlerror (void)
+{
+ char *buf = NULL;
+ struct dl_action_result *result;
+
+# ifdef SHARED
+ if (__glibc_unlikely (_dlfcn_hook != NULL))
+ 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;
+}
+# ifdef SHARED
+strong_alias (__dlerror, dlerror)
+# endif
+
+int
+internal_function
+_dlerror_run (void (*operate) (void *), void *args)
+{
+ 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;
+}
+
+
+/* Initialize buffers for results. */
+static void
+init (void)
+{
+ 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;
+}
+
+
+static void
+check_free (struct dl_action_result *rec)
+{
+ 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 namespace. When we're statically
+ linked, the dynamic linker is part of the program and so always
+ uses the same C library we use here. */
+#ifdef SHARED
+ struct link_map *map = NULL;
+ Dl_info info;
+ if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
+#endif
+ free ((char *) rec->errstring);
+ }
+}
+
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ check_free (&last_result);
+}
+
+
+/* Free the thread specific data, this is done if a thread terminates. */
+static void
+free_key_mem (void *mem)
+{
+ check_free ((struct dl_action_result *) mem);
+
+ free (mem);
+ __libc_setspecific (key, NULL);
+}
+
+# ifdef SHARED
+
+struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+libdl_hidden_data_def (_dlfcn_hook)
+
+# else
+
+static struct dlfcn_hook _dlfcn_hooks =
+ {
+ .dlopen = __dlopen,
+ .dlclose = __dlclose,
+ .dlsym = __dlsym,
+ .dlvsym = __dlvsym,
+ .dlerror = __dlerror,
+ .dladdr = __dladdr,
+ .dladdr1 = __dladdr1,
+ .dlinfo = __dlinfo,
+ .dlmopen = __dlmopen
+ };
+
+void
+__libc_register_dlfcn_hook (struct link_map *map)
+{
+ struct dlfcn_hook **hook;
+
+ hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
+ if (hook != NULL)
+ *hook = &_dlfcn_hooks;
+}
+# endif
+#endif