1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
22 #include <sys/types.h>
31 #include <sys/syscall.h>
33 #include <sys/ioctl.h>
36 #include "collector.h"
37 #include "libcol_util.h"
38 #include "gp-experiment.h"
40 #include "memmgr.h" // __collector_allocCSize, __collector_freeCSize
44 * This file is intended for collector's own implementation of
45 * various routines to avoid interaction with libc and other
49 /* ------- libc interface ----------------- */
50 CollectorUtilFuncs __collector_util_funcs
= {NULL
};
51 int __collector_dlsym_guard
= 0;
52 int(*__collector_sscanfp
)(const char *restrict s
, const char *restrict fmt
, ...);
55 * We have calls on Solaris to get the thread ID.
56 * On Linux, there is a gettid() system call.
57 * From user space, we have to use syscall(__NR_gettid).
58 * The call is probably fast (with the tid in vdso), but dbx intercepts the syscall.
59 * 7182047 syscall() has large overhead under dbx on linux
60 * One option is to use an assembly call to get the tid.
61 * We know how to do this on x86, but not on SPARC.
62 * So another option is to do the syscall once and cache the result in thread-local storage.
63 * This solves the SPARC case.
64 * On x86 we could use one or both strategies. So there are opportunities here to simplify the code.
66 static unsigned gettid_key
= COLLECTOR_TSD_INVALID_KEY
;
69 __collector_ext_gettid_tsd_create_key ()
71 gettid_key
= __collector_tsd_create_key (sizeof (pid_t
), NULL
, NULL
);
77 pid_t
*tid_ptr
= (pid_t
*) __collector_tsd_get_by_key (gettid_key
);
78 // check if we have a thread-specific tid and if it's been initialized
79 // (it's 0 before initialization and cannot be 0 after since pid 0 is the boot process)
80 if (tid_ptr
&& *tid_ptr
> 0)
86 #define syscall_instr "int $0x80"
87 #define syscall_clobber "memory"
89 #define syscall_instr "syscall"
90 #define syscall_clobber "rcx", "r11", "memory"
92 __asm__
__volatile__(syscall_instr
93 : "=a" (r
) : "0" (__NR_gettid
)
96 r
= syscall (__NR_gettid
);
104 atomic_swap (volatile int * p
, int v
)
108 __asm__
__volatile__("xchg %1, %2" : "=r" (r
) : "m" (*p
), "0" (v
));
111 /* Since the inline templates perfan/libcollector/src/inline.*.il all
112 * have implementations for __collector_cas_32(), how about we just
113 * use that interface for Intel as well and drop the "#if ARCH()" stuff here?
115 * As it is, we're using an atomic swap on Intel and
116 * compare-and-swap on SPARC. The semantics are different
117 * (cas requires an expected "compare" value and swaps ONLY
118 * if we match that value). Nevertheless, the results of the
120 * Intel: atomic_swap(&lock, 1)
121 * SPARC: cas(&lock,0,1)
122 * happen to be the same for the two cases we're interested in:
123 * if lock==0 lock=1 return 0
124 * if lock==1 lock=1 return 1
125 * You CANNOT always simply substitute cas for swap.
127 return __collector_cas_32 ((volatile uint32_t *)p
, 0, v
);
132 __collector_mutex_lock (collector_mutex_t
*lock_var
)
134 volatile unsigned int i
= 0; /* xxxx volatile may not be honored on amd64 -x04 */
136 if (!(*lock_var
) && !atomic_swap (lock_var
, 1))
141 while ((collector_mutex_t
) (*lock_var
) == 1)
144 while (atomic_swap (lock_var
, 1));
149 __collector_mutex_trylock (collector_mutex_t
*lock_var
)
151 if (!(*lock_var
) && !atomic_swap (lock_var
, 1))
157 __collector_mutex_unlock (collector_mutex_t
*lock_var
)
165 __collector_inc_32 (volatile uint32_t *mem
)
168 __asm__
__volatile__(" ld %2,%0 \n"
174 : "=&r" (t1
), "=&r" (t2
)
181 __collector_dec_32 (volatile uint32_t *mem
)
184 __asm__
__volatile__(" ld %2,%0 \n"
190 : "=&r" (t1
), "=&r" (t2
)
197 __collector_cas_32 (volatile uint32_t *mem
, uint32_t old
, uint32_t new)
199 __asm__
__volatile__("cas [%1],%2,%0"
201 : "r" (mem
), "r" (old
));
206 __collector_subget_32 (volatile uint32_t *mem
, uint32_t val
)
209 __asm__
__volatile__(" ld %2,%0 \n"
216 : "=&r" (t1
), "=&r" (t2
)
217 : "m" (*mem
), "r" (val
)
226 __collector_cas_ptr (volatile void *mem
, void *old
, void *new)
228 __asm__
__volatile__("cas [%1],%2,%0"
230 : "r" (mem
), "r" (old
));
235 __collector_cas_64p (volatile uint64_t *mem
, uint64_t *old
, uint64_t *new)
238 __asm__
__volatile__(" ldx [%2],%2 \n"
240 " casx [%1],%2,%3 \n"
243 : "r" (mem
), "r" (old
), "r" (new)
251 __collector_cas_ptr (volatile void *mem
, void *old
, void *new)
253 __asm__
__volatile__("casx [%1],%2,%0"
255 : "r" (mem
), "r" (old
));
260 __collector_cas_64p (volatile uint64_t *mem
, uint64_t *old
, uint64_t *new)
263 __asm__
__volatile__(" ldx [%2],%2 \n"
265 " casx [%1],%2,%3 \n"
268 : "r" (mem
), "r" (old
), "r" (new)
277 __collector_memcpy (void *s1
, const void *s2
, size_t n
)
279 char *cp1
= (char*) s1
;
280 char *cp2
= (char*) s2
;
287 collector_memset (void *s
, int c
, size_t n
)
289 unsigned char *s1
= s
;
291 *s1
++ = (unsigned char) c
;
296 __collector_strcmp (const char *s1
, const char *s2
)
310 __collector_strncmp (const char *s1
, const char *s2
, size_t n
)
326 __collector_strstr (const char *s1
, const char *s2
)
328 if (s2
== NULL
|| *s2
== 0)
330 size_t len
= __collector_strlen (s2
);
331 for (char c
= *s2
; *s1
; s1
++)
332 if (c
== *s1
&& __collector_strncmp (s1
, s2
, len
) == 0)
338 __collector_strchr (const char *str
, int chr
)
341 return (char *) (str
+ __collector_strlen (str
));
343 if (chr
== (int) *str
)
349 __collector_strrchr (const char *str
, int chr
)
351 const char *p
= str
+ __collector_strlen (str
);
352 for (; p
- str
>= 0; p
--)
359 __collector_strStartWith (const char *s1
, const char *s2
)
361 size_t slen
= __collector_strlen (s2
);
362 return __collector_strncmp (s1
, s2
, slen
);
366 __collector_strlen (const char *s
)
369 while (s
[++len
] != '\0')
375 __collector_strlcpy (char *dst
, const char *src
, size_t dstsize
)
378 size_t n
= dstsize
- 1;
380 while ((c
= *src
++) != 0)
389 __collector_strncpy (char *dst
, const char *src
, size_t dstsize
)
392 for (i
= 0; i
< dstsize
; i
++)
402 __collector_strcat (char *dst
, const char *src
)
404 size_t sz
= __collector_strlen (dst
);
405 for (size_t i
= 0;; i
++)
407 dst
[sz
+ i
] = src
[i
];
415 __collector_strlcat (char *dst
, const char *src
, size_t dstsize
)
417 size_t sz
= __collector_strlen (dst
);
418 return sz
+ __collector_strlcpy (dst
+ sz
, src
, dstsize
- sz
);
422 __collector_malloc (size_t size
)
424 void * ptr
= __collector_allocCSize (__collector_heap
, size
, 0);
429 __collector_calloc (size_t nelem
, size_t elsize
)
431 size_t n
= nelem
* elsize
;
432 void * ptr
= __collector_malloc (n
);
435 collector_memset (ptr
, 0, n
);
440 __collector_strdup (const char * str
)
444 size_t size
= __collector_strlen (str
);
445 char * dst
= (char *) __collector_malloc (size
+ 1);
448 __collector_strncpy (dst
, str
, size
+ 1);
455 Printable
[256] = {//characters should be escaped by xml: "'<>&
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, /* ................ */
457 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
458 3, 3, 1, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* !"#$%&'()*+,-./ */
459 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 3, /* 0123456789:;<=>? */
460 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
461 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* PQRSTUVWXYZ[\]^_ */
462 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
463 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, /* pqrstuvwxyz{|}~. */
464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
465 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
466 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
468 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
469 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
470 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
471 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* ................ */
473 static char hex
[17] = "0123456789abcdef";
474 static char HEX
[17] = "0123456789ABCDEF";
477 __collector_xml_snprintf (char *s
, size_t n
, const char *format
, ...)
480 va_start (args
, format
);
481 int res
= __collector_xml_vsnprintf (s
, n
, format
, args
);
487 __collector_xml_vsnprintf (char *s
, size_t n
, const char *format
, va_list args
)
489 const char *src
= format
;
493 while ((c
= *src
) != 0)
514 *dst
++ = hex
[c
/ 16];
516 *dst
++ = hex
[c
% 16];
552 unsigned char c1
= (unsigned char) va_arg (args
, int);
553 if ((Printable
[(int) c1
] & C_STR
) == 0)
625 *dst
++ = hex
[c1
/ 16];
627 *dst
++ = hex
[c1
% 16];
632 else if (cnt
++ < n
- 1)
640 /* Strings are always left justified */
641 char *str
= va_arg (args
, char*);
645 while ((c1
= *str
++) != 0)
647 if ((Printable
[(int) c1
] & C_STR
) == 0)
719 *dst
++ = hex
[c1
/ 16];
721 *dst
++ = hex
[c1
% 16];
726 else if (cnt
++ < n
- 1)
764 else if (c
== 'x' || c
== 'X')
769 long long argll
= 0LL;
773 argll
= va_arg (args
, unsigned int);
775 argll
= va_arg (args
, int);
780 argll
= va_arg (args
, unsigned long);
782 argll
= va_arg (args
, long);
785 argll
= va_arg (args
, long long);
786 unsigned long long argllu
= 0ULL;
787 if (uflag
|| argll
>= 0)
794 int idx
= sizeof (numbuf
);
797 numbuf
[--idx
] = (c
== 'X' ? HEX
[argllu
% base
] : hex
[argllu
% base
]);
798 argllu
= argllu
/ base
;
815 while (idx
< sizeof (numbuf
) && width
> 0)
818 *dst
++ = numbuf
[idx
];
825 while (width
> sizeof (numbuf
) - idx
)
828 *dst
++ = zflag
? '0' : ' ';
831 while (idx
!= sizeof (numbuf
))
834 *dst
++ = numbuf
[idx
];
843 case '1': case '2': case '3': case '4': case '5':
844 case '6': case '7': case '8': case '9':
846 while (c
>= '0' && c
<= '9')
848 width
= width
* 10 + (c
- '0');
859 else if ((Printable
[(int) c
] & C_FMT
) == 0)
864 *dst
++ = hex
[c
/ 16];
866 *dst
++ = hex
[c
% 16];
888 * Functions to be called directly from libc.so
890 #if ARCH(Intel) /* intel-Linux */
892 * The CPUIDinfo/__collector_cpuid() code is old,
893 * incorrect, and complicated. It returns the apicid
894 * rather than the processor number.
896 * Unfortunately, the higher-level sched_getcpu() function,
897 * which we use on SPARC-Linux, is not available on Oracle
898 * Linux 5. So we have to test for its existence.
901 /* a pointer to sched_getcpu(), in case we find it */
902 typedef int (*sched_getcpu_ptr_t
)(void);
903 sched_getcpu_ptr_t sched_getcpu_ptr
;
904 static int need_warning
= 0;
906 /* the old, low-level code */
907 static int useLeafB
= 0;
909 /* access to the CPUID instruction on Intel/AMD */
912 uint32_t eax
, ebx
, ecx
, edx
;
916 * This function returns the result of the "cpuid" instruction
918 static __attribute__ ((always_inline
)) inline void
919 __collector_cpuid (CPUIDinfo
* info
)
921 uint32_t ebx
= info
->ebx
, ecx
= info
->ecx
, edx
= info
->edx
, eax
= info
->eax
;
922 __asm__ ("cpuid" : "=b" (ebx
), "=c" (ecx
), "=d" (edx
), "=a" (eax
) : "a" (eax
));
933 info
.eax
= 0; /* max input value for CPUID */
934 __collector_cpuid (&info
);
940 __collector_cpuid (&info
);
941 useLeafB
= info
.ebx
!= 0;
944 /* indicate that we need a warning */
945 /* (need to wait until log mechanism has been initialized) */
952 /* if we found sched_getcpu(), use it */
953 if (sched_getcpu_ptr
)
954 return (*sched_getcpu_ptr
)();
956 /* otherwise, check if we need warning */
960 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">x2APIC</event>\n",
961 SP_JCMD_CWARN
, COL_WARN_LINUX_X86_APICID
);
963 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">APIC</event>\n",
964 SP_JCMD_CWARN
, COL_WARN_LINUX_X86_APICID
);
968 /* and use the old, low-level code */
974 __collector_cpuid (&info
);
975 return info
.edx
; /* x2APIC ID */
981 __collector_cpuid (&info
);
982 return info
.ebx
>> 24; /* APIC ID */
986 #else /* sparc-Linux */
990 * How should sched_getcpu() be prototyped? Like this?
993 * #define _GNU_SOURCE
995 * Or just prototype this function explicitly without bothering with include files.
1002 return sched_getcpu ();
1006 /* if ever retries time-out, we will stop allowing them */
1007 static int exhausted_retries
= 0;
1010 __collector_open (const char *path
, int oflag
, ...)
1015 hrtime_t t_timeout
= __collector_gethrtime () + 5 * ((hrtime_t
) NANOSEC
);
1017 long long delay
= 100; /* start at some small, arbitrary value */
1019 /* get optional mode argument if it's expected/required */
1020 if (oflag
| O_CREAT
)
1023 va_start (ap
, oflag
);
1024 mode
= (mode_t
) va_arg (ap
, mode_t
);
1028 /* retry upon failure */
1029 while ((fd
= CALL_UTIL (open_bare
)(path
, oflag
, mode
)) < 0)
1031 if (exhausted_retries
)
1034 /* The particular condition we're willing to retry is if
1035 * too many file descriptors were in use. The errno should
1036 * be EMFILE, but apparently and mysteriously it can also be
1037 * and often is ENOENT.
1039 if ((errno
!= EMFILE
) && (errno
!= ENOENT
))
1041 if (__collector_gethrtime () > t_timeout
)
1043 exhausted_retries
= 1;
1047 /* Oddly, if I replace this spin wait with
1048 * - a usleep() call or
1049 * - a loop on gethrtime() calls
1050 * for roughly the same length of time, retries aren't very effective. */
1052 double xdummy
= 0.5;
1053 for (ispin
= 0; ispin
< delay
; ispin
++)
1054 xdummy
= 0.5 * (xdummy
+ 1.);
1056 /* should never happen, but we check so the loop won't be optimized away */
1059 if (delay
> 100000000)
1060 delay
= 100000000; /* cap at some large, arbitrary value */
1067 __collector_util_init ()
1071 /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
1072 void *libc
= dlopen (SYS_LIBC_NAME
, RTLD_LAZY
| RTLD_NOLOAD
);
1074 libc
= dlopen (SYS_LIBC_NAME
, RTLD_NOW
| RTLD_LOCAL
);
1077 /* libcollector will subsequently abort, as all the pointers in the vector are NULL */
1079 /* SP_COLLECTOR_TRACELEVEL is not yet set, so no Tprintf */
1080 fprintf (stderr
, "__collector_util_init: dlopen(%s) failed: %s\n", SYS_LIBC_NAME
, dlerror ());
1081 return COL_ERROR_UTIL_INIT
;
1086 void *ptr
= dlsym (libc
, "fprintf");
1088 __collector_util_funcs
.fprintf
= (int(*)(FILE *, const char *, ...))ptr
;
1091 // We can't write any error messages without a libc reference
1093 fprintf (stderr
, "__collector_util_init: COLERROR_UTIL_INIT fprintf: %s\n", dlerror ());
1094 return COL_ERROR_UTIL_INIT
;
1100 ptr
= dlsym (libc
, "mmap");
1102 __collector_util_funcs
.mmap
= (void*(*)(void *, size_t, int, int, int, off_t
))ptr
;
1105 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT mmap: %s\n", dlerror ());
1106 err
= COL_ERROR_UTIL_INIT
;
1109 /* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */
1110 /* internal calls for mapping in libcollector call mmap64 */
1111 ptr
= dlsym (libc
, "mmap64");
1113 __collector_util_funcs
.mmap64_
= (void*(*)(void *, size_t, int, int, int, off_t
))ptr
;
1115 __collector_util_funcs
.mmap64_
= __collector_util_funcs
.mmap
;
1117 ptr
= dlsym (libc
, "munmap");
1119 __collector_util_funcs
.munmap
= (int(*)())ptr
;
1122 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT munmap: %s\n", dlerror ());
1123 err
= COL_ERROR_UTIL_INIT
;
1126 ptr
= dlsym (libc
, "close");
1128 __collector_util_funcs
.close
= (int(*)())ptr
;
1131 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ());
1132 err
= COL_ERROR_UTIL_INIT
;
1135 ptr
= dlsym (libc
, "open");
1137 __collector_util_funcs
.open
= (int(*)(const char *path
, int oflag
, ...))ptr
;
1140 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT open: %s\n", dlerror ());
1141 err
= COL_ERROR_UTIL_INIT
;
1144 #if ARCH(Intel) && WSIZE(32)
1145 ptr
= dlvsym (libc
, "open64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1147 __collector_util_funcs
.open_bare
= (int(*)(const char *path
, int oflag
, ...))ptr
;
1150 Tprintf (DBG_LT0
, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "open64", "GLIBC_2.2");
1151 #endif /* ARCH(Intel) && WSIZE(32) */
1152 ptr
= dlsym (libc
, "open64");
1154 __collector_util_funcs
.open_bare
= (int(*)(const char *path
, int oflag
, ...))ptr
;
1156 __collector_util_funcs
.open_bare
= __collector_util_funcs
.open
;
1157 #if ARCH(Intel) && WSIZE(32)
1159 #endif /* ARCH(Intel) && WSIZE(32) */
1161 ptr
= dlsym (libc
, "close");
1163 __collector_util_funcs
.close
= (int(*)())ptr
;
1166 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ());
1167 err
= COL_ERROR_UTIL_INIT
;
1170 ptr
= dlsym (libc
, "read");
1172 __collector_util_funcs
.read
= (ssize_t (*)())ptr
;
1175 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT read: %s\n", dlerror ());
1176 err
= COL_ERROR_UTIL_INIT
;
1179 ptr
= dlsym (libc
, "write");
1181 __collector_util_funcs
.write
= (ssize_t (*)())ptr
;
1184 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT write: %s\n", dlerror ());
1185 err
= COL_ERROR_UTIL_INIT
;
1188 #if ARCH(Intel) && WSIZE(32)
1189 ptr
= dlvsym (libc
, "pwrite", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1191 __collector_util_funcs
.pwrite
= (ssize_t (*)())ptr
;
1194 Tprintf (DBG_LT0
, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite", "GLIBC_2.2");
1195 #endif /* ARCH(Intel) && WSIZE(32) */
1196 ptr
= dlsym (libc
, "pwrite");
1198 __collector_util_funcs
.pwrite
= (ssize_t (*)())ptr
;
1201 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT pwrite: %s\n", dlerror ());
1202 err
= COL_ERROR_UTIL_INIT
;
1204 #if ARCH(Intel) && WSIZE(32)
1208 #if ARCH(Intel) && WSIZE(32)
1209 ptr
= dlvsym (libc
, "pwrite64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1211 __collector_util_funcs
.pwrite64_
= (ssize_t (*)())ptr
;
1214 Tprintf (DBG_LT0
, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite64", "GLIBC_2.2");
1215 #endif /* ARCH(Intel) && WSIZE(32) */
1216 ptr
= dlsym (libc
, "pwrite64");
1218 __collector_util_funcs
.pwrite64_
= (ssize_t (*)())ptr
;
1220 __collector_util_funcs
.pwrite64_
= __collector_util_funcs
.pwrite
;
1221 #if ARCH(Intel) && WSIZE(32)
1223 #endif /* ARCH(Intel) && WSIZE(32) */
1225 ptr
= dlsym (libc
, "lseek");
1227 __collector_util_funcs
.lseek
= (off_t (*)())ptr
;
1230 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT lseek: %s\n", dlerror ());
1231 err
= COL_ERROR_UTIL_INIT
;
1234 ptr
= dlsym (libc
, "access");
1236 __collector_util_funcs
.access
= (int(*)())ptr
;
1239 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT access: %s\n", dlerror ());
1240 err
= COL_ERROR_UTIL_INIT
;
1243 ptr
= dlsym (libc
, "mkdir");
1245 __collector_util_funcs
.mkdir
= (int(*)())ptr
;
1248 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT mkdir: %s\n", dlerror ());
1249 err
= COL_ERROR_UTIL_INIT
;
1252 ptr
= dlsym (libc
, "opendir");
1254 __collector_util_funcs
.opendir
= (DIR * (*)())ptr
;
1257 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT opendir: %s\n", dlerror ());
1258 err
= COL_ERROR_UTIL_INIT
;
1261 ptr
= dlsym (libc
, "closedir");
1263 __collector_util_funcs
.closedir
= (int(*)())ptr
;
1266 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT closedir: %s\n", dlerror ());
1267 err
= COL_ERROR_UTIL_INIT
;
1270 ptr
= dlsym (libc
, "execv");
1272 __collector_util_funcs
.execv
= (int(*)())ptr
;
1275 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT execv: %s\n", dlerror ());
1276 err
= COL_ERROR_UTIL_INIT
;
1279 ptr
= dlsym (libc
, "exit");
1281 __collector_util_funcs
.exit
= (void(*)())ptr
;
1284 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT exit: %s\n", dlerror ());
1285 err
= COL_ERROR_UTIL_INIT
;
1288 ptr
= dlsym (libc
, "vfork");
1290 __collector_util_funcs
.vfork
= (pid_t (*)())ptr
;
1293 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT vfork: %s\n", dlerror ());
1294 err
= COL_ERROR_UTIL_INIT
;
1297 ptr
= dlsym (libc
, "waitpid");
1299 __collector_util_funcs
.waitpid
= (pid_t (*)())ptr
;
1302 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT waitpid: %s\n", dlerror ());
1303 err
= COL_ERROR_UTIL_INIT
;
1306 int (*__collector_getcpuid
)() = (int(*)()) & getcpuid
;
1308 /* if sched_getcpu() not found, init our getcpuid() */
1309 sched_getcpu_ptr
= (sched_getcpu_ptr_t
) dlsym (libc
, "sched_getcpu");
1310 if (sched_getcpu_ptr
== NULL
)
1313 __collector_util_funcs
.getcpuid
= __collector_getcpuid
;
1314 __collector_util_funcs
.memset
= collector_memset
;
1316 ptr
= dlsym (libc
, "getcontext");
1318 __collector_util_funcs
.getcontext
= (int(*)())ptr
;
1321 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT getcontext: %s\n", dlerror ());
1322 err
= COL_ERROR_UTIL_INIT
;
1325 ptr
= dlsym (libc
, "malloc");
1327 __collector_util_funcs
.malloc
= (void *(*)(size_t))ptr
;
1330 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT malloc: %s\n", dlerror ());
1331 err
= COL_ERROR_UTIL_INIT
;
1334 ptr
= dlsym (libc
, "putenv");
1336 __collector_util_funcs
.putenv
= (int(*)())ptr
;
1339 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT putenv: %s\n", dlerror ());
1340 err
= COL_ERROR_UTIL_INIT
;
1343 ptr
= dlsym (libc
, "getenv");
1345 __collector_util_funcs
.getenv
= (char*(*)())ptr
;
1348 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT getenv: %s\n", dlerror ());
1349 err
= COL_ERROR_UTIL_INIT
;
1352 ptr
= dlsym (libc
, "time");
1354 __collector_util_funcs
.time
= (time_t (*)())ptr
;
1357 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT time: %s\n", dlerror ());
1358 err
= COL_ERROR_UTIL_INIT
;
1361 ptr
= dlsym (libc
, "mktime");
1363 __collector_util_funcs
.mktime
= (time_t (*)())ptr
;
1366 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT mktime: %s\n", dlerror ());
1367 err
= COL_ERROR_UTIL_INIT
;
1370 __collector_util_funcs
.strcmp
= __collector_strcmp
;
1371 __collector_util_funcs
.strncmp
= __collector_strncmp
;
1372 __collector_util_funcs
.strncpy
= __collector_strncpy
;
1373 __collector_util_funcs
.strstr
= __collector_strstr
;
1375 ptr
= dlsym (libc
, "gmtime_r");
1377 __collector_util_funcs
.gmtime_r
= (struct tm
* (*)())ptr
;
1380 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT gmtime_r: %s\n", dlerror ());
1381 err
= COL_ERROR_UTIL_INIT
;
1384 ptr
= dlsym (libc
, "strtol");
1386 __collector_util_funcs
.strtol
= (long (*)())ptr
;
1389 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strtol: %s\n", dlerror ());
1390 err
= COL_ERROR_UTIL_INIT
;
1393 ptr
= dlsym (libc
, "strtoll");
1395 __collector_util_funcs
.strtoll
= (long long (*)())ptr
;
1398 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strtoll: %s\n", dlerror ());
1399 err
= COL_ERROR_UTIL_INIT
;
1402 __collector_util_funcs
.strchr
= __collector_strchr
;
1403 __collector_util_funcs
.strrchr
= __collector_strrchr
;
1405 ptr
= dlsym (libc
, "setenv");
1407 __collector_util_funcs
.setenv
= (int(*)())ptr
;
1410 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT setenv: %s\n", dlerror ());
1411 err
= COL_ERROR_UTIL_INIT
;
1414 ptr
= dlsym (libc
, "unsetenv");
1416 __collector_util_funcs
.unsetenv
= (int(*)())ptr
;
1419 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT unsetenv: %s\n", dlerror ());
1420 err
= COL_ERROR_UTIL_INIT
;
1423 ptr
= dlsym (libc
, "atof");
1425 __collector_util_funcs
.atof
= (double (*)())ptr
;
1428 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT atof: %s\n", dlerror ());
1429 err
= COL_ERROR_UTIL_INIT
;
1432 ptr
= dlsym (libc
, "sysinfo");
1434 __collector_util_funcs
.sysinfo
= (long (*)())ptr
;
1437 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT sysinfo: %s\n", dlerror ());
1438 err
= COL_ERROR_UTIL_INIT
;
1441 ptr
= dlsym (libc
, "clearenv");
1443 __collector_util_funcs
.clearenv
= (int(*)())ptr
;
1446 /* suppress warning on S10 or earlier Solaris */
1448 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT clearenv: %s\n", dlerror ());
1449 /* err = COL_ERROR_UTIL_INIT; */
1450 /* don't treat this as fatal, so that S10 could work */
1453 if ((ptr
= dlvsym (libc
, "fopen", "GLIBC_2.17")) != NULL
)
1454 __collector_util_funcs
.fopen
= ptr
;
1455 else if ((ptr
= dlvsym (libc
, "fopen", "GLIBC_2.2.5")) != NULL
)
1456 __collector_util_funcs
.fopen
= ptr
;
1457 else if ((ptr
= dlvsym (libc
, "fopen", "GLIBC_2.1")) != NULL
)
1458 __collector_util_funcs
.fopen
= ptr
;
1459 else if ((ptr
= dlvsym (libc
, "fopen", "GLIBC_2.0")) != NULL
)
1460 __collector_util_funcs
.fopen
= ptr
;
1462 ptr
= dlsym (libc
, "fopen");
1463 if (__collector_util_funcs
.fopen
== NULL
)
1465 CALL_UTIL (fprintf
)(stderr
, "COL_ERROR_UTIL_INIT fopen: %s\n", dlerror ());
1466 err
= COL_ERROR_UTIL_INIT
;
1469 if ((ptr
= dlvsym (libc
, "popen", "GLIBC_2.17")) != NULL
)
1470 __collector_util_funcs
.popen
= ptr
;
1471 else if ((ptr
= dlvsym (libc
, "popen", "GLIBC_2.2.5")) != NULL
)
1472 __collector_util_funcs
.popen
= ptr
;
1473 else if ((ptr
= dlvsym (libc
, "popen", "GLIBC_2.1")) != NULL
)
1474 __collector_util_funcs
.popen
= ptr
;
1475 else if ((ptr
= dlvsym (libc
, "popen", "GLIBC_2.0")) != NULL
)
1476 __collector_util_funcs
.popen
= ptr
;
1478 ptr
= dlsym (libc
, "popen");
1479 if (__collector_util_funcs
.popen
== NULL
)
1481 CALL_UTIL (fprintf
)(stderr
, "COL_ERROR_UTIL_INIT popen: %s\n", dlerror ());
1482 err
= COL_ERROR_UTIL_INIT
;
1485 if ((ptr
= dlvsym (libc
, "fclose", "GLIBC_2.17")) != NULL
)
1486 __collector_util_funcs
.fclose
= ptr
;
1487 else if ((ptr
= dlvsym (libc
, "fclose", "GLIBC_2.2.5")) != NULL
)
1488 __collector_util_funcs
.fclose
= ptr
;
1489 else if ((ptr
= dlvsym (libc
, "fclose", "GLIBC_2.1")) != NULL
)
1490 __collector_util_funcs
.fclose
= ptr
;
1491 else if ((ptr
= dlvsym (libc
, "fclose", "GLIBC_2.0")) != NULL
)
1492 __collector_util_funcs
.fclose
= ptr
;
1494 ptr
= dlsym (libc
, "fclose");
1495 if (__collector_util_funcs
.fclose
== NULL
)
1497 CALL_UTIL (fprintf
)(stderr
, "COL_ERROR_UTIL_INIT fclose: %s\n", dlerror ());
1498 err
= COL_ERROR_UTIL_INIT
;
1501 ptr
= dlsym (libc
, "pclose");
1503 __collector_util_funcs
.pclose
= (int(*)())ptr
;
1506 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT pclose: %s\n", dlerror ());
1507 err
= COL_ERROR_UTIL_INIT
;
1510 ptr
= dlsym (libc
, "fgets");
1512 __collector_util_funcs
.fgets
= (char*(*)())ptr
;
1515 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT fgets: %s\n", dlerror ());
1516 err
= COL_ERROR_UTIL_INIT
;
1519 ptr
= dlsym (libc
, "sscanf");
1521 __collector_sscanfp
= (int(*)(const char *restrict s
, const char *restrict fmt
, ...))ptr
;
1524 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT sscanf: %s\n", dlerror ());
1525 err
= COL_ERROR_UTIL_INIT
;
1528 ptr
= dlsym (libc
, "snprintf");
1530 __collector_util_funcs
.snprintf
= (int(*)(char *, size_t, const char *, ...))ptr
;
1533 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT snprintf: %s\n", dlerror ());
1534 err
= COL_ERROR_UTIL_INIT
;
1537 ptr
= dlsym (libc
, "vsnprintf");
1539 __collector_util_funcs
.vsnprintf
= (int(*)())ptr
;
1542 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT vsnprintf: %s\n", dlerror ());
1543 err
= COL_ERROR_UTIL_INIT
;
1546 ptr
= dlsym (libc
, "atoi");
1548 __collector_util_funcs
.atoi
= (int(*)())ptr
;
1551 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT atoi: %s\n", dlerror ());
1552 err
= COL_ERROR_UTIL_INIT
;
1555 ptr
= dlsym (libc
, "calloc");
1557 __collector_util_funcs
.calloc
= (void*(*)())ptr
;
1560 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT calloc: %s\n", dlerror ());
1561 err
= COL_ERROR_UTIL_INIT
;
1564 ptr
= dlsym (libc
, "free");
1567 __collector_util_funcs
.free
= (void(*)())ptr
;
1571 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT free: %s\n", dlerror ());
1572 err
= COL_ERROR_UTIL_INIT
;
1575 ptr
= dlsym (libc
, "strdup");
1577 __collector_util_funcs
.libc_strdup
= (char*(*)())ptr
;
1580 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strdup: %s\n", dlerror ());
1581 err
= COL_ERROR_UTIL_INIT
;
1584 __collector_util_funcs
.strlen
= __collector_strlen
;
1585 __collector_util_funcs
.strlcat
= __collector_strlcat
;
1586 __collector_util_funcs
.strlcpy
= __collector_strlcpy
;
1588 ptr
= dlsym (libc
, "strerror");
1590 __collector_util_funcs
.strerror
= (char*(*)())ptr
;
1593 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strerror: %s\n", dlerror ());
1594 err
= COL_ERROR_UTIL_INIT
;
1596 ptr
= dlsym (libc
, "strerror_r");
1598 __collector_util_funcs
.strerror_r
= (int(*)())ptr
;
1601 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strerror_r: %s\n", dlerror ());
1602 err
= COL_ERROR_UTIL_INIT
;
1604 ptr
= dlsym (libc
, "strspn");
1606 __collector_util_funcs
.strspn
= (size_t (*)())ptr
;
1609 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strspn: %s\n", dlerror ());
1610 err
= COL_ERROR_UTIL_INIT
;
1613 ptr
= dlsym (libc
, "strtoul");
1615 __collector_util_funcs
.strtoul
= (unsigned long int(*)())ptr
;
1618 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strtoul: %s\n", dlerror ());
1619 err
= COL_ERROR_UTIL_INIT
;
1622 ptr
= dlsym (libc
, "strtoull");
1624 __collector_util_funcs
.strtoull
= (unsigned long long int(*)())ptr
;
1627 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT strtoull: %s\n", dlerror ());
1628 err
= COL_ERROR_UTIL_INIT
;
1631 ptr
= dlsym (libc
, "fcntl");
1633 __collector_util_funcs
.fcntl
= (int(*)(int, int, ...))ptr
;
1636 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT fcntl: %s\n", dlerror ());
1637 err
= COL_ERROR_UTIL_INIT
;
1640 ptr
= dlsym (libc
, "ioctl");
1642 __collector_util_funcs
.ioctl
= (int(*)(int, int, ...))ptr
;
1645 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT ioctl: %s\n", dlerror ());
1646 err
= COL_ERROR_UTIL_INIT
;
1649 ptr
= dlsym (libc
, "symlink");
1651 __collector_util_funcs
.symlink
= (int(*)(const char*, const char*))ptr
;
1654 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT symlink: %s\n", dlerror ());
1655 err
= COL_ERROR_UTIL_INIT
;
1658 ptr
= dlsym (libc
, "syscall");
1660 __collector_util_funcs
.syscall
= (int(*)(int, ...))ptr
;
1663 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT syscall: %s\n", dlerror ());
1664 err
= COL_ERROR_UTIL_INIT
;
1667 ptr
= dlsym (libc
, "sysconf");
1669 __collector_util_funcs
.sysconf
= (long(*)())ptr
;
1672 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT sysconf: %s\n", dlerror ());
1673 err
= COL_ERROR_UTIL_INIT
;
1676 ptr
= dlsym (libc
, "sigfillset");
1678 __collector_util_funcs
.sigfillset
= (int(*)())ptr
;
1681 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT sigfillset: %s\n", dlerror ());
1682 err
= COL_ERROR_UTIL_INIT
;
1685 ptr
= dlsym (libc
, "sigprocmask");
1687 __collector_util_funcs
.sigprocmask
= (int(*)())ptr
;
1690 CALL_UTIL (fprintf
)(stderr
, "collector_util_init COL_ERROR_UTIL_INIT sigprocmask: %s\n", dlerror ());
1691 err
= COL_ERROR_UTIL_INIT
;