binutils-gdb/gprofng/libcollector/libcol_util.c
Vladimir Mezentsev bb368aad29 gprofng: a new GNU profiler
top-level
	* Makefile.def: Add gprofng module.
	* configure.ac: Add --enable-gprofng option.
	* src-release.sh: Add gprofng.
	* Makefile.in: Regenerate.
	* configure: Regenerate.
	* gprofng: New directory.

binutils
	* MAINTAINERS: Add gprofng maintainer.
	* README-how-to-make-a-release: Add gprofng.

include.
	* collectorAPI.h: New file.
	* libcollector.h: New file.
	* libfcollector.h: New file.
2022-03-11 08:58:31 +00:00

1694 lines
42 KiB
C

/* 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 == '"')
{//&quot;
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 == '\'')
{//&apos;
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 == '&')
{//&amp;
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 == '<')
{//&lt;
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 == '>')
{//&gt;
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 == '"')
{//&quot;
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 == '\'')
{//&apos;
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 == '&')
{//&amp;
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 == '<')
{//&lt;
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 == '>')
{//&gt;
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;
}