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