]>
Commit | Line | Data |
---|---|---|
fd67aa11 | 1 | /* Copyright (C) 2021-2024 Free Software Foundation, Inc. |
bb368aad VM |
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); | |
53beac2e VM |
41 | extern int (*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...) |
42 | __attribute__ ((format (scanf, 2, 3))); | |
bb368aad VM |
43 | extern char * __collector_strcat (char *s1, const char *s2); |
44 | extern char * __collector_strchr (const char *s1, int chr); | |
45 | extern size_t __collector_strlcpy (char *dst, const char *src, size_t dstsize); | |
46 | extern char* __collector_strrchr (const char *str, int chr); | |
47 | extern size_t __collector_strlen (const char *s); | |
48 | extern size_t __collector_strlcat (char *dst, const char *src, size_t dstsize); | |
49 | extern char* __collector_strchr (const char *str, int chr); | |
50 | extern int __collector_strcmp (const char *s1, const char *s2); | |
51 | extern int __collector_strncmp (const char *s1, const char *s2, size_t n); | |
52 | extern char * __collector_strstr (const char *s1, const char *s2); | |
53 | extern size_t __collector_strncpy (char *dst, const char *src, size_t dstsize); | |
54 | extern size_t __collector_strncat (char *dst, const char *src, size_t dstsize); | |
55 | extern void * __collector_malloc (size_t size); | |
56 | extern void * __collector_calloc (size_t nelem, size_t elsize); | |
57 | extern char * __collector_strdup (const char * str); | |
58 | extern int __collector_strStartWith (const char *s1, const char *s2); | |
59 | extern int __collector_xml_snprintf (char *s, size_t n, const char *format, ...) __attribute__ ((format (printf, 3, 4))); | |
60 | extern int __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args); | |
61 | ||
62 | /* ------- collector_thread ----------------- */ | |
fe39ffdc | 63 | extern pid_t __collector_gettid (); |
bb368aad | 64 | extern void __collector_ext_gettid_tsd_create_key (); |
fe39ffdc VM |
65 | typedef pthread_t collector_thread_t; |
66 | #define __collector_lwp_self() ((collector_thread_t) ((unsigned long) __collector_gettid())) | |
67 | #define __collector_thr_self() ((collector_thread_t) ((unsigned long) __collector_gettid())) | |
bb368aad VM |
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 | } | |
2a2cb7cf | 136 | |
bb368aad VM |
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 | } | |
2a2cb7cf | 152 | |
bb368aad VM |
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; | |
2a2cb7cf | 160 | #if WSIZE(32) || defined(__ILP32__) |
bb368aad | 161 | __asm__ __volatile__("movl %%esp, %0" |
2a2cb7cf VM |
162 | #else |
163 | __asm__ __volatile__("movq %%rsp, %0" | |
164 | #endif | |
bb368aad VM |
165 | : "=r" (r)); // output |
166 | return r; | |
167 | } | |
2a2cb7cf | 168 | |
bb368aad VM |
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; | |
2a2cb7cf | 176 | #if WSIZE(32) || defined(__ILP32__) |
bb368aad | 177 | __asm__ __volatile__("movl %%ebp, %0" |
2a2cb7cf VM |
178 | #else |
179 | __asm__ __volatile__("movq %%rbp, %0" | |
bb368aad VM |
180 | #endif |
181 | : "=r" (r)); // output | |
182 | return r; | |
183 | } | |
2a2cb7cf | 184 | |
bb368aad VM |
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; | |
2a2cb7cf VM |
192 | #if defined(__x86_64) |
193 | __asm__ __volatile__("lea (%%rip), %0" : "=r" (r)); | |
bb368aad | 194 | #else |
2a2cb7cf VM |
195 | __asm__ __volatile__("call 1f \n" |
196 | "1: popl %0" : "=r" (r)); | |
bb368aad | 197 | #endif |
bb368aad VM |
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; | |
2a2cb7cf | 262 | #if WSIZE(32) || defined(__ILP32__) |
bb368aad VM |
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 */ |