xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/libcollector/libcol_util.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
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)
9    any later version.
10 
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.
15 
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.  */
20 
21 #include "config.h"
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <dlfcn.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/syscall.h>
32 #include <sys/mman.h>
33 #include <sys/ioctl.h>
34 
35 #include "gp-defs.h"
36 #include "collector.h"
37 #include "libcol_util.h"
38 #include "gp-experiment.h"
39 #include "Emsgnum.h"
40 #include "memmgr.h"  // __collector_allocCSize, __collector_freeCSize
41 #include "tsd.h"
42 
43 /*
44  *    This file is intended for collector's own implementation of
45  *    various routines to avoid interaction with libc and other
46  *    libraries.
47  */
48 
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, ...);
53 
54 /*
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.
65  */
66 static unsigned gettid_key = COLLECTOR_TSD_INVALID_KEY;
67 
68 void
__collector_ext_gettid_tsd_create_key()69 __collector_ext_gettid_tsd_create_key ()
70 {
71   gettid_key = __collector_tsd_create_key (sizeof (pid_t), NULL, NULL);
72 }
73 
74 pid_t
__collector_gettid()75 __collector_gettid ()
76 {
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)
81     return *tid_ptr;
82   pid_t r;
83 
84 #if ARCH(Intel)
85 #if WSIZE(32)
86 #define syscall_instr          "int $0x80"
87 #define syscall_clobber        "memory"
88 #else //WSIZE(64)
89 #define syscall_instr          "syscall"
90 #define syscall_clobber        "rcx", "r11", "memory"
91 #endif
92   __asm__ __volatile__(syscall_instr
93 		       : "=a" (r) : "0" (__NR_gettid)
94 		       : syscall_clobber);
95 #else
96   r = syscall (__NR_gettid);
97 #endif
98   if (tid_ptr)
99     *tid_ptr = r;
100   return r;
101 }
102 
103 static inline int
atomic_swap(volatile int * p,int v)104 atomic_swap (volatile int * p, int v)
105 {
106 #if ARCH(Intel)
107   int r;
108   __asm__ __volatile__("xchg %1, %2" : "=r" (r) : "m" (*p), "0" (v));
109   return r;
110 #else
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?
114    *
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
119    * two operations
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.
126    */
127   return __collector_cas_32 ((volatile uint32_t *)p, 0, v);
128 #endif
129 }
130 
131 int
__collector_mutex_lock(collector_mutex_t * lock_var)132 __collector_mutex_lock (collector_mutex_t *lock_var)
133 {
134   volatile unsigned int i = 0; /* xxxx volatile may not be honored on amd64 -x04 */
135 
136   if (!(*lock_var) && !atomic_swap (lock_var, 1))
137     return 0;
138 
139   do
140     {
141       while ((collector_mutex_t) (*lock_var) == 1)
142 	i++;
143     }
144   while (atomic_swap (lock_var, 1));
145   return 0;
146 }
147 
148 int
__collector_mutex_trylock(collector_mutex_t * lock_var)149 __collector_mutex_trylock (collector_mutex_t *lock_var)
150 {
151   if (!(*lock_var) && !atomic_swap (lock_var, 1))
152     return 0;
153   return EBUSY;
154 }
155 
156 int
__collector_mutex_unlock(collector_mutex_t * lock_var)157 __collector_mutex_unlock (collector_mutex_t *lock_var)
158 {
159   (*lock_var) = 0;
160   return 0;
161 }
162 
163 #if ARCH(SPARC)
164 void
__collector_inc_32(volatile uint32_t * mem)165 __collector_inc_32 (volatile uint32_t *mem)
166 {
167   uint32_t t1, t2;
168   __asm__ __volatile__("	ld	%2,%0 \n"
169 		       "1:	add	%0,1,%1 \n"
170 		       "	cas	%2,%0,%1 \n"
171 		       "	cmp	%0,%1 \n"
172 		       "	bne,a	1b \n"
173 		       "	mov	%1,%0 \n"
174 		       : "=&r" (t1), "=&r" (t2)
175 		       : "m" (*mem)
176 		       : "cc"
177 		       );
178 }
179 
180 void
__collector_dec_32(volatile uint32_t * mem)181 __collector_dec_32 (volatile uint32_t *mem)
182 {
183   uint32_t t1, t2;
184   __asm__ __volatile__("	ld	%2,%0 \n"
185 		       "1:	sub	%0,1,%1 \n"
186 		       "	cas	%2,%0,%1 \n"
187 		       "	cmp	%0,%1 \n"
188 		       "	bne,a	1b \n"
189 		       "	mov	%1,%0 \n"
190 		       : "=&r" (t1), "=&r" (t2)
191 		       : "m" (*mem)
192 		       : "cc"
193 		       );
194 }
195 
196 uint32_t
__collector_cas_32(volatile uint32_t * mem,uint32_t old,uint32_t new)197 __collector_cas_32 (volatile uint32_t *mem, uint32_t old, uint32_t new)
198 {
199   __asm__ __volatile__("cas [%1],%2,%0"
200 		       : "+r" (new)
201 		       : "r" (mem), "r" (old));
202   return new;
203 }
204 
205 uint32_t
__collector_subget_32(volatile uint32_t * mem,uint32_t val)206 __collector_subget_32 (volatile uint32_t *mem, uint32_t val)
207 {
208   uint32_t t1, t2;
209   __asm__ __volatile__("	ld	%2,%0 \n"
210 		       "1:	sub	%0,%3,%1 \n"
211 		       "	cas	%2,%0,%1 \n"
212 		       "	cmp	%0,%1 \n"
213 		       "	bne,a	1b \n"
214 		       "	mov	%1,%0 \n"
215 		       "	sub	%0,%3,%1 \n"
216 		       : "=&r" (t1), "=&r" (t2)
217 		       : "m" (*mem), "r" (val)
218 		       : "cc"
219 		       );
220   return t2;
221 }
222 
223 #if WSIZE(32)
224 
225 void *
__collector_cas_ptr(volatile void * mem,void * old,void * new)226 __collector_cas_ptr (volatile void *mem, void *old, void *new)
227 {
228   __asm__ __volatile__("cas [%1],%2,%0"
229 		       : "+r" (new)
230 		       : "r" (mem), "r" (old));
231   return new;
232 }
233 
234 uint64_t
__collector_cas_64p(volatile uint64_t * mem,uint64_t * old,uint64_t * new)235 __collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new)
236 {
237   uint64_t t;
238   __asm__ __volatile__("	ldx	[%2],%2 \n"
239 		       "	ldx	[%3],%3 \n"
240 		       "	casx	[%1],%2,%3 \n"
241 		       "	stx	%3,%0 \n"
242 		       : "=m" (t)
243 		       : "r" (mem), "r" (old), "r" (new)
244 		       );
245   return t;
246 }
247 
248 #elif WSIZE(64)
249 
250 void *
__collector_cas_ptr(volatile void * mem,void * old,void * new)251 __collector_cas_ptr (volatile void *mem, void *old, void *new)
252 {
253   __asm__ __volatile__("casx [%1],%2,%0"
254 		       : "+r" (new)
255 		       : "r" (mem), "r" (old));
256   return new;
257 }
258 
259 uint64_t
__collector_cas_64p(volatile uint64_t * mem,uint64_t * old,uint64_t * new)260 __collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new)
261 {
262   uint64_t t;
263   __asm__ __volatile__("	ldx	[%2],%2 \n"
264 		       "	ldx	[%3],%3 \n"
265 		       "	casx	[%1],%2,%3 \n"
266 		       "	mov	%3,%0 \n"
267 		       : "=&r" (t)
268 		       : "r" (mem), "r" (old), "r" (new)
269 		       );
270   return t;
271 }
272 
273 #endif /* WSIZE() */
274 #endif /* ARCH() */
275 
276 void *
__collector_memcpy(void * s1,const void * s2,size_t n)277 __collector_memcpy (void *s1, const void *s2, size_t n)
278 {
279   char *cp1 = (char*) s1;
280   char *cp2 = (char*) s2;
281   while (n--)
282     *cp1++ = *cp2++;
283   return s1;
284 }
285 
286 static void *
collector_memset(void * s,int c,size_t n)287 collector_memset (void *s, int c, size_t n)
288 {
289   unsigned char *s1 = s;
290   while (n--)
291     *s1++ = (unsigned char) c;
292   return s;
293 }
294 
295 int
__collector_strcmp(const char * s1,const char * s2)296 __collector_strcmp (const char *s1, const char *s2)
297 {
298   for (;;)
299     {
300       if (*s1 != *s2)
301 	return *s1 - *s2;
302       if (*s1 == 0)
303 	return 0;
304       s1++;
305       s2++;
306     }
307 }
308 
309 int
__collector_strncmp(const char * s1,const char * s2,size_t n)310 __collector_strncmp (const char *s1, const char *s2, size_t n)
311 {
312   while (n > 0)
313     {
314       if (*s1 != *s2)
315 	return *s1 - *s2;
316       if (*s1 == 0)
317 	return 0;
318       s1++;
319       s2++;
320       n--;
321     }
322   return 0;
323 }
324 
325 char *
__collector_strstr(const char * s1,const char * s2)326 __collector_strstr (const char *s1, const char *s2)
327 {
328   if (s2 == NULL || *s2 == 0)
329     return NULL;
330   size_t len = __collector_strlen (s2);
331   for (char c = *s2; *s1; s1++)
332     if (c == *s1 && __collector_strncmp (s1, s2, len) == 0)
333       return (char *) s1;
334   return NULL;
335 }
336 
337 char *
__collector_strchr(const char * str,int chr)338 __collector_strchr (const char *str, int chr)
339 {
340   if (chr == '\0')
341     return (char *) (str + __collector_strlen (str));
342   for (; *str; str++)
343     if (chr == (int) *str)
344       return (char *) str;
345   return NULL;
346 }
347 
348 char *
__collector_strrchr(const char * str,int chr)349 __collector_strrchr (const char *str, int chr)
350 {
351   const char *p = str + __collector_strlen (str);
352   for (; p - str >= 0; p--)
353     if (chr == *p)
354       return (char *) p;
355   return NULL;
356 }
357 
358 int
__collector_strStartWith(const char * s1,const char * s2)359 __collector_strStartWith (const char *s1, const char *s2)
360 {
361   size_t slen = __collector_strlen (s2);
362   return __collector_strncmp (s1, s2, slen);
363 }
364 
365 size_t
__collector_strlen(const char * s)366 __collector_strlen (const char *s)
367 {
368   int len = -1;
369   while (s[++len] != '\0')
370     ;
371   return len;
372 }
373 
374 size_t
__collector_strlcpy(char * dst,const char * src,size_t dstsize)375 __collector_strlcpy (char *dst, const char *src, size_t dstsize)
376 {
377   size_t srcsize = 0;
378   size_t n = dstsize - 1;
379   char c;
380   while ((c = *src++) != 0)
381     if (srcsize++ < n)
382       *dst++ = c;
383   if (dstsize > 0)
384     *dst = '\0';
385   return srcsize;
386 }
387 
388 size_t
__collector_strncpy(char * dst,const char * src,size_t dstsize)389 __collector_strncpy (char *dst, const char *src, size_t dstsize)
390 {
391   size_t i;
392   for (i = 0; i < dstsize; i++)
393     {
394       dst[i] = src[i];
395       if (src[i] == '\0')
396 	break;
397     }
398   return i;
399 }
400 
401 char *
__collector_strcat(char * dst,const char * src)402 __collector_strcat (char *dst, const char *src)
403 {
404   size_t sz = __collector_strlen (dst);
405   for (size_t i = 0;; i++)
406     {
407       dst[sz + i] = src[i];
408       if (src[i] == '\0')
409 	break;
410     }
411   return dst;
412 }
413 
414 size_t
__collector_strlcat(char * dst,const char * src,size_t dstsize)415 __collector_strlcat (char *dst, const char *src, size_t dstsize)
416 {
417   size_t sz = __collector_strlen (dst);
418   return sz + __collector_strlcpy (dst + sz, src, dstsize - sz);
419 }
420 
421 void *
__collector_malloc(size_t size)422 __collector_malloc (size_t size)
423 {
424   void * ptr = __collector_allocCSize (__collector_heap, size, 0);
425   return ptr;
426 }
427 
428 void *
__collector_calloc(size_t nelem,size_t elsize)429 __collector_calloc (size_t nelem, size_t elsize)
430 {
431   size_t n = nelem * elsize;
432   void * ptr = __collector_malloc (n);
433   if (NULL == ptr)
434     return NULL;
435   collector_memset (ptr, 0, n);
436   return ptr;
437 }
438 
439 char *
__collector_strdup(const char * str)440 __collector_strdup (const char * str)
441 {
442   if (NULL == str)
443     return NULL;
444   size_t size = __collector_strlen (str);
445   char * dst = (char *) __collector_malloc (size + 1);
446   if (NULL == dst)
447     return NULL;
448   __collector_strncpy (dst, str, size + 1);
449   return dst;
450 }
451 
452 #define C_FMT 1
453 #define C_STR 2
454 static char
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    /* ................ */
472 };
473 static char hex[17] = "0123456789abcdef";
474 static char HEX[17] = "0123456789ABCDEF";
475 
476 int
__collector_xml_snprintf(char * s,size_t n,const char * format,...)477 __collector_xml_snprintf (char *s, size_t n, const char *format, ...)
478 {
479   va_list args;
480   va_start (args, format);
481   int res = __collector_xml_vsnprintf (s, n, format, args);
482   va_end (args);
483   return res;
484 }
485 
486 int
__collector_xml_vsnprintf(char * s,size_t n,const char * format,va_list args)487 __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args)
488 {
489   const char *src = format;
490   char *dst = s;
491   int cnt = 0;
492   unsigned char c;
493   while ((c = *src) != 0)
494     {
495       if (c == '%')
496 	{
497 	  char numbuf[32];
498 	  int done = 0;
499 	  int jflag = 0;
500 	  int lflag = 0;
501 	  int zflag = 0;
502 	  int width = 0;
503 	  src++;
504 	  while (!done)
505 	    {
506 	      c = *src;
507 	      switch (c)
508 		{
509 		case '%':
510 		  {
511 		    if (cnt++ < n - 1)
512 		      *dst++ = '%';
513 		    if (cnt++ < n - 1)
514 		      *dst++ = hex[c / 16];
515 		    if (cnt++ < n - 1)
516 		      *dst++ = hex[c % 16];
517 		    if (cnt++ < n - 1)
518 		      *dst++ = '%';
519 		    src++;
520 		    done = 1;
521 		    break;
522 		  }
523 		case '-':
524 		  {
525 		    if (jflag != 0)
526 		      done = 1;
527 		    else
528 		      {
529 			jflag = 1;
530 			src++;
531 		      }
532 		    break;
533 		  }
534 		case 'l':
535 		  {
536 		    if (lflag != 0)
537 		      done = 1;
538 		    else
539 		      {
540 			lflag = 1;
541 			c = *++src;
542 			if (c == 'l')
543 			  {
544 			    lflag++;
545 			    src++;
546 			  }
547 		      }
548 		    break;
549 		  }
550 		case 'c':
551 		  {
552 		    unsigned char c1 = (unsigned char) va_arg (args, int);
553 		    if ((Printable[(int) c1] & C_STR) == 0)
554 		      {
555 			if (c1 == '"')
556 			  {//&quot;
557 			    if (cnt++ < n - 1)
558 			      *dst++ = '&';
559 			    if (cnt++ < n - 1)
560 			      *dst++ = 'q';
561 			    if (cnt++ < n - 1)
562 			      *dst++ = 'u';
563 			    if (cnt++ < n - 1)
564 			      *dst++ = 'o';
565 			    if (cnt++ < n - 1)
566 			      *dst++ = 't';
567 			    if (cnt++ < n - 1)
568 			      *dst++ = ';';
569 			  }
570 			else if (c1 == '\'')
571 			  {//&apos;
572 			    if (cnt++ < n - 1)
573 			      *dst++ = '&';
574 			    if (cnt++ < n - 1)
575 			      *dst++ = 'a';
576 			    if (cnt++ < n - 1)
577 			      *dst++ = 'p';
578 			    if (cnt++ < n - 1)
579 			      *dst++ = 'o';
580 			    if (cnt++ < n - 1)
581 			      *dst++ = 's';
582 			    if (cnt++ < n - 1)
583 			      *dst++ = ';';
584 			  }
585 			else if (c1 == '&')
586 			  {//&amp;
587 			    if (cnt++ < n - 1)
588 			      *dst++ = '&';
589 			    if (cnt++ < n - 1)
590 			      *dst++ = 'a';
591 			    if (cnt++ < n - 1)
592 			      *dst++ = 'm';
593 			    if (cnt++ < n - 1)
594 			      *dst++ = 'p';
595 			    if (cnt++ < n - 1)
596 			      *dst++ = ';';
597 			  }
598 			else if (c1 == '<')
599 			  {//&lt;
600 			    if (cnt++ < n - 1)
601 			      *dst++ = '&';
602 			    if (cnt++ < n - 1)
603 			      *dst++ = 'l';
604 			    if (cnt++ < n - 1)
605 			      *dst++ = 't';
606 			    if (cnt++ < n - 1)
607 			      *dst++ = ';';
608 			  }
609 			else if (c1 == '>')
610 			  {//&gt;
611 			    if (cnt++ < n - 1)
612 			      *dst++ = '&';
613 			    if (cnt++ < n - 1)
614 			      *dst++ = 'g';
615 			    if (cnt++ < n - 1)
616 			      *dst++ = 't';
617 			    if (cnt++ < n - 1)
618 			      *dst++ = ';';
619 			  }
620 			else
621 			  {
622 			    if (cnt++ < n - 1)
623 			      *dst++ = '%';
624 			    if (cnt++ < n - 1)
625 			      *dst++ = hex[c1 / 16];
626 			    if (cnt++ < n - 1)
627 			      *dst++ = hex[c1 % 16];
628 			    if (cnt++ < n - 1)
629 			      *dst++ = '%';
630 			  }
631 		      }
632 		    else if (cnt++ < n - 1)
633 		      *dst++ = c1;
634 		    src++;
635 		    done = 1;
636 		    break;
637 		  }
638 		case 's':
639 		  {
640 		    /* Strings are always left justified */
641 		    char *str = va_arg (args, char*);
642 		    if (!str)
643 		      str = "<NULL>";
644 		    unsigned char c1;
645 		    while ((c1 = *str++) != 0)
646 		      {
647 			if ((Printable[(int) c1] & C_STR) == 0)
648 			  {
649 			    if (c1 == '"')
650 			      {//&quot;
651 				if (cnt++ < n - 1)
652 				  *dst++ = '&';
653 				if (cnt++ < n - 1)
654 				  *dst++ = 'q';
655 				if (cnt++ < n - 1)
656 				  *dst++ = 'u';
657 				if (cnt++ < n - 1)
658 				  *dst++ = 'o';
659 				if (cnt++ < n - 1)
660 				  *dst++ = 't';
661 				if (cnt++ < n - 1)
662 				  *dst++ = ';';
663 			      }
664 			    else if (c1 == '\'')
665 			      {//&apos;
666 				if (cnt++ < n - 1)
667 				  *dst++ = '&';
668 				if (cnt++ < n - 1)
669 				  *dst++ = 'a';
670 				if (cnt++ < n - 1)
671 				  *dst++ = 'p';
672 				if (cnt++ < n - 1)
673 				  *dst++ = 'o';
674 				if (cnt++ < n - 1)
675 				  *dst++ = 's';
676 				if (cnt++ < n - 1)
677 				  *dst++ = ';';
678 			      }
679 			    else if (c1 == '&')
680 			      {//&amp;
681 				if (cnt++ < n - 1)
682 				  *dst++ = '&';
683 				if (cnt++ < n - 1)
684 				  *dst++ = 'a';
685 				if (cnt++ < n - 1)
686 				  *dst++ = 'm';
687 				if (cnt++ < n - 1)
688 				  *dst++ = 'p';
689 				if (cnt++ < n - 1)
690 				  *dst++ = ';';
691 			      }
692 			    else if (c1 == '<')
693 			      {//&lt;
694 				if (cnt++ < n - 1)
695 				  *dst++ = '&';
696 				if (cnt++ < n - 1)
697 				  *dst++ = 'l';
698 				if (cnt++ < n - 1)
699 				  *dst++ = 't';
700 				if (cnt++ < n - 1)
701 				  *dst++ = ';';
702 			      }
703 			    else if (c1 == '>')
704 			      {//&gt;
705 				if (cnt++ < n - 1)
706 				  *dst++ = '&';
707 				if (cnt++ < n - 1)
708 				  *dst++ = 'g';
709 				if (cnt++ < n - 1)
710 				  *dst++ = 't';
711 				if (cnt++ < n - 1)
712 				  *dst++ = ';';
713 			      }
714 			    else
715 			      {
716 				if (cnt++ < n - 1)
717 				  *dst++ = '%';
718 				if (cnt++ < n - 1)
719 				  *dst++ = hex[c1 / 16];
720 				if (cnt++ < n - 1)
721 				  *dst++ = hex[c1 % 16];
722 				if (cnt++ < n - 1)
723 				  *dst++ = '%';
724 			      }
725 			  }
726 			else if (cnt++ < n - 1)
727 			  *dst++ = c1;
728 			width--;
729 		      }
730 		    while (width > 0)
731 		      {
732 			if (cnt++ < n - 1)
733 			  *dst++ = ' ';
734 			width--;
735 		      }
736 		    src++;
737 		    done = 1;
738 		    break;
739 		  }
740 		case 'i':
741 		case 'd':
742 		case 'o':
743 		case 'p':
744 		case 'u':
745 		case 'x':
746 		case 'X':
747 		  {
748 		    int base = 10;
749 		    int uflag = 0;
750 		    int sflag = 0;
751 		    if (c == 'o')
752 		      {
753 			uflag = 1;
754 			base = 8;
755 		      }
756 		    else if (c == 'u')
757 		      uflag = 1;
758 		    else if (c == 'p')
759 		      {
760 			lflag = 1;
761 			uflag = 1;
762 			base = 16;
763 		      }
764 		    else if (c == 'x' || c == 'X')
765 		      {
766 			uflag = 1;
767 			base = 16;
768 		      }
769 		    long long argll = 0LL;
770 		    if (lflag == 0)
771 		      {
772 			if (uflag)
773 			  argll = va_arg (args, unsigned int);
774 			else
775 			  argll = va_arg (args, int);
776 		      }
777 		    else if (lflag == 1)
778 		      {
779 			if (uflag)
780 			  argll = va_arg (args, unsigned long);
781 			else
782 			  argll = va_arg (args, long);
783 		      }
784 		    else if (lflag == 2)
785 		      argll = va_arg (args, long long);
786 		    unsigned long long argllu = 0ULL;
787 		    if (uflag || argll >= 0)
788 		      argllu = argll;
789 		    else
790 		      {
791 			sflag = 1;
792 			argllu = -argll;
793 		      }
794 		    int idx = sizeof (numbuf);
795 		    do
796 		      {
797 			numbuf[--idx] = (c == 'X' ? HEX[argllu % base] : hex[argllu % base]);
798 			argllu = argllu / base;
799 		      }
800 		    while (argllu != 0)
801 		      ;
802 		    if (sflag)
803 		      {
804 			if (jflag || zflag)
805 			  {
806 			    if (cnt++ < n - 1)
807 			      *dst++ = '-';
808 			  }
809 			else
810 			  numbuf[--idx] = '-';
811 		      }
812 
813 		    if (jflag)
814 		      {
815 			while (idx < sizeof (numbuf) && width > 0)
816 			  {
817 			    if (cnt++ < n - 1)
818 			      *dst++ = numbuf[idx];
819 			    idx++;
820 			    width--;
821 			  }
822 			zflag = 0;
823 		      }
824 
825 		    while (width > sizeof (numbuf) - idx)
826 		      {
827 			if (cnt++ < n - 1)
828 			  *dst++ = zflag ? '0' : ' ';
829 			width--;
830 		      }
831 		    while (idx != sizeof (numbuf))
832 		      {
833 			if (cnt++ < n - 1)
834 			  *dst++ = numbuf[idx];
835 			idx++;
836 		      }
837 		    src++;
838 		    done = 1;
839 		    break;
840 		  }
841 		case '0':
842 		  zflag = 1;
843 		case '1': case '2': case '3': case '4': case '5':
844 		case '6': case '7': case '8': case '9':
845 		  {
846 		    while (c >= '0' && c <= '9')
847 		      {
848 			width = width * 10 + (c - '0');
849 			c = *++src;
850 		      }
851 		    break;
852 		  }
853 		default:
854 		  done = 1;
855 		  break;
856 		}
857 	    }
858 	}
859       else if ((Printable[(int) c] & C_FMT) == 0)
860 	{
861 	  if (cnt++ < n - 1)
862 	    *dst++ = '%';
863 	  if (cnt++ < n - 1)
864 	    *dst++ = hex[c / 16];
865 	  if (cnt++ < n - 1)
866 	    *dst++ = hex[c % 16];
867 	  if (cnt++ < n - 1)
868 	    *dst++ = '%';
869 	  src++;
870 	}
871       else
872 	{
873 	  if (cnt++ < n - 1)
874 	    *dst++ = c;
875 	  src++;
876 	}
877     }
878 
879   if (cnt < n - 1)
880     s[cnt] = '\0';
881   else
882     s[n - 1] = '\0';
883 
884   return cnt;
885 }
886 
887 /*
888  *    Functions to be called directly from libc.so
889  */
890 #if ARCH(Intel)    /* intel-Linux */
891 /*
892  * The CPUIDinfo/__collector_cpuid() code is old,
893  * incorrect, and complicated.  It returns the apicid
894  * rather than the processor number.
895  *
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.
899  */
900 
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;
905 
906 /* the old, low-level code */
907 static int useLeafB = 0;
908 
909 /* access to the CPUID instruction on Intel/AMD */
910 typedef struct
911 {
912   uint32_t eax, ebx, ecx, edx;
913 } CPUIDinfo;
914 
915 /**
916  * This function returns the result of the "cpuid" instruction
917  */
918 static __attribute__ ((always_inline)) inline void
__collector_cpuid(CPUIDinfo * info)919 __collector_cpuid (CPUIDinfo* info)
920 {
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));
923   info->eax = eax;
924   info->ebx = ebx;
925   info->ecx = ecx;
926   info->edx = edx;
927 }
928 
929 static void
getcpuid_init()930 getcpuid_init ()
931 {
932   CPUIDinfo info;
933   info.eax = 0; /* max input value for CPUID */
934   __collector_cpuid (&info);
935 
936   if (info.eax >= 0xb)
937     {
938       info.eax = 0xb;
939       info.ecx = 0;
940       __collector_cpuid (&info);
941       useLeafB = info.ebx != 0;
942     }
943 
944   /* indicate that we need a warning */
945   /* (need to wait until log mechanism has been initialized) */
946   need_warning = 1;
947 }
948 
949 static uint32_t
getcpuid()950 getcpuid ()
951 {
952   /* if we found sched_getcpu(), use it */
953   if (sched_getcpu_ptr)
954     return (*sched_getcpu_ptr)();
955 
956   /* otherwise, check if we need warning */
957   if (need_warning)
958     {
959       if (useLeafB)
960 	(void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">x2APIC</event>\n",
961 				      SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID);
962       else
963 	(void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">APIC</event>\n",
964 				      SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID);
965       need_warning = 0;
966     }
967 
968   /* and use the old, low-level code */
969   CPUIDinfo info;
970   if (useLeafB)
971     {
972       info.eax = 0xb;
973       info.ecx = 0;
974       __collector_cpuid (&info);
975       return info.edx; /*  x2APIC ID */
976     }
977   else
978     {
979       info.eax = 0x1;
980       info.ecx = 0;
981       __collector_cpuid (&info);
982       return info.ebx >> 24; /* APIC ID */
983     }
984 }
985 
986 #else /* sparc-Linux */
987 
988 /*
989  * EUGENE
990  * How should sched_getcpu() be prototyped?  Like this?
991  *     #include <sched.h>
992  * Or like this?
993  *     #define _GNU_SOURCE
994  *     #include <utmpx.h>
995  * Or just prototype this function explicitly without bothering with include files.
996  */
997 int sched_getcpu ();
998 
999 static int
getcpuid()1000 getcpuid ()
1001 {
1002   return sched_getcpu ();
1003 }
1004 #endif
1005 
1006 /* if ever retries time-out, we will stop allowing them */
1007 static int exhausted_retries = 0;
1008 
1009 int
__collector_open(const char * path,int oflag,...)1010 __collector_open (const char *path, int oflag, ...)
1011 {
1012   int fd;
1013   mode_t mode = 0;
1014 
1015   hrtime_t t_timeout = __collector_gethrtime () + 5 * ((hrtime_t) NANOSEC);
1016   int nretries = 0;
1017   long long delay = 100; /* start at some small, arbitrary value */
1018 
1019   /* get optional mode argument if it's expected/required */
1020   if (oflag | O_CREAT)
1021     {
1022       va_list ap;
1023       va_start (ap, oflag);
1024       mode = (mode_t) va_arg (ap, mode_t);
1025       va_end (ap);
1026     }
1027 
1028   /* retry upon failure */
1029   while ((fd = CALL_UTIL (open_bare)(path, oflag, mode)) < 0)
1030     {
1031       if (exhausted_retries)
1032 	break;
1033 
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.
1038        */
1039       if ((errno != EMFILE) && (errno != ENOENT))
1040 	break;
1041       if (__collector_gethrtime () > t_timeout)
1042 	{
1043 	  exhausted_retries = 1;
1044 	  break;
1045 	}
1046 
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. */
1051       int ispin;
1052       double xdummy = 0.5;
1053       for (ispin = 0; ispin < delay; ispin++)
1054 	xdummy = 0.5 * (xdummy + 1.);
1055       if (xdummy < 0.1)
1056 	/* should never happen, but we check so the loop won't be optimized away */
1057 	break;
1058       delay *= 2;
1059       if (delay > 100000000)
1060 	delay = 100000000; /* cap at some large, arbitrary value */
1061       nretries++;
1062     }
1063   return fd;
1064 }
1065 
1066 int
__collector_util_init()1067 __collector_util_init ()
1068 {
1069   int oldos = 0;
1070 
1071   /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
1072   void *libc = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
1073   if (libc == NULL)
1074     libc = dlopen (SYS_LIBC_NAME, RTLD_NOW | RTLD_LOCAL);
1075   if (libc == NULL)
1076     {
1077       /* libcollector will subsequently abort, as all the pointers in the vector are NULL */
1078 #if 0
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;
1082 #endif
1083       abort ();
1084     }
1085 
1086   void *ptr = dlsym (libc, "fprintf");
1087   if (ptr)
1088     __collector_util_funcs.fprintf = (int(*)(FILE *, const char *, ...))ptr;
1089   else
1090     {
1091       // We can't write any error messages without a libc reference
1092 #if 0
1093       fprintf (stderr, "__collector_util_init: COLERROR_UTIL_INIT fprintf: %s\n", dlerror ());
1094       return COL_ERROR_UTIL_INIT;
1095 #endif
1096       abort ();
1097     }
1098   int err = 0;
1099 
1100   ptr = dlsym (libc, "mmap");
1101   if (ptr)
1102     __collector_util_funcs.mmap = (void*(*)(void *, size_t, int, int, int, off_t))ptr;
1103   else
1104     {
1105       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mmap: %s\n", dlerror ());
1106       err = COL_ERROR_UTIL_INIT;
1107     }
1108 
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");
1112   if (ptr)
1113     __collector_util_funcs.mmap64_ = (void*(*)(void *, size_t, int, int, int, off_t))ptr;
1114   else
1115     __collector_util_funcs.mmap64_ = __collector_util_funcs.mmap;
1116 
1117   ptr = dlsym (libc, "munmap");
1118   if (ptr)
1119     __collector_util_funcs.munmap = (int(*)())ptr;
1120   else
1121     {
1122       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT munmap: %s\n", dlerror ());
1123       err = COL_ERROR_UTIL_INIT;
1124     }
1125 
1126   ptr = dlsym (libc, "close");
1127   if (ptr)
1128     __collector_util_funcs.close = (int(*)())ptr;
1129   else
1130     {
1131       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ());
1132       err = COL_ERROR_UTIL_INIT;
1133     }
1134 
1135   ptr = dlsym (libc, "open");
1136   if (ptr)
1137     __collector_util_funcs.open = (int(*)(const char *path, int oflag, ...))ptr;
1138   else
1139     {
1140       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT open: %s\n", dlerror ());
1141       err = COL_ERROR_UTIL_INIT;
1142     }
1143 
1144 #if ARCH(Intel) && WSIZE(32)
1145   ptr = dlvsym (libc, "open64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1146   if (ptr)
1147     __collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr;
1148   else
1149     {
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");
1153       if (ptr)
1154 	__collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr;
1155       else
1156 	__collector_util_funcs.open_bare = __collector_util_funcs.open;
1157 #if ARCH(Intel) && WSIZE(32)
1158     }
1159 #endif /* ARCH(Intel) && WSIZE(32) */
1160 
1161   ptr = dlsym (libc, "close");
1162   if (ptr)
1163     __collector_util_funcs.close = (int(*)())ptr;
1164   else
1165     {
1166       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ());
1167       err = COL_ERROR_UTIL_INIT;
1168     }
1169 
1170   ptr = dlsym (libc, "read");
1171   if (ptr)
1172     __collector_util_funcs.read = (ssize_t (*)())ptr;
1173   else
1174     {
1175       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT read: %s\n", dlerror ());
1176       err = COL_ERROR_UTIL_INIT;
1177     }
1178 
1179   ptr = dlsym (libc, "write");
1180   if (ptr)
1181     __collector_util_funcs.write = (ssize_t (*)())ptr;
1182   else
1183     {
1184       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT write: %s\n", dlerror ());
1185       err = COL_ERROR_UTIL_INIT;
1186     }
1187 
1188 #if ARCH(Intel) && WSIZE(32)
1189   ptr = dlvsym (libc, "pwrite", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1190   if (ptr)
1191     __collector_util_funcs.pwrite = (ssize_t (*)())ptr;
1192   else
1193     {
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");
1197       if (ptr)
1198 	__collector_util_funcs.pwrite = (ssize_t (*)())ptr;
1199       else
1200 	{
1201 	  CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pwrite: %s\n", dlerror ());
1202 	  err = COL_ERROR_UTIL_INIT;
1203 	}
1204 #if ARCH(Intel) && WSIZE(32)
1205     }
1206 #endif
1207 
1208 #if ARCH(Intel) && WSIZE(32)
1209   ptr = dlvsym (libc, "pwrite64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0
1210   if (ptr)
1211     __collector_util_funcs.pwrite64_ = (ssize_t (*)())ptr;
1212   else
1213     {
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");
1217       if (ptr)
1218 	__collector_util_funcs.pwrite64_ = (ssize_t (*)())ptr;
1219       else
1220 	__collector_util_funcs.pwrite64_ = __collector_util_funcs.pwrite;
1221 #if ARCH(Intel) && WSIZE(32)
1222     }
1223 #endif /* ARCH(Intel) && WSIZE(32) */
1224 
1225   ptr = dlsym (libc, "lseek");
1226   if (ptr)
1227     __collector_util_funcs.lseek = (off_t (*)())ptr;
1228   else
1229     {
1230       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT lseek: %s\n", dlerror ());
1231       err = COL_ERROR_UTIL_INIT;
1232     }
1233 
1234   ptr = dlsym (libc, "access");
1235   if (ptr)
1236     __collector_util_funcs.access = (int(*)())ptr;
1237   else
1238     {
1239       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT access: %s\n", dlerror ());
1240       err = COL_ERROR_UTIL_INIT;
1241     }
1242 
1243   ptr = dlsym (libc, "mkdir");
1244   if (ptr)
1245     __collector_util_funcs.mkdir = (int(*)())ptr;
1246   else
1247     {
1248       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mkdir: %s\n", dlerror ());
1249       err = COL_ERROR_UTIL_INIT;
1250     }
1251 
1252   ptr = dlsym (libc, "opendir");
1253   if (ptr)
1254     __collector_util_funcs.opendir = (DIR * (*)())ptr;
1255   else
1256     {
1257       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT opendir: %s\n", dlerror ());
1258       err = COL_ERROR_UTIL_INIT;
1259     }
1260 
1261   ptr = dlsym (libc, "closedir");
1262   if (ptr)
1263     __collector_util_funcs.closedir = (int(*)())ptr;
1264   else
1265     {
1266       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT closedir: %s\n", dlerror ());
1267       err = COL_ERROR_UTIL_INIT;
1268     }
1269 
1270   ptr = dlsym (libc, "execv");
1271   if (ptr)
1272     __collector_util_funcs.execv = (int(*)())ptr;
1273   else
1274     {
1275       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT execv: %s\n", dlerror ());
1276       err = COL_ERROR_UTIL_INIT;
1277     }
1278 
1279   ptr = dlsym (libc, "exit");
1280   if (ptr)
1281     __collector_util_funcs.exit = (void(*)())ptr;
1282   else
1283     {
1284       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT exit: %s\n", dlerror ());
1285       err = COL_ERROR_UTIL_INIT;
1286     }
1287 
1288   ptr = dlsym (libc, "vfork");
1289   if (ptr)
1290     __collector_util_funcs.vfork = (pid_t (*)())ptr;
1291   else
1292     {
1293       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vfork: %s\n", dlerror ());
1294       err = COL_ERROR_UTIL_INIT;
1295     }
1296 
1297   ptr = dlsym (libc, "waitpid");
1298   if (ptr)
1299     __collector_util_funcs.waitpid = (pid_t (*)())ptr;
1300   else
1301     {
1302       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT waitpid: %s\n", dlerror ());
1303       err = COL_ERROR_UTIL_INIT;
1304     }
1305 
1306   int (*__collector_getcpuid)() = (int(*)()) & getcpuid;
1307 #if ARCH(Intel)
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)
1311     getcpuid_init ();
1312 #endif
1313   __collector_util_funcs.getcpuid = __collector_getcpuid;
1314   __collector_util_funcs.memset = collector_memset;
1315 
1316   ptr = dlsym (libc, "getcontext");
1317   if (ptr)
1318     __collector_util_funcs.getcontext = (int(*)())ptr;
1319   else
1320     {
1321       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT getcontext: %s\n", dlerror ());
1322       err = COL_ERROR_UTIL_INIT;
1323     }
1324 
1325   ptr = dlsym (libc, "malloc");
1326   if (ptr)
1327     __collector_util_funcs.malloc = (void *(*)(size_t))ptr;
1328   else
1329     {
1330       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT malloc: %s\n", dlerror ());
1331       err = COL_ERROR_UTIL_INIT;
1332     }
1333 
1334   ptr = dlsym (libc, "putenv");
1335   if (ptr)
1336     __collector_util_funcs.putenv = (int(*)())ptr;
1337   else
1338     {
1339       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT putenv: %s\n", dlerror ());
1340       err = COL_ERROR_UTIL_INIT;
1341     }
1342 
1343   ptr = dlsym (libc, "getenv");
1344   if (ptr)
1345     __collector_util_funcs.getenv = (char*(*)())ptr;
1346   else
1347     {
1348       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT getenv: %s\n", dlerror ());
1349       err = COL_ERROR_UTIL_INIT;
1350     }
1351 
1352   ptr = dlsym (libc, "time");
1353   if (ptr)
1354     __collector_util_funcs.time = (time_t (*)())ptr;
1355   else
1356     {
1357       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT time: %s\n", dlerror ());
1358       err = COL_ERROR_UTIL_INIT;
1359     }
1360 
1361   ptr = dlsym (libc, "mktime");
1362   if (ptr)
1363     __collector_util_funcs.mktime = (time_t (*)())ptr;
1364   else
1365     {
1366       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mktime: %s\n", dlerror ());
1367       err = COL_ERROR_UTIL_INIT;
1368     }
1369 
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;
1374 
1375   ptr = dlsym (libc, "gmtime_r");
1376   if (ptr)
1377     __collector_util_funcs.gmtime_r = (struct tm * (*)())ptr;
1378   else
1379     {
1380       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT gmtime_r: %s\n", dlerror ());
1381       err = COL_ERROR_UTIL_INIT;
1382     }
1383 
1384   ptr = dlsym (libc, "strtol");
1385   if (ptr)
1386     __collector_util_funcs.strtol = (long (*)())ptr;
1387   else
1388     {
1389       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtol: %s\n", dlerror ());
1390       err = COL_ERROR_UTIL_INIT;
1391     }
1392 
1393   ptr = dlsym (libc, "strtoll");
1394   if (ptr)
1395     __collector_util_funcs.strtoll = (long long (*)())ptr;
1396   else
1397     {
1398       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoll: %s\n", dlerror ());
1399       err = COL_ERROR_UTIL_INIT;
1400     }
1401 
1402   __collector_util_funcs.strchr = __collector_strchr;
1403   __collector_util_funcs.strrchr = __collector_strrchr;
1404 
1405   ptr = dlsym (libc, "setenv");
1406   if (ptr)
1407     __collector_util_funcs.setenv = (int(*)())ptr;
1408   else
1409     {
1410       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT setenv: %s\n", dlerror ());
1411       err = COL_ERROR_UTIL_INIT;
1412     }
1413 
1414   ptr = dlsym (libc, "unsetenv");
1415   if (ptr)
1416     __collector_util_funcs.unsetenv = (int(*)())ptr;
1417   else
1418     {
1419       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT unsetenv: %s\n", dlerror ());
1420       err = COL_ERROR_UTIL_INIT;
1421     }
1422 
1423   ptr = dlsym (libc, "atof");
1424   if (ptr)
1425     __collector_util_funcs.atof = (double (*)())ptr;
1426   else
1427     {
1428       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atof: %s\n", dlerror ());
1429       err = COL_ERROR_UTIL_INIT;
1430     }
1431 
1432   ptr = dlsym (libc, "sysinfo");
1433   if (ptr)
1434     __collector_util_funcs.sysinfo = (long (*)())ptr;
1435   else
1436     {
1437       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysinfo: %s\n", dlerror ());
1438       err = COL_ERROR_UTIL_INIT;
1439     }
1440 
1441   ptr = dlsym (libc, "clearenv");
1442   if (ptr)
1443     __collector_util_funcs.clearenv = (int(*)())ptr;
1444   else
1445     {
1446       /* suppress warning on S10 or earlier Solaris */
1447       if (oldos == 0)
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 */
1451     }
1452 
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;
1461   else
1462     ptr = dlsym (libc, "fopen");
1463   if (__collector_util_funcs.fopen == NULL)
1464     {
1465       CALL_UTIL (fprintf)(stderr, "COL_ERROR_UTIL_INIT fopen: %s\n", dlerror ());
1466       err = COL_ERROR_UTIL_INIT;
1467     }
1468 
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;
1477   else
1478     ptr = dlsym (libc, "popen");
1479   if (__collector_util_funcs.popen == NULL)
1480     {
1481       CALL_UTIL (fprintf)(stderr, "COL_ERROR_UTIL_INIT popen: %s\n", dlerror ());
1482       err = COL_ERROR_UTIL_INIT;
1483     }
1484 
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;
1493   else
1494     ptr = dlsym (libc, "fclose");
1495   if (__collector_util_funcs.fclose == NULL)
1496     {
1497       CALL_UTIL (fprintf)(stderr, "COL_ERROR_UTIL_INIT fclose: %s\n", dlerror ());
1498       err = COL_ERROR_UTIL_INIT;
1499     }
1500 
1501   ptr = dlsym (libc, "pclose");
1502   if (ptr)
1503     __collector_util_funcs.pclose = (int(*)())ptr;
1504   else
1505     {
1506       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pclose: %s\n", dlerror ());
1507       err = COL_ERROR_UTIL_INIT;
1508     }
1509 
1510   ptr = dlsym (libc, "fgets");
1511   if (ptr)
1512     __collector_util_funcs.fgets = (char*(*)())ptr;
1513   else
1514     {
1515       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fgets: %s\n", dlerror ());
1516       err = COL_ERROR_UTIL_INIT;
1517     }
1518 
1519   ptr = dlsym (libc, "sscanf");
1520   if (ptr)
1521     __collector_sscanfp = (int(*)(const char *restrict s, const char *restrict fmt, ...))ptr;
1522   else
1523     {
1524       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sscanf: %s\n", dlerror ());
1525       err = COL_ERROR_UTIL_INIT;
1526     }
1527 
1528   ptr = dlsym (libc, "snprintf");
1529   if (ptr)
1530     __collector_util_funcs.snprintf = (int(*)(char *, size_t, const char *, ...))ptr;
1531   else
1532     {
1533       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT snprintf: %s\n", dlerror ());
1534       err = COL_ERROR_UTIL_INIT;
1535     }
1536 
1537   ptr = dlsym (libc, "vsnprintf");
1538   if (ptr)
1539     __collector_util_funcs.vsnprintf = (int(*)())ptr;
1540   else
1541     {
1542       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vsnprintf: %s\n", dlerror ());
1543       err = COL_ERROR_UTIL_INIT;
1544     }
1545 
1546   ptr = dlsym (libc, "atoi");
1547   if (ptr)
1548     __collector_util_funcs.atoi = (int(*)())ptr;
1549   else
1550     {
1551       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atoi: %s\n", dlerror ());
1552       err = COL_ERROR_UTIL_INIT;
1553     }
1554 
1555   ptr = dlsym (libc, "calloc");
1556   if (ptr)
1557     __collector_util_funcs.calloc = (void*(*)())ptr;
1558   else
1559     {
1560       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT calloc: %s\n", dlerror ());
1561       err = COL_ERROR_UTIL_INIT;
1562     }
1563 
1564   ptr = dlsym (libc, "free");
1565   if (ptr)
1566     {
1567       __collector_util_funcs.free = (void(*)())ptr;
1568     }
1569   else
1570     {
1571       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT free: %s\n", dlerror ());
1572       err = COL_ERROR_UTIL_INIT;
1573     }
1574 
1575   ptr = dlsym (libc, "strdup");
1576   if (ptr)
1577     __collector_util_funcs.libc_strdup = (char*(*)())ptr;
1578   else
1579     {
1580       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strdup: %s\n", dlerror ());
1581       err = COL_ERROR_UTIL_INIT;
1582     }
1583 
1584   __collector_util_funcs.strlen = __collector_strlen;
1585   __collector_util_funcs.strlcat = __collector_strlcat;
1586   __collector_util_funcs.strlcpy = __collector_strlcpy;
1587 
1588   ptr = dlsym (libc, "strerror");
1589   if (ptr)
1590     __collector_util_funcs.strerror = (char*(*)())ptr;
1591   else
1592     {
1593       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror: %s\n", dlerror ());
1594       err = COL_ERROR_UTIL_INIT;
1595     }
1596   ptr = dlsym (libc, "strerror_r");
1597   if (ptr)
1598     __collector_util_funcs.strerror_r = (int(*)())ptr;
1599   else
1600     {
1601       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror_r: %s\n", dlerror ());
1602       err = COL_ERROR_UTIL_INIT;
1603     }
1604   ptr = dlsym (libc, "strspn");
1605   if (ptr)
1606     __collector_util_funcs.strspn = (size_t (*)())ptr;
1607   else
1608     {
1609       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strspn: %s\n", dlerror ());
1610       err = COL_ERROR_UTIL_INIT;
1611     }
1612 
1613   ptr = dlsym (libc, "strtoul");
1614   if (ptr)
1615     __collector_util_funcs.strtoul = (unsigned long int(*)())ptr;
1616   else
1617     {
1618       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoul: %s\n", dlerror ());
1619       err = COL_ERROR_UTIL_INIT;
1620     }
1621 
1622   ptr = dlsym (libc, "strtoull");
1623   if (ptr)
1624     __collector_util_funcs.strtoull = (unsigned long long int(*)())ptr;
1625   else
1626     {
1627       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoull: %s\n", dlerror ());
1628       err = COL_ERROR_UTIL_INIT;
1629     }
1630 
1631   ptr = dlsym (libc, "fcntl");
1632   if (ptr)
1633     __collector_util_funcs.fcntl = (int(*)(int, int, ...))ptr;
1634   else
1635     {
1636       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fcntl: %s\n", dlerror ());
1637       err = COL_ERROR_UTIL_INIT;
1638     }
1639 
1640   ptr = dlsym (libc, "ioctl");
1641   if (ptr)
1642     __collector_util_funcs.ioctl = (int(*)(int, int, ...))ptr;
1643   else
1644     {
1645       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT ioctl: %s\n", dlerror ());
1646       err = COL_ERROR_UTIL_INIT;
1647     }
1648 
1649   ptr = dlsym (libc, "symlink");
1650   if (ptr)
1651     __collector_util_funcs.symlink = (int(*)(const char*, const char*))ptr;
1652   else
1653     {
1654       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT symlink: %s\n", dlerror ());
1655       err = COL_ERROR_UTIL_INIT;
1656     }
1657 
1658   ptr = dlsym (libc, "syscall");
1659   if (ptr)
1660     __collector_util_funcs.syscall = (int(*)(int, ...))ptr;
1661   else
1662     {
1663       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT syscall: %s\n", dlerror ());
1664       err = COL_ERROR_UTIL_INIT;
1665     }
1666 
1667   ptr = dlsym (libc, "sysconf");
1668   if (ptr)
1669     __collector_util_funcs.sysconf = (long(*)())ptr;
1670   else
1671     {
1672       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysconf: %s\n", dlerror ());
1673       err = COL_ERROR_UTIL_INIT;
1674     }
1675 
1676   ptr = dlsym (libc, "sigfillset");
1677   if (ptr)
1678     __collector_util_funcs.sigfillset = (int(*)())ptr;
1679   else
1680     {
1681       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigfillset: %s\n", dlerror ());
1682       err = COL_ERROR_UTIL_INIT;
1683     }
1684 
1685   ptr = dlsym (libc, "sigprocmask");
1686   if (ptr)
1687     __collector_util_funcs.sigprocmask = (int(*)())ptr;
1688   else
1689     {
1690       CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigprocmask: %s\n", dlerror ());
1691       err = COL_ERROR_UTIL_INIT;
1692     }
1693 
1694   return err;
1695 }
1696