xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/libcollector/libcol_util.h (revision 528ce0b18ee40383f14928382d06afd754b01561)
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 #ifndef _LIBCOL_UTIL_H
22 #define _LIBCOL_UTIL_H
23 
24 #include <stdarg.h>
25 #include <pthread.h>
26 #include <signal.h>
27 
28 // LIBCOLLECTOR NOT I18N
29 #define NTXT(x) x
30 #define STXT(x) x
31 
32 extern int __collector_tracelevel;
33 
34 /* Initialization function */
35 extern	int  __collector_util_init();
36 extern  void __collector_libkstat_funcs_init();
37 extern  void __collector_libscf_funcs_init();
38 
39 /* -------  functions from libcol_util.c ----------------- */
40 extern void * __collector_memcpy (void *s1, const void *s2, size_t n);
41 extern int (*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...);
42 extern char * __collector_strcat (char *s1, const char *s2);
43 extern char * __collector_strchr (const char *s1, int chr);
44 extern size_t __collector_strlcpy (char *dst, const char *src, size_t dstsize);
45 extern char* __collector_strrchr (const char *str, int chr);
46 extern size_t __collector_strlen (const char *s);
47 extern size_t __collector_strlcat (char *dst, const char *src, size_t dstsize);
48 extern char* __collector_strchr (const char *str, int chr);
49 extern int __collector_strcmp (const char *s1, const char *s2);
50 extern int __collector_strncmp (const char *s1, const char *s2, size_t n);
51 extern char * __collector_strstr (const char *s1, const char *s2);
52 extern size_t __collector_strncpy (char *dst, const char *src, size_t dstsize);
53 extern size_t __collector_strncat (char *dst, const char *src, size_t dstsize);
54 extern void * __collector_malloc (size_t size);
55 extern void * __collector_calloc (size_t nelem, size_t elsize);
56 extern char * __collector_strdup (const char * str);
57 extern int __collector_strStartWith (const char *s1, const char *s2);
58 extern int __collector_xml_snprintf (char *s, size_t n, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
59 extern int __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args);
60 
61 /* -------  collector_thread ----------------- */
62 pid_t __collector_gettid ();
63 extern void __collector_ext_gettid_tsd_create_key ();
64 #define collector_thread_t pthread_t            // not using pid_t, since tid is defined as pthread_t in package structures, and other codes assume this type
65 #define statvfs_t  struct statvfs
66 #define __collector_lwp_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
67 #define __collector_thr_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
68 
69 /* -------  collector_mutex ----------------- */
70 /*
71  * mutex_init is defined in libthread. If we don't want to interact
72  * with libthread we should use memset to initialize mutexes
73  */
74 
75 typedef volatile int collector_mutex_t;
76 #define  COLLECTOR_MUTEX_INITIALIZER 0
77 extern int __collector_mutex_lock (collector_mutex_t *mp);
78 extern int __collector_mutex_unlock (collector_mutex_t *mp);
79 extern int __collector_mutex_trylock (collector_mutex_t *mp);
80 
81 #define __collector_mutex_init(xx) \
82   do { collector_mutex_t tmp=COLLECTOR_MUTEX_INITIALIZER; *(xx)=tmp; } while(0)
83 
84 void __collector_sample (char *name);
85 void __collector_terminate_expt ();
86 void __collector_pause ();
87 void __collector_pause_m ();
88 void __collector_resume ();
89 
90 struct DT_lineno;
91 
92 typedef enum
93 {
94   DFUNC_API = 1, /* dynamic function declared with API */
95   DFUNC_JAVA, /* dynamically compiled java method */
96   DFUNC_KERNEL /* dynamic code mapped by the kernel (Linux) */
97 } dfunc_mode_t;
98 
99 extern void __collector_int_func_load (dfunc_mode_t mode, char *name,
100 				       char *sourcename, void *vaddr,
101 				       int size, int lntsize,
102 				       struct DT_lineno *lntable);
103 extern void __collector_int_func_unload (dfunc_mode_t mode, void *vaddr);
104 
105 extern int __collector_sigaction (int sig, const struct sigaction *nact,
106 				  struct sigaction *oact);
107 extern void __collector_SIGDFL_handler (int sig);
108 extern int __collector_ext_itimer_set (int period);
109 
110 #if ARCH(Intel)
111 /* Atomic functions on x86/x64 */
112 
113 /**
114  * This function enables the inrementing (by one) of the value stored in target
115  * to occur in an atomic manner.
116  */
117 static __attribute__ ((always_inline)) inline void
118 __collector_inc_32 (uint32_t *ptr)
119 {
120   __asm__ __volatile__("lock; incl %0"
121 		       : // "=m" (*ptr)    // output
122 		       : "m" (*ptr)); // input
123 }
124 
125 /**
126  * This function enables the decrementing (by one) of the value stored in target
127  * to occur in an atomic manner.
128  */
129 static __attribute__ ((always_inline)) inline void
130 __collector_dec_32 (volatile uint32_t *ptr)
131 {
132   __asm__ __volatile__("lock; decl %0"
133 		       : // "=m" (*ptr)    // output
134 		       : "m" (*ptr)); // input
135 }
136 
137 /**
138  * This function subtrackts the value "off" of the value stored in target
139  * to occur in an atomic manner, and returns new value stored in target.
140  */
141 static __attribute__ ((always_inline)) inline uint32_t
142 __collector_subget_32 (uint32_t *ptr, uint32_t off)
143 {
144   uint32_t r;
145   uint32_t offset = off;
146   __asm__ __volatile__("movl %2, %0; negl %0; lock; xaddl %0, %1"
147 		       : "=r" (r), "=m" (*ptr) /* output */
148 		       : "a" (off), "r" (*ptr) /* input */
149 		       );
150   return (r - offset);
151 }
152 
153 /**
154  * This function returns the value of the stack pointer register
155  */
156 static __attribute__ ((always_inline)) inline void *
157 __collector_getsp ()
158 {
159   void *r;
160 #if WSIZE(32) || defined(__ILP32__)
161   __asm__ __volatile__("movl %%esp, %0"
162 #else
163   __asm__ __volatile__("movq %%rsp, %0"
164 #endif
165 	  : "=r" (r)); // output
166   return r;
167 }
168 
169 /**
170  * This function returns the value of the frame pointer register
171  */
172 static __attribute__ ((always_inline)) inline void *
173 __collector_getfp ()
174 {
175   void *r;
176 #if WSIZE(32) || defined(__ILP32__)
177   __asm__ __volatile__("movl %%ebp, %0"
178 #else
179   __asm__ __volatile__("movq %%rbp, %0"
180 #endif
181 	  : "=r" (r)); // output
182   return r;
183 }
184 
185 /**
186  * This function returns the value of the processor counter register
187  */
188 static __attribute__ ((always_inline)) inline void *
189 __collector_getpc ()
190 {
191   void *r;
192 #if defined(__x86_64)
193   __asm__ __volatile__("lea (%%rip), %0" : "=r" (r));
194 #else
195   __asm__ __volatile__("call  1f \n"
196 		       "1: popl  %0" : "=r" (r));
197 #endif
198   return r;
199 }
200 
201 /**
202  * This function enables a compare and swap operation to occur atomically.
203  * The 32-bit value stored in target is compared with "old". If these values
204  * are equal, the value stored in target is replaced with "new". The old
205  * 32-bit value stored in target is returned by the function whether or not
206  * the replacement occurred.
207  */
208 static __attribute__ ((always_inline)) inline uint32_t
209 __collector_cas_32 (volatile uint32_t *pdata, uint32_t old, uint32_t new)
210 {
211   uint32_t r;
212   __asm__ __volatile__("lock; cmpxchgl %2, %1"
213 		       : "=a" (r), "=m" (*pdata) : "r" (new),
214 		       "a" (old), "m" (*pdata));
215   return r;
216 }
217 /**
218  * This function enables a compare and swap operation to occur atomically.
219  * The 64-bit value stored in target is compared with "old". If these values
220  * are equal, the value stored in target is replaced with "new". The old
221  * 64-bit value stored in target is returned by the function whether or not
222  * the replacement occurred.
223  */
224 static __attribute__ ((always_inline)) inline uint64_t
225 __collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t * new)
226 {
227   uint64_t r;
228 #if WSIZE(32)
229   uint32_t old1 = (uint32_t) (*old & 0xFFFFFFFFL);
230   uint32_t old2 = (uint32_t) ((*old >> 32) & 0xFFFFFFFFL);
231   uint32_t new1 = (uint32_t) (*new & 0xFFFFFFFFL);
232   uint32_t new2 = (uint32_t) ((*new >> 32) & 0xFFFFFFFFL);
233   uint32_t res1 = 0;
234   uint32_t res2 = 0;
235   __asm__ __volatile__(
236       "movl %3, %%esi; lock; cmpxchg8b (%%esi); movl %%edx, %2; movl %%eax, %1"
237       : "=m" (r), "=m" (res1), "=m" (res2) /* output */
238       : "m" (mem), "a" (old1), "d" (old2), "b" (new1), "c" (new2) /* input */
239       : "memory", "cc", "esi" //, "edx", "ecx", "ebx", "eax" /* clobbered register */
240 		       );
241   r = (((uint64_t) res2) << 32) | ((uint64_t) res1);
242 #else
243   __asm__ __volatile__( "lock; cmpxchgq %2, %1"
244 		       : "=a" (r), "=m" (*mem) /* output */
245 		       : "r" (*new), "a" (*old), "m" (*mem) /* input */
246 		       : "%rcx", "rdx" /* clobbered register */
247 		       );
248 #endif
249   return r;
250 }
251 /**
252  * This function enables a compare and swap operation to occur atomically.
253  * The 32-/64-bit value stored in target is compared with "cmp". If these values
254  * are equal, the value stored in target is replaced with "new".
255  * The old value stored in target is returned by the function whether or not
256  * the replacement occurred.
257  */
258 static __attribute__ ((always_inline)) inline void *
259 __collector_cas_ptr (void *mem, void *cmp, void *new)
260 {
261   void *r;
262 #if WSIZE(32) || defined(__ILP32__)
263   r = (void *) __collector_cas_32 ((volatile uint32_t *)mem, (uint32_t) cmp, (uint32_t)new);
264 #else
265   __asm__ __volatile__("lock; cmpxchgq %2, (%1)"
266 		       : "=a" (r), "=b" (mem) /* output */
267 		       : "r" (new), "a" (cmp), "b" (mem) /* input */
268 		       );
269 #endif
270   return r;
271 }
272 
273 #elif ARCH(Aarch64)
274 static __attribute__ ((always_inline)) inline uint32_t
275 __collector_inc_32 (volatile uint32_t *ptr)
276 {
277   return __sync_add_and_fetch (ptr, 1);
278 }
279 
280 static __attribute__ ((always_inline)) inline uint32_t
281 __collector_dec_32 (volatile uint32_t *ptr)
282 {
283   return __sync_sub_and_fetch (ptr, 1);
284 }
285 
286 static __attribute__ ((always_inline)) inline uint32_t
287 __collector_subget_32 (volatile uint32_t *ptr, uint32_t off)
288 {
289   return __sync_sub_and_fetch (ptr, off);
290 }
291 
292 static __attribute__ ((always_inline)) inline uint32_t
293 __collector_cas_32 (volatile uint32_t *ptr, uint32_t old, uint32_t new)
294 {
295   return __sync_val_compare_and_swap (ptr, old, new);
296 }
297 
298 static __attribute__ ((always_inline)) inline uint64_t
299 __collector_cas_64p (volatile uint64_t *ptr, uint64_t *old, uint64_t * new)
300 {
301   return __sync_val_compare_and_swap (ptr, *old, *new);
302 }
303 
304 static __attribute__ ((always_inline)) inline void *
305 __collector_cas_ptr (void *ptr, void *old, void *new)
306 {
307   return (void *) __sync_val_compare_and_swap ((unsigned long *) ptr, (unsigned long) old, (unsigned long) new);
308 }
309 
310 #else
311 extern void __collector_flushw (); /* defined for SPARC only */
312 extern void* __collector_getpc ();
313 extern void* __collector_getsp ();
314 extern void* __collector_getfp ();
315 extern void __collector_inc_32 (volatile uint32_t *);
316 extern void __collector_dec_32 (volatile uint32_t *);
317 extern void* __collector_cas_ptr (volatile void *, void *, void *);
318 extern uint32_t __collector_cas_32 (volatile uint32_t *, uint32_t, uint32_t);
319 extern uint32_t __collector_subget_32 (volatile uint32_t *, uint32_t);
320 extern uint64_t __collector_cas_64p (volatile uint64_t *, uint64_t *, uint64_t *);
321 #endif /* ARCH() */
322 #endif /* _LIBCOL_UTIL_H */
323