diff options
Diffstat (limited to 'gprofng/libcollector/libcol_util.c')
-rw-r--r-- | gprofng/libcollector/libcol_util.c | 1693 |
1 files changed, 1693 insertions, 0 deletions
diff --git a/gprofng/libcollector/libcol_util.c b/gprofng/libcollector/libcol_util.c new file mode 100644 index 0000000..c709b3c --- /dev/null +++ b/gprofng/libcollector/libcol_util.c @@ -0,0 +1,1693 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <dlfcn.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "gp-defs.h" +#include "collector.h" +#include "libcol_util.h" +#include "gp-experiment.h" +#include "Emsgnum.h" +#include "memmgr.h" // __collector_allocCSize, __collector_freeCSize +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* + * This file is intended for collector's own implementation of + * various routines to avoid interaction with libc and other + * libraries. + */ + +/* ------- libc interface ----------------- */ +CollectorUtilFuncs __collector_util_funcs = {NULL}; +int __collector_dlsym_guard = 0; +int(*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...); + +/* + * We have calls on Solaris to get the thread ID. + * On Linux, there is a gettid() system call. + * From user space, we have to use syscall(__NR_gettid). + * The call is probably fast (with the tid in vdso), but dbx intercepts the syscall. + * 7182047 syscall() has large overhead under dbx on linux + * One option is to use an assembly call to get the tid. + * We know how to do this on x86, but not on SPARC. + * So another option is to do the syscall once and cache the result in thread-local storage. + * This solves the SPARC case. + * On x86 we could use one or both strategies. So there are opportunities here to simplify the code. + */ +static unsigned gettid_key = COLLECTOR_TSD_INVALID_KEY; + +void +__collector_ext_gettid_tsd_create_key () +{ + gettid_key = __collector_tsd_create_key (sizeof (pid_t), NULL, NULL); +} + +pid_t +__collector_gettid () +{ + pid_t *tid_ptr = (pid_t *) __collector_tsd_get_by_key (gettid_key); + // check if we have a thread-specific tid and if it's been initialized + // (it's 0 before initialization and cannot be 0 after since pid 0 is the boot process) + if (tid_ptr && *tid_ptr > 0) + return *tid_ptr; + pid_t r; + +#if ARCH(Intel) +#if WSIZE(32) +#define syscall_instr "int $0x80" +#define syscall_clobber "memory" +#else //WSIZE(64) +#define syscall_instr "syscall" +#define syscall_clobber "rcx", "r11", "memory" +#endif + __asm__ __volatile__(syscall_instr + : "=a" (r) : "0" (__NR_gettid) + : syscall_clobber); +#else + r = syscall (__NR_gettid); +#endif + if (tid_ptr) + *tid_ptr = r; + return r; +} + +static inline int +atomic_swap (volatile int * p, int v) +{ +#if ARCH(Intel) + int r; + __asm__ __volatile__("xchg %1, %2" : "=r" (r) : "m" (*p), "0" (v)); + return r; +#else + /* Since the inline templates perfan/libcollector/src/inline.*.il all + * have implementations for __collector_cas_32(), how about we just + * use that interface for Intel as well and drop the "#if ARCH()" stuff here? + * + * As it is, we're using an atomic swap on Intel and + * compare-and-swap on SPARC. The semantics are different + * (cas requires an expected "compare" value and swaps ONLY + * if we match that value). Nevertheless, the results of the + * two operations + * Intel: atomic_swap(&lock, 1) + * SPARC: cas(&lock,0,1) + * happen to be the same for the two cases we're interested in: + * if lock==0 lock=1 return 0 + * if lock==1 lock=1 return 1 + * You CANNOT always simply substitute cas for swap. + */ + return __collector_cas_32 ((volatile uint32_t *)p, 0, v); +#endif +} + +int +__collector_mutex_lock (collector_mutex_t *lock_var) +{ + volatile unsigned int i; /* xxxx volatile may not be honored on amd64 -x04 */ + + if (!(*lock_var) && !atomic_swap (lock_var, 1)) + return 0; + + do + { + while ((collector_mutex_t) (*lock_var) == 1) + i++; + } + while (atomic_swap (lock_var, 1)); + return 0; +} + +int +__collector_mutex_trylock (collector_mutex_t *lock_var) +{ + if (!(*lock_var) && !atomic_swap (lock_var, 1)) + return 0; + return EBUSY; +} + +int +__collector_mutex_unlock (collector_mutex_t *lock_var) +{ + (*lock_var) = 0; + return 0; +} + +#if ARCH(SPARC) +void +__collector_inc_32 (volatile uint32_t *mem) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: add %0,1,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem) + : "cc" + ); +} + +void +__collector_dec_32 (volatile uint32_t *mem) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: sub %0,1,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem) + : "cc" + ); +} + +uint32_t +__collector_cas_32 (volatile uint32_t *mem, uint32_t old, uint32_t new) +{ + __asm__ __volatile__("cas [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint32_t +__collector_subget_32 (volatile uint32_t *mem, uint32_t val) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: sub %0,%3,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + " sub %0,%3,%1 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem), "r" (val) + : "cc" + ); + return t2; +} + +#if WSIZE(32) + +void * +__collector_cas_ptr (volatile void *mem, void *old, void *new) +{ + __asm__ __volatile__("cas [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint64_t +__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new) +{ + uint64_t t; + __asm__ __volatile__(" ldx [%2],%2 \n" + " ldx [%3],%3 \n" + " casx [%1],%2,%3 \n" + " stx %3,%0 \n" + : "=m" (t) + : "r" (mem), "r" (old), "r" (new) + ); + return t; +} + +#elif WSIZE(64) + +void * +__collector_cas_ptr (volatile void *mem, void *old, void *new) +{ + __asm__ __volatile__("casx [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint64_t +__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new) +{ + uint64_t t; + __asm__ __volatile__(" ldx [%2],%2 \n" + " ldx [%3],%3 \n" + " casx [%1],%2,%3 \n" + " mov %3,%0 \n" + : "=&r" (t) + : "r" (mem), "r" (old), "r" (new) + ); + return t; +} + +#endif /* WSIZE() */ +#endif /* ARCH() */ + +void * +__collector_memcpy (void *s1, const void *s2, size_t n) +{ + char *cp1 = (char*) s1; + char *cp2 = (char*) s2; + while (n--) + *cp1++ = *cp2++; + return s1; +} + +static void * +collector_memset (void *s, int c, size_t n) +{ + unsigned char *s1 = s; + while (n--) + *s1++ = (unsigned char) c; + return s; +} + +int +__collector_strcmp (const char *s1, const char *s2) +{ + for (;;) + { + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + s1++; + s2++; + } +} + +int +__collector_strncmp (const char *s1, const char *s2, size_t n) +{ + while (n > 0) + { + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + s1++; + s2++; + n--; + } + return 0; +} + +char * +__collector_strstr (const char *s1, const char *s2) +{ + if (s2 == NULL || *s2 == 0) + return NULL; + size_t len = __collector_strlen (s2); + for (char c = *s2; *s1; s1++) + if (c == *s1 && __collector_strncmp (s1, s2, len) == 0) + return (char *) s1; + return NULL; +} + +char * +__collector_strchr (const char *str, int chr) +{ + if (chr == '\0') + return (char *) (str + __collector_strlen (str)); + for (; *str; str++) + if (chr == (int) *str) + return (char *) str; + return NULL; +} + +char * +__collector_strrchr (const char *str, int chr) +{ + const char *p = str + __collector_strlen (str); + for (; p - str >= 0; p--) + if (chr == *p) + return (char *) p; + return NULL; +} + +int +__collector_strStartWith (const char *s1, const char *s2) +{ + size_t slen = __collector_strlen (s2); + return __collector_strncmp (s1, s2, slen); +} + +size_t +__collector_strlen (const char *s) +{ + int len = -1; + while (s[++len] != '\0') + ; + return len; +} + +size_t +__collector_strlcpy (char *dst, const char *src, size_t dstsize) +{ + size_t srcsize = 0; + size_t n = dstsize - 1; + char c; + while ((c = *src++) != 0) + if (srcsize++ < n) + *dst++ = c; + if (dstsize > 0) + *dst = '\0'; + return srcsize; +} + +size_t +__collector_strncpy (char *dst, const char *src, size_t dstsize) +{ + size_t i; + for (i = 0; i < dstsize; i++) + { + dst[i] = src[i]; + if (src[i] == '\0') + break; + } + return i; +} + +char * +__collector_strcat (char *dst, const char *src) +{ + size_t sz = __collector_strlen (dst); + for (size_t i = 0;; i++) + { + dst[sz + i] = src[i]; + if (src[i] == '\0') + break; + } + return dst; +} + +size_t +__collector_strlcat (char *dst, const char *src, size_t dstsize) +{ + size_t sz = __collector_strlen (dst); + return sz + __collector_strlcpy (dst + sz, src, dstsize - sz); +} + +void * +__collector_malloc (size_t size) +{ + void * ptr = __collector_allocCSize (__collector_heap, size, 0); + return ptr; +} + +void * +__collector_calloc (size_t nelem, size_t elsize) +{ + size_t n = nelem * elsize; + void * ptr = __collector_malloc (n); + if (NULL == ptr) + return NULL; + collector_memset (ptr, 0, n); + return ptr; +} + +char * +__collector_strdup (const char * str) +{ + if (NULL == str) + return NULL; + size_t size = __collector_strlen (str); + char * dst = (char *) __collector_malloc (size + 1); + if (NULL == dst) + return NULL; + __collector_strncpy (dst, str, size + 1); + return dst; +} + +#define C_FMT 1 +#define C_STR 2 +static char +Printable[256] = {//characters should be escaped by xml: "'<>& + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 3, 3, 1, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* !"#$%&'()*+,-./ */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 3, /* 0123456789:;<=>? */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* PQRSTUVWXYZ[\]^_ */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, /* pqrstuvwxyz{|}~. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* ................ */ +}; +static char hex[17] = "0123456789abcdef"; +static char HEX[17] = "0123456789ABCDEF"; + +int +__collector_xml_snprintf (char *s, size_t n, const char *format, ...) +{ + va_list args; + va_start (args, format); + int res = __collector_xml_vsnprintf (s, n, format, args); + va_end (args); + return res; +} + +int +__collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args) +{ + const char *src = format; + char *dst = s; + int cnt = 0; + unsigned char c; + while ((c = *src) != 0) + { + if (c == '%') + { + char numbuf[32]; + int done = 0; + int jflag = 0; + int lflag = 0; + int zflag = 0; + int width = 0; + src++; + while (!done) + { + c = *src; + switch (c) + { + case '%': + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + src++; + done = 1; + break; + } + case '-': + { + if (jflag != 0) + done = 1; + else + { + jflag = 1; + src++; + } + break; + } + case 'l': + { + if (lflag != 0) + done = 1; + else + { + lflag = 1; + c = *++src; + if (c == 'l') + { + lflag++; + src++; + } + } + break; + } + case 'c': + { + unsigned char c1 = (unsigned char) va_arg (args, int); + if ((Printable[(int) c1] & C_STR) == 0) + { + if (c1 == '"') + {//" + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'q'; + if (cnt++ < n - 1) + *dst++ = 'u'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '\'') + {//' + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 's'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '&') + {//& + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'm'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '<') + {//< + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'l'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '>') + {//> + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'g'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c1 / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c1 % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + } + } + else if (cnt++ < n - 1) + *dst++ = c1; + src++; + done = 1; + break; + } + case 's': + { + /* Strings are always left justified */ + char *str = va_arg (args, char*); + if (!str) + str = "<NULL>"; + unsigned char c1; + while ((c1 = *str++) != 0) + { + if ((Printable[(int) c1] & C_STR) == 0) + { + if (c1 == '"') + {//" + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'q'; + if (cnt++ < n - 1) + *dst++ = 'u'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '\'') + {//' + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 's'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '&') + {//& + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'm'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '<') + {//< + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'l'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '>') + {//> + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'g'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c1 / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c1 % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + } + } + else if (cnt++ < n - 1) + *dst++ = c1; + width--; + } + while (width > 0) + { + if (cnt++ < n - 1) + *dst++ = ' '; + width--; + } + src++; + done = 1; + break; + } + case 'i': + case 'd': + case 'o': + case 'p': + case 'u': + case 'x': + case 'X': + { + int base = 10; + int uflag = 0; + int sflag = 0; + if (c == 'o') + { + uflag = 1; + base = 8; + } + else if (c == 'u') + uflag = 1; + else if (c == 'p') + { + lflag = 1; + uflag = 1; + base = 16; + } + else if (c == 'x' || c == 'X') + { + uflag = 1; + base = 16; + } + long long argll = 0LL; + if (lflag == 0) + { + if (uflag) + argll = va_arg (args, unsigned int); + else + argll = va_arg (args, int); + } + else if (lflag == 1) + { + if (uflag) + argll = va_arg (args, unsigned long); + else + argll = va_arg (args, long); + } + else if (lflag == 2) + argll = va_arg (args, long long); + unsigned long long argllu = 0ULL; + if (uflag || argll >= 0) + argllu = argll; + else + { + sflag = 1; + argllu = -argll; + } + int idx = sizeof (numbuf); + do + { + numbuf[--idx] = (c == 'X' ? HEX[argllu % base] : hex[argllu % base]); + argllu = argllu / base; + } + while (argllu != 0) + ; + if (sflag) + { + if (jflag || zflag) + { + if (cnt++ < n - 1) + *dst++ = '-'; + } + else + numbuf[--idx] = '-'; + } + + if (jflag) + { + while (idx < sizeof (numbuf) && width > 0) + { + if (cnt++ < n - 1) + *dst++ = numbuf[idx]; + idx++; + width--; + } + zflag = 0; + } + + while (width > sizeof (numbuf) - idx) + { + if (cnt++ < n - 1) + *dst++ = zflag ? '0' : ' '; + width--; + } + while (idx != sizeof (numbuf)) + { + if (cnt++ < n - 1) + *dst++ = numbuf[idx]; + idx++; + } + src++; + done = 1; + break; + } + case '0': + zflag = 1; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + { + while (c >= '0' && c <= '9') + { + width = width * 10 + (c - '0'); + c = *++src; + } + break; + } + default: + done = 1; + break; + } + } + } + else if ((Printable[(int) c] & C_FMT) == 0) + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + src++; + } + else + { + if (cnt++ < n - 1) + *dst++ = c; + src++; + } + } + + if (cnt < n - 1) + s[cnt] = '\0'; + else + s[n - 1] = '\0'; + + return cnt; +} + +/* + * Functions to be called directly from libc.so + */ +#if ARCH(Intel) /* intel-Linux */ +/* + * The CPUIDinfo/__collector_cpuid() code is old, + * incorrect, and complicated. It returns the apicid + * rather than the processor number. + * + * Unfortunately, the higher-level sched_getcpu() function, + * which we use on SPARC-Linux, is not available on Oracle + * Linux 5. So we have to test for its existence. + */ + +/* a pointer to sched_getcpu(), in case we find it */ +typedef int (*sched_getcpu_ptr_t)(void); +sched_getcpu_ptr_t sched_getcpu_ptr; +static int need_warning = 0; + +/* the old, low-level code */ +static int useLeafB = 0; + +/* access to the CPUID instruction on Intel/AMD */ +typedef struct +{ + uint32_t eax, ebx, ecx, edx; +} CPUIDinfo; + +/** + * This function returns the result of the "cpuid" instruction + */ +static __attribute__ ((always_inline)) inline void +__collector_cpuid (CPUIDinfo* info) +{ + uint32_t ebx = info->ebx, ecx = info->ecx, edx = info->edx, eax = info->eax; + __asm__ ("cpuid" : "=b" (ebx), "=c" (ecx), "=d" (edx), "=a" (eax) : "a" (eax)); + info->eax = eax; + info->ebx = ebx; + info->ecx = ecx; + info->edx = edx; +} + +static void +getcpuid_init () +{ + CPUIDinfo info; + info.eax = 0; /* max input value for CPUID */ + __collector_cpuid (&info); + + if (info.eax >= 0xb) + { + info.eax = 0xb; + info.ecx = 0; + __collector_cpuid (&info); + useLeafB = info.ebx != 0; + } + + /* indicate that we need a warning */ + /* (need to wait until log mechanism has been initialized) */ + need_warning = 1; +} + +static uint32_t +getcpuid () +{ + /* if we found sched_getcpu(), use it */ + if (sched_getcpu_ptr) + return (*sched_getcpu_ptr)(); + + /* otherwise, check if we need warning */ + if (need_warning) + { + if (useLeafB) + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">x2APIC</event>\n", + SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID); + else + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">APIC</event>\n", + SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID); + need_warning = 0; + } + + /* and use the old, low-level code */ + CPUIDinfo info; + if (useLeafB) + { + info.eax = 0xb; + info.ecx = 0; + __collector_cpuid (&info); + return info.edx; /* x2APIC ID */ + } + else + { + info.eax = 0x1; + info.ecx = 0; + __collector_cpuid (&info); + return info.ebx >> 24; /* APIC ID */ + } +} + +#else /* sparc-Linux */ + +/* + * EUGENE + * How should sched_getcpu() be prototyped? Like this? + * #include <sched.h> + * Or like this? + * #define _GNU_SOURCE + * #include <utmpx.h> + * Or just prototype this function explicitly without bothering with include files. + */ +int sched_getcpu (); + +static int +getcpuid () +{ + return sched_getcpu (); +} +#endif + +/* if ever retries time-out, we will stop allowing them */ +static int exhausted_retries = 0; + +int +__collector_open (const char *path, int oflag, ...) +{ + int fd; + mode_t mode = 0; + + hrtime_t t_timeout = __collector_gethrtime () + 5 * ((hrtime_t) NANOSEC); + int nretries = 0; + long long delay = 100; /* start at some small, arbitrary value */ + + /* get optional mode argument if it's expected/required */ + if (oflag | O_CREAT) + { + va_list ap; + va_start (ap, oflag); + mode = (mode_t) va_arg (ap, mode_t); + va_end (ap); + } + + /* retry upon failure */ + while ((fd = CALL_UTIL (open_bare)(path, oflag, mode)) < 0) + { + if (exhausted_retries) + break; + + /* The particular condition we're willing to retry is if + * too many file descriptors were in use. The errno should + * be EMFILE, but apparently and mysteriously it can also be + * and often is ENOENT. + */ + if ((errno != EMFILE) && (errno != ENOENT)) + break; + if (__collector_gethrtime () > t_timeout) + { + exhausted_retries = 1; + break; + } + + /* Oddly, if I replace this spin wait with + * - a usleep() call or + * - a loop on gethrtime() calls + * for roughly the same length of time, retries aren't very effective. */ + int ispin; + double xdummy = 0.5; + for (ispin = 0; ispin < delay; ispin++) + xdummy = 0.5 * (xdummy + 1.); + if (xdummy < 0.1) + /* should never happen, but we check so the loop won't be optimized away */ + break; + delay *= 2; + if (delay > 100000000) + delay = 100000000; /* cap at some large, arbitrary value */ + nretries++; + } + return fd; +} + +int +__collector_util_init () +{ + int oldos = 0; + + /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */ + void *libc = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD); + if (libc == NULL) + libc = dlopen (SYS_LIBC_NAME, RTLD_NOW | RTLD_LOCAL); + if (libc == NULL) + { + /* libcollector will subsequently abort, as all the pointers in the vector are NULL */ +#if 0 + /* SP_COLLECTOR_TRACELEVEL is not yet set, so no Tprintf */ + fprintf (stderr, "__collector_util_init: dlopen(%s) failed: %s\n", SYS_LIBC_NAME, dlerror ()); + return COL_ERROR_UTIL_INIT; +#endif + abort (); + } + + void *ptr = dlsym (libc, "fprintf"); + if (ptr) + __collector_util_funcs.fprintf = (int(*)(FILE *, const char *, ...))ptr; + else + { + // We can't write any error messages without a libc reference +#if 0 + fprintf (stderr, "__collector_util_init: COLERROR_UTIL_INIT fprintf: %s\n", dlerror ()); + return COL_ERROR_UTIL_INIT; +#endif + abort (); + } + int err = 0; + + ptr = dlsym (libc, "mmap"); + if (ptr) + __collector_util_funcs.mmap = (void*(*)(void *, size_t, int, int, int, off_t))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mmap: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + /* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */ + /* internal calls for mapping in libcollector call mmap64 */ + ptr = dlsym (libc, "mmap64"); + if (ptr) + __collector_util_funcs.mmap64 = (void*(*)(void *, size_t, int, int, int, off_t))ptr; + else + __collector_util_funcs.mmap64 = __collector_util_funcs.mmap; + + ptr = dlsym (libc, "munmap"); + if (ptr) + __collector_util_funcs.munmap = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT munmap: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "close"); + if (ptr) + __collector_util_funcs.close = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "open"); + if (ptr) + __collector_util_funcs.open = (int(*)(const char *path, int oflag, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT open: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "open64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "open64", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "open64"); + if (ptr) + __collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr; + else + __collector_util_funcs.open_bare = __collector_util_funcs.open; +#if ARCH(Intel) && WSIZE(32) + } +#endif /* ARCH(Intel) && WSIZE(32) */ + + ptr = dlsym (libc, "close"); + if (ptr) + __collector_util_funcs.close = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "read"); + if (ptr) + __collector_util_funcs.read = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT read: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "write"); + if (ptr) + __collector_util_funcs.write = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT write: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "pwrite", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.pwrite = (ssize_t (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "pwrite"); + if (ptr) + __collector_util_funcs.pwrite = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pwrite: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "pwrite64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.pwrite64 = (ssize_t (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite64", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "pwrite64"); + if (ptr) + __collector_util_funcs.pwrite64 = (ssize_t (*)())ptr; + else + __collector_util_funcs.pwrite64 = __collector_util_funcs.pwrite; +#if ARCH(Intel) && WSIZE(32) + } +#endif /* ARCH(Intel) && WSIZE(32) */ + + ptr = dlsym (libc, "lseek"); + if (ptr) + __collector_util_funcs.lseek = (off_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT lseek: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "access"); + if (ptr) + __collector_util_funcs.access = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT access: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "mkdir"); + if (ptr) + __collector_util_funcs.mkdir = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mkdir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "opendir"); + if (ptr) + __collector_util_funcs.opendir = (DIR * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT opendir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "closedir"); + if (ptr) + __collector_util_funcs.closedir = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT closedir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "execv"); + if (ptr) + __collector_util_funcs.execv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT execv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "exit"); + if (ptr) + __collector_util_funcs.exit = (void(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT exit: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "vfork"); + if (ptr) + __collector_util_funcs.vfork = (pid_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vfork: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "waitpid"); + if (ptr) + __collector_util_funcs.waitpid = (pid_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT waitpid: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + int (*__collector_getcpuid)() = (int(*)()) & getcpuid; +#if ARCH(Intel) + /* if sched_getcpu() not found, init our getcpuid() */ + sched_getcpu_ptr = (sched_getcpu_ptr_t) dlsym (libc, "sched_getcpu"); + if (sched_getcpu_ptr == NULL) + getcpuid_init (); +#endif + __collector_util_funcs.getcpuid = __collector_getcpuid; + __collector_util_funcs.memset = collector_memset; + + ptr = dlsym (libc, "malloc"); + if (ptr) + __collector_util_funcs.malloc = (void *(*)(size_t))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT malloc: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "putenv"); + if (ptr) + __collector_util_funcs.putenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT putenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "getenv"); + if (ptr) + __collector_util_funcs.getenv = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT getenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "time"); + if (ptr) + __collector_util_funcs.time = (time_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT time: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "mktime"); + if (ptr) + __collector_util_funcs.mktime = (time_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mktime: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strcmp = __collector_strcmp; + __collector_util_funcs.strncmp = __collector_strncmp; + __collector_util_funcs.strncpy = __collector_strncpy; + __collector_util_funcs.strstr = __collector_strstr; + + ptr = dlsym (libc, "gmtime_r"); + if (ptr) + __collector_util_funcs.gmtime_r = (struct tm * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT gmtime_r: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtol"); + if (ptr) + __collector_util_funcs.strtol = (long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtol: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoll"); + if (ptr) + __collector_util_funcs.strtoll = (long long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoll: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strchr = __collector_strchr; + __collector_util_funcs.strrchr = __collector_strrchr; + + ptr = dlsym (libc, "setenv"); + if (ptr) + __collector_util_funcs.setenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT setenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "unsetenv"); + if (ptr) + __collector_util_funcs.unsetenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT unsetenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "atof"); + if (ptr) + __collector_util_funcs.atof = (double (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atof: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sysinfo"); + if (ptr) + __collector_util_funcs.sysinfo = (long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysinfo: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "clearenv"); + if (ptr) + __collector_util_funcs.clearenv = (int(*)())ptr; + else + { + /* suppress warning on S10 or earlier Solaris */ + if (oldos == 0) + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT clearenv: %s\n", dlerror ()); + /* err = COL_ERROR_UTIL_INIT; */ + /* don't treat this as fatal, so that S10 could work */ + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "fopen", "GLIBC_2.1"); + if (ptr) + __collector_util_funcs.fopen = (FILE * (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "fopen", "GLIBC_2.1"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "fopen"); + if (ptr) + __collector_util_funcs.fopen = (FILE * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fopen: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + + ptr = dlsym (libc, "popen"); + if (ptr) + __collector_util_funcs.popen = (FILE * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT popen: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "fclose", "GLIBC_2.1"); + if (ptr) + __collector_util_funcs.fclose = (int(*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "fclose", "GLIBC_2.1"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "fclose"); + if (ptr) + __collector_util_funcs.fclose = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fclose: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + + ptr = dlsym (libc, "pclose"); + if (ptr) + __collector_util_funcs.pclose = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pclose: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "fgets"); + if (ptr) + __collector_util_funcs.fgets = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fgets: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sscanf"); + if (ptr) + __collector_sscanfp = (int(*)(const char *restrict s, const char *restrict fmt, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sscanf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "snprintf"); + if (ptr) + __collector_util_funcs.snprintf = (int(*)(char *, size_t, const char *, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT snprintf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "vsnprintf"); + if (ptr) + __collector_util_funcs.vsnprintf = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vsnprintf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "atoi"); + if (ptr) + __collector_util_funcs.atoi = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atoi: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "calloc"); + if (ptr) + __collector_util_funcs.calloc = (void*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT calloc: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "free"); + if (ptr) + { + __collector_util_funcs.free = (void(*)())ptr; + } + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT free: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strdup"); + if (ptr) + __collector_util_funcs.libc_strdup = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strdup: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strlen = __collector_strlen; + __collector_util_funcs.strlcat = __collector_strlcat; + __collector_util_funcs.strlcpy = __collector_strlcpy; + + ptr = dlsym (libc, "strerror"); + if (ptr) + __collector_util_funcs.strerror = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + ptr = dlsym (libc, "strerror_r"); + if (ptr) + __collector_util_funcs.strerror_r = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror_r: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + ptr = dlsym (libc, "strspn"); + if (ptr) + __collector_util_funcs.strspn = (size_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strspn: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoul"); + if (ptr) + __collector_util_funcs.strtoul = (unsigned long int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoul: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoull"); + if (ptr) + __collector_util_funcs.strtoull = (unsigned long long int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoull: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "fcntl"); + if (ptr) + __collector_util_funcs.fcntl = (int(*)(int, int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fcntl: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "ioctl"); + if (ptr) + __collector_util_funcs.ioctl = (int(*)(int, int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT ioctl: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "symlink"); + if (ptr) + __collector_util_funcs.symlink = (int(*)(const char*, const char*))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT symlink: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "syscall"); + if (ptr) + __collector_util_funcs.syscall = (int(*)(int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT syscall: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sysconf"); + if (ptr) + __collector_util_funcs.sysconf = (long(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysconf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sigfillset"); + if (ptr) + __collector_util_funcs.sigfillset = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigfillset: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sigprocmask"); + if (ptr) + __collector_util_funcs.sigprocmask = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigprocmask: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + return err; +} |