1693 lines
42 KiB
C
1693 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 == '"')
|
|
{//"
|
|
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;
|
|
}
|