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/*
22 *	Central SIGPROF dispatcher to various module event handlers
23 *      (REALPROF profile, HWC check, overview sample, manual sample)
24 */
25
26#include "config.h"
27#include <dlfcn.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <ucontext.h>
34#include <sys/param.h>
35#include <sys/signal.h>
36#include <sys/syscall.h>
37#include <time.h>
38#include <signal.h>
39
40#include "gp-defs.h"
41#include "gp-experiment.h"
42#include "collector.h"
43#include "collector_module.h"
44#include "tsd.h"
45#include "hwcdrv.h"
46
47
48/* TprintfT(<level>,...) definitions.  Adjust per module as needed */
49#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
50#define DBG_LTT 0 // for interposition on GLIBC functions
51#define DBG_LT1 1 // for configuration details, warnings
52#define DBG_LT2 2
53#define DBG_LT3 3
54
55static void collector_sigprof_dispatcher (int, siginfo_t*, void*);
56static int init_interposition_intf ();
57#include "memmgr.h"
58static int collector_timer_create (timer_t * ptimerid);
59static int collector_timer_settime (int period, timer_t timerid);
60static int collector_timer_gettime (timer_t timerid);
61static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */
62static timer_t collector_master_thread_timerid = NULL;
63static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER;
64static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
65
66static void *__real_clone = NULL;
67static void *__real_timer_create = NULL;
68static void *__real_timer_settime = NULL;
69static void *__real_timer_delete = NULL;
70static void *__real_timer_gettime = NULL;
71#if ARCH(Intel) && WSIZE(32)
72static void *__real_pthread_create_2_1 = NULL;
73static void *__real_pthread_create_2_0 = NULL;
74#elif ARCH(Intel) && WSIZE(64)
75static void *__real_timer_create_2_3_3 = NULL;
76static void *__real_timer_create_2_2_5 = NULL;
77#elif ARCH(SPARC) && WSIZE(64)
78static void *__real_timer_create_2_3_3 = NULL;
79static void *__real_timer_create_2_2 = NULL;
80#endif
81
82/* Original SIGPROF handler which will be replaced with the dispatcher.  Used
83 * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */
84static struct sigaction original_sigprof_handler;
85
86enum
87{
88  DISPATCH_NYI = -1,    /* dispatcher not yet installed */
89  DISPATCH_OFF = 0,     /* dispatcher installed, but disabled */
90  DISPATCH_ON = 1,      /* dispatcher installed, and enabled */
91  DISPATCH_TST = 2      /* dispatcher installed, and enabled in testing mode */
92};
93
94static int dispatch_mode = DISPATCH_NYI;   /* controls SIGPROF dispatching */
95static int itimer_period_requested = 0;    /* dispatcher itimer period */
96static int itimer_period_actual = 0;       /* actual dispatcher itimer period */
97
98#define CALL_REAL(x) (*(int(*)())__real_##x)
99#define NULL_PTR(x) ( __real_##x == NULL )
100
101static void *__real_sigaction = NULL;
102static void *__real_setitimer = NULL;
103static void *__real_libc_setitimer = NULL;
104static void *__real_sigprocmask = NULL;
105static void *__real_thr_sigsetmask = NULL;
106static void *__real_pthread_sigmask = NULL;
107static void *__real_pthread_create = NULL;
108
109/*
110 * void collector_sigprof_dispatcher()
111 *
112 * Common SIGPROF event handler which dispatches events to appropriate
113 * module handlers, if they are active for this collection and due.
114 * Dispatch sequence, logic and handlers currently hardcoded in dispatcher.
115 */
116static void
117collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context)
118{
119  if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER))
120    {
121      TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n",
122		original_sigprof_handler.sa_handler);
123      /* pass signal to previous handler */
124      /* watch for recursion, SIG_IGN, and SIG_DFL */
125      if (original_sigprof_handler.sa_handler == SIG_DFL)
126	__collector_SIGDFL_handler (SIGPROF);
127      else if (original_sigprof_handler.sa_handler != SIG_IGN &&
128	       original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher)
129	{
130	  (original_sigprof_handler.sa_sigaction)(sig, info, context);
131	  TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n");
132	}
133    }
134  else if (dispatch_mode == DISPATCH_ON)
135    {
136#if ARCH(SPARC)
137      ucontext_t uctxmem;
138      ucontext_t *uctx = &uctxmem;
139      uctx->uc_link = NULL;
140      /* 23340823 signal handler third argument should point to a ucontext_t */
141      /* Convert sigcontext to ucontext_t on sparc-Linux */
142      struct sigcontext *sctx = (struct sigcontext*) context;
143#if WSIZE(32)
144      uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
145      __collector_memcpy (&uctx->uc_mcontext.gregs[3],
146			  sctx->si_regs.u_regs,
147			  sizeof (sctx->si_regs.u_regs));
148#else
149      uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
150      __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
151			  sctx->sigc_regs.u_regs,
152			  sizeof (sctx->sigc_regs.u_regs));
153#endif /* WSIZE() */
154
155#else /* not sparc-Linux */
156      ucontext_t *uctx = (ucontext_t*) context;
157#endif /* ARCH() */
158      TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n");
159
160      /* XXXX the order of these checks/activities may need adjustment */
161      /* XXXX should also check (first) for a "cached" manual sample */
162      /* HWC check for each LWP: required even if collection is paused */
163      /* This should be first, otherwise it's likely to find the counters
164       * stopped due to an event/overflow during some of the other activities.
165       */
166      /* XXXX HWC check performed every time (skipping if HWC profiling inactive)
167       * to avoid complexity of maintaining separate check times for each LWP
168       */
169      __collector_ext_hwc_check (info, uctx);
170
171      /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample
172       * (and get it next time through)
173       */
174
175      /* check for experiment past delay start */
176      if (__collector_delay_start != 0)
177	{
178	  hrtime_t now = __collector_gethrtime ();
179	  if (__collector_delay_start < now)
180	    {
181	      TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n",
182			(now - __collector_start_time), (__collector_delay_start - __collector_start_time));
183
184	      /* resume the data collection */
185	      __collector_delay_start = 0;
186	      __collector_resume ();
187
188	      /* don't take a periodic sample, just let the resume sample cover it */
189	      if (__collector_sample_period != 0)
190		{
191		  /* this update should only be done for periodic samples */
192		  while (__collector_next_sample < now)
193		    __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
194		}
195	      /* return; */
196	    }
197	}
198      /* check for periodic sampling */
199      if (__collector_gethrtime () > __collector_next_sample)
200	__collector_ext_usage_sample (PERIOD_SMPL, "periodic");
201
202      /* check for experiment past termination time */
203      if (__collector_exp_active && __collector_terminate_time != 0)
204	{
205	  hrtime_t now = __collector_gethrtime ();
206	  if (__collector_terminate_time < now)
207	    {
208	      TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n",
209			(now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
210	      /* close the experiment */
211	      __collector_close_experiment ();
212	    }
213	}
214
215      /* call the code to process the profile data, and generate the packet */
216      /* (must always be called, otherwise profile data must be aggregated,
217       * but can be left till last, as already have the required data)
218       */
219      __collector_ext_profile_handler (info, uctx);
220    }
221  else if (dispatch_mode == DISPATCH_TST)
222    {
223      collector_sigprof_entries++;
224      return;
225    }
226}
227
228/*
229 *  __collector_sigprof_install
230 */
231int
232__collector_sigprof_install ()
233{
234  TprintfT (DBG_LT2, "__collector_sigprof_install\n");
235  struct sigaction oact;
236  if (__collector_sigaction (SIGPROF, NULL, &oact) != 0)
237    return COL_ERROR_DISPINIT;
238  if (oact.sa_sigaction == collector_sigprof_dispatcher)
239    /* signal handler is already in place; we are probably in a fork-child */
240    TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n");
241  else
242    {
243      struct sigaction c_act;
244      CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
245      sigemptyset (&c_act.sa_mask);
246      sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */
247      c_act.sa_sigaction = collector_sigprof_dispatcher;
248      c_act.sa_flags = SA_RESTART | SA_SIGINFO;
249      if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler))
250	return COL_ERROR_DISPINIT;
251    }
252  dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */
253  TprintfT (DBG_LT2, "__collector_sigprof_install done\n");
254  return COL_ERROR_NONE;
255}
256
257/*
258 * void __collector_ext_dispatcher_tsd_create_key()
259 *
260 * create tsd key for dispatcher
261 */
262void
263__collector_ext_dispatcher_tsd_create_key ()
264{
265  dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL);
266}
267/*
268 * int __collector_ext_dispatcher_install()
269 *
270 * installs a common handler/dispatcher (and itimer) for SIGPROF events
271 */
272int
273__collector_ext_dispatcher_install ()
274{
275  int timer_period;
276  TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n");
277
278  /* check period set for interval timer, which will be used as the basis
279   * for all timed activities: if not set, no role for SIGPROF dispatcher
280   */
281  if (itimer_period_requested <= 0)
282    {
283      TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n");
284      return COL_ERROR_NONE; /* no itimer/dispatcher required */
285    }
286
287  /* check for an existing interval timer */
288  if (collector_master_thread_timerid == NULL)
289    if (collector_timer_create (&collector_master_thread_timerid) < 0)
290      return COL_ERROR_ITMRINIT;
291  timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
292  if (timeridptr != NULL)
293    *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start
294  TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n",
295	    collector_master_thread_timerid);
296  timer_period = collector_timer_gettime (collector_master_thread_timerid);
297  if (timer_period > 0)
298    {
299      TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period);
300      (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n",
301				    SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested);
302    }
303  /* install the interval timer used for all timed activities */
304  if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0)
305    return COL_ERROR_ITMRINIT;
306  TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n");
307  dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */
308  return COL_ERROR_NONE;
309}
310
311int
312__collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
313{
314  TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL);
315  if (NULL_PTR (sigaction))
316    init_interposition_intf ();
317
318  /* Whether we change the signal handler in the kernel
319   * or not make sure the real sigaction is aware about
320   * our new handler (6227565)
321   */
322  return CALL_REAL (sigaction)(sig, nact, oact);
323}
324
325/*
326 * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to
327 * decide whether the signal was intended for us or for the user.
328 * One special case is SIGDFL, in which case we don't have a
329 * user-function address to call.  If the user did indeed set
330 * default disposition for one of these signals and sent that
331 * signal, we honor that action, even though it will lead to
332 * termination.
333 */
334void
335__collector_SIGDFL_handler (int sig)
336{
337  /* remove our dispatcher, replacing it with the default disposition */
338  struct sigaction act;
339  CALL_UTIL (memset)(&act, 0, sizeof (act));
340  act.sa_handler = SIG_DFL;
341  if (__collector_sigaction (sig, &act, NULL))
342    {
343      /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */
344    }
345  /* resend the signal we intercepted earlier */
346  // XXXX Bug 18177509 - additional sigprof signal kills target program
347  kill (getpid (), sig);
348}
349
350/*
351 * suspend/resume timer per thread
352 */
353void
354__collector_ext_dispatcher_thread_timer_suspend ()
355{
356  timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
357  if (timeridptr != NULL && *timeridptr != NULL)
358    (void) collector_timer_settime (0, *timeridptr);
359  return;
360}
361
362int
363__collector_ext_dispatcher_thread_timer_resume ()
364{
365  timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
366  if (timeridptr == NULL)
367    return -1;
368  if (*timeridptr == NULL)
369    { // timer id not initialized yet
370      TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n");
371      if (collector_timer_create (timeridptr) == -1)
372	{
373	  TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n");
374	  return -1;
375	}
376    }
377  return collector_timer_settime (itimer_period_requested, *timeridptr);
378}
379
380void
381__collector_ext_dispatcher_suspend ()
382{
383  TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n");
384  if (dispatch_mode == DISPATCH_NYI)
385    {
386      TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n");
387      return;
388    }
389
390  /* disable SIGPROF dispatching */
391  dispatch_mode = DISPATCH_OFF;
392
393  /* disable the interval timer; ignore any failures */
394  __collector_ext_dispatcher_thread_timer_suspend ();
395  return;
396}
397
398void
399__collector_ext_dispatcher_restart ()
400{
401  TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested);
402  if (dispatch_mode == DISPATCH_NYI)
403    {
404      TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n");
405      return;
406    }
407
408  /* restart the interval timer used for all timed activities */
409  if (__collector_ext_dispatcher_thread_timer_resume () == 0)
410    dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */
411  return;
412}
413/*
414 * void __collector_ext_dispatcher_deinstall()
415 *
416 * If installed, disables SIGPROF dispatch and interval timer.
417 * Includes checks for last SIGPROF dispatch time, interval timer period,
418 * and currently installed SIGPROF handler, with appropriate warnings logged.
419 * The dispatcher remains installed to handle pending collector SIGPROFs and
420 * forward non-collector SIGPROFs to the application's handler(s).
421 * If the decision is ever made actually to deinstall the dispatcher,
422 * consider bug 4183714 and what to do about any possible pending
423 * SIGPROFs.
424 */
425
426void
427__collector_ext_dispatcher_deinstall ()
428{
429  TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n");
430  if (dispatch_mode == DISPATCH_NYI)
431    {
432      TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n");
433      return;
434    }
435  dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */
436
437  /* verify that interval timer is still installed with expected period */
438  int timer_period = collector_timer_gettime (collector_master_thread_timerid);
439  if (timer_period != itimer_period_actual)
440    {
441      TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n",
442		itimer_period_actual, timer_period);
443      if ((itimer_period_actual >= (timer_period + timer_period / 10)) ||
444	  (itimer_period_actual <= (timer_period - timer_period / 10)))
445	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
446			       SP_JCMD_CWARN, COL_WARN_ITMRREP,
447			       itimer_period_actual, timer_period);
448      else
449	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
450			       SP_JCMD_COMMENT, COL_WARN_PROFRND,
451			       itimer_period_actual, timer_period);
452    }
453
454  /* Verify that SIGPROF dispatcher is still installed.
455   * (still required with sigaction interposition and management,
456   * since interposition is not done for attach experiments)
457   */
458  struct sigaction curr;
459  if (__collector_sigaction (SIGPROF, NULL, &curr) == -1)
460    TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno);
461  else if (curr.sa_sigaction != collector_sigprof_dispatcher)
462    {
463      TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler);
464      (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n",
465				    SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler);
466    }
467  else
468    TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n");
469
470  /* disable the interval timer; ignore any failures */
471  if (collector_master_thread_timerid != NULL)
472    {
473      (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
474      collector_master_thread_timerid = NULL;
475    }
476  dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
477  itimer_period_requested = 0;
478  itimer_period_actual = 0;
479}
480
481/*
482 * void __collector_ext_dispatcher_fork_child_cleanup()
483 *
484 * delete timer, clear timer interval
485 */
486void
487__collector_ext_dispatcher_fork_child_cleanup ()
488{
489  if (collector_master_thread_timerid != NULL)
490    {
491      (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
492      collector_master_thread_timerid = NULL;
493    }
494  __collector_mutex_init (&collector_clone_libc_lock);
495  dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
496  itimer_period_requested = 0;
497  itimer_period_actual = 0;
498}
499/*
500 * int __collector_ext_itimer_set (int rperiod)
501 *
502 * set itimer period, if not yet set to a positive number of microseconds,
503 * (after rounding to sys_resolution if necessary) and return its value
504 */
505int
506__collector_ext_itimer_set (int rperiod)
507{
508  int period;
509  /* if rperiod is negative, force setting */
510  if (rperiod < 0)
511    {
512      itimer_period_actual = 0;
513      period = -rperiod;
514    }
515  else
516    period = rperiod;
517
518  // ignore SIGPROF while testing itimer interval setting
519  int saved = dispatch_mode;
520  dispatch_mode = DISPATCH_OFF;
521  if (collector_timer_create (&collector_master_thread_timerid) == -1)
522    {
523      TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n");
524      return itimer_period_actual;
525    }
526  if (collector_timer_settime (period, collector_master_thread_timerid) == 0)
527    {
528      itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid);
529      (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */
530      itimer_period_requested = period;
531      if (itimer_period_requested != itimer_period_actual)
532	{
533	  TprintfT (DBG_LT2, "    itimer period %d adjusted to %d\n",
534		    itimer_period_requested, itimer_period_actual);
535	  // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
536	  //     SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual);
537	}
538      else
539	TprintfT (DBG_LT2, "    itimer period %d accepted\n", period);
540    }
541
542  // restore dispatching SIGPROF handler
543  dispatch_mode = saved;
544  TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n",
545	    rperiod, itimer_period_requested, itimer_period_actual);
546  return (itimer_period_actual);
547}
548
549static int
550collector_timer_gettime (timer_t timerid)
551{
552  int timer_period;
553  struct itimerspec itimer;
554  if (timerid == NULL)
555    return (0); // timer was not initialized
556  if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1)
557    {
558      /* this should never reasonably fail, so not worth logging */
559      TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno);
560      return (-1);
561    }
562  timer_period = ((itimer.it_interval.tv_sec * NANOSEC) +
563		  itimer.it_interval.tv_nsec) / 1000;
564  TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period);
565  return (timer_period);
566}
567
568static int
569collector_timer_create (timer_t * ptimerid)
570{
571  struct sigevent sigev;
572  if (NULL_PTR (timer_create))
573    init_interposition_intf ();
574  TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create);
575  sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
576  sigev.sigev_signo = SIGPROF;
577  sigev.sigev_value.sival_ptr = ptimerid;
578  sigev._sigev_un._tid = __collector_gettid ();
579  if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1)
580    {
581      TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno);
582      return -1;
583    }
584  return 0;
585}
586
587static int
588collector_timer_settime (int period, timer_t timerid)
589{
590  struct itimerspec itimer;
591  if (NULL_PTR (timer_settime))
592    init_interposition_intf ();
593  TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period);
594  time_t NPM = 1000;
595  itimer.it_interval.tv_sec = NPM * period / NANOSEC;
596  itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC;
597  itimer.it_value = itimer.it_interval;
598  if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1)
599    {
600      TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno);
601      return -1;
602    }
603  return 0;
604}
605
606static void
607protect_profiling_signals (sigset_t* lset)
608{
609  static unsigned int protected_sigprof = 0;
610  static unsigned int protected_sigemt = 0;
611  // T1 relies on thread signal masking, so best not to mess with it:
612  // T1 users have already been warned about the dangers of its use
613  if (__collector_libthread_T1)
614    return;
615  if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON))
616    {
617      TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF");
618      if (protected_sigprof == 0)
619	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
620			       SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF");
621      sigdelset (lset, SIGPROF);
622      protected_sigprof++;
623    }
624  if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ())
625    {
626      TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT");
627      if (protected_sigemt == 0)
628	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
629			       SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING);
630      sigdelset (lset, HWCFUNCS_SIGNAL);
631      protected_sigemt++;
632    }
633}
634
635#define SYS_SETITIMER_NAME      "setitimer"
636#define SYS_SIGACTION_NAME      "sigaction"
637#define SYS_SIGPROCMASK_NAME    "sigprocmask"
638#define SYS_PTHREAD_SIGMASK     "pthread_sigmask"
639#define SYS_THR_SIGSETMASK      "thr_sigsetmask"
640
641static int
642init_interposition_intf ()
643{
644  if (__collector_dlsym_guard)
645    return 1;
646  void *dlflag;
647  /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
648  void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
649
650#if ARCH(SPARC) && WSIZE(64)
651  /* dlopen a bogus path to avoid CR 23608692 */
652  dlopen ("/bogus_path_for_23608692_workaround/", RTLD_LAZY | RTLD_NOLOAD);
653#endif
654  __real_setitimer = dlsym (RTLD_NEXT, SYS_SETITIMER_NAME);
655
656  if (__real_setitimer == NULL)
657    {
658      __real_setitimer = dlsym (RTLD_DEFAULT, SYS_SETITIMER_NAME);
659      if (__real_setitimer == NULL)
660	{
661	  TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n");
662	  return 1;
663	}
664      dlflag = RTLD_DEFAULT;
665    }
666  else
667    dlflag = RTLD_NEXT;
668
669  TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n",
670	    (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT");
671  TprintfT (DBG_LT2, "@%p __real_setitimer\n", __real_setitimer);
672
673  __real_sigaction = dlsym (dlflag, SYS_SIGACTION_NAME);
674  TprintfT (DBG_LT2, "@%p __real_sigaction\n", __real_sigaction);
675
676  /* also explicitly get libc.so/setitimer (as a backup) */
677  __real_libc_setitimer = dlsym (handle, SYS_SETITIMER_NAME);
678  TprintfT (DBG_LT2, "@%p __real_libc_setitimer\n", __real_libc_setitimer);
679
680  __real_sigprocmask = dlsym (dlflag, SYS_SIGPROCMASK_NAME);
681  TprintfT (DBG_LT2, "@%p __real_sigprocmask\n", __real_sigprocmask);
682
683  __real_thr_sigsetmask = dlsym (dlflag, SYS_THR_SIGSETMASK);
684  TprintfT (DBG_LT2, "@%p __real_thr_sigsetmask\n", __real_thr_sigsetmask);
685
686  __real_pthread_sigmask = dlsym (dlflag, SYS_PTHREAD_SIGMASK);
687  TprintfT (DBG_LT2, "@%p __real_pthread_sigmask\n", __real_pthread_sigmask);
688
689#if ARCH(Aarch64)
690  __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
691  __real_timer_create = dlsym (dlflag, "timer_create");
692  __real_timer_settime = dlsym (dlflag, "timer_settime");
693  __real_timer_delete = dlsym (dlflag, "timer_delete");
694  __real_timer_gettime = dlsym (dlflag, "timer_gettime");
695#else
696  __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
697  TprintfT (DBG_LT2, "[%s] @%p __real_pthread_create\n", SYS_PTHREAD_CREATE_VERSION, __real_pthread_create);
698  __real_timer_create = dlvsym (dlflag, "timer_create", SYS_TIMER_X_VERSION);
699  TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_create\n", SYS_TIMER_X_VERSION, __real_timer_create);
700  __real_timer_settime = dlvsym (dlflag, "timer_settime", SYS_TIMER_X_VERSION);
701  TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_settime\n", SYS_TIMER_X_VERSION, __real_timer_settime);
702  __real_timer_delete = dlvsym (dlflag, "timer_delete", SYS_TIMER_X_VERSION);
703  TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_delete\n", SYS_TIMER_X_VERSION, __real_timer_delete);
704  __real_timer_gettime = dlvsym (dlflag, "timer_gettime", SYS_TIMER_X_VERSION);
705  TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_gettime\n", SYS_TIMER_X_VERSION, __real_timer_gettime);
706  __real_clone = dlsym (dlflag, "clone");
707  TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
708#if ARCH(Intel) && WSIZE(32)
709  __real_pthread_create_2_1 = __real_pthread_create;
710  __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0");
711#elif ARCH(Intel) && WSIZE(64)
712  __real_timer_create_2_3_3 = __real_timer_create;
713  __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5");
714#elif ARCH(SPARC) && WSIZE(64)
715  __real_timer_create_2_3_3 = __real_timer_create;
716  __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2");
717#endif /* ARCH() && SIZE() */
718#endif
719  return 0;
720}
721
722
723/*------------------------------------------------------------- sigaction */
724
725/* NB: need a global interposing function called "sigaction" */
726int
727sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
728{
729  int ret = 0;
730  int err = 0;
731  if (NULL_PTR (sigaction))
732    err = init_interposition_intf ();
733  if (err)
734    return -1;
735  TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact);
736  if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI)
737    {
738      if (oact != NULL)
739	{
740	  oact->sa_handler = original_sigprof_handler.sa_handler;
741	  oact->sa_mask = original_sigprof_handler.sa_mask;
742	  oact->sa_flags = original_sigprof_handler.sa_flags;
743	}
744      if (nact != NULL)
745	{
746	  original_sigprof_handler.sa_handler = nact->sa_handler;
747	  original_sigprof_handler.sa_mask = nact->sa_mask;
748	  original_sigprof_handler.sa_flags = nact->sa_flags;
749	  TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig);
750	}
751    }
752  else if (sig == HWCFUNCS_SIGNAL)
753    ret = collector_sigemt_sigaction (nact, oact);
754  else
755    {
756      if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact))
757	ret = CALL_REAL (sigaction)(sig, nact, oact);
758      TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n",
759		sig, ret, oact);
760      /* but check for other important signals */
761      /* check for sample and pause/resume signals; give warning once, if need be */
762      if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0))
763	{
764	  /* give user a warning */
765	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
766					SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig);
767	  __collector_sample_sig_warn = 1;
768	}
769      if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0))
770	{
771	  /* give user a warning */
772	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
773					SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig);
774	  __collector_pause_sig_warn = 1;
775	}
776    }
777  TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact);
778  return ret;
779}
780
781/*
782 * In addition to interposing on sigaction(), should we also interpose
783 * on other important signal functions like signal() or sigset()?
784 * - On Solaris, those other functions apparently call sigaction().
785 *   So, we only have to interpose on it.
786 * - On Linux, we should perhaps interpose on these other functions,
787 *   but they are less portable than sigaction() and deprecated or even obsolete.
788 *   So, we interpose, but don't overly worry about doing a good job.
789 */
790sighandler_t
791signal (int sig, sighandler_t handler)
792{
793  struct sigaction nact;
794  struct sigaction oact;
795  TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler);
796  sigemptyset (&nact.sa_mask);
797  nact.sa_handler = handler;
798  nact.sa_flags = SA_RESTART;
799  if (sigaction (sig, &nact, &oact))
800    return SIG_ERR;
801  TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler);
802  return oact.sa_handler;
803}
804
805sighandler_t
806sigset (int sig, sighandler_t handler)
807{
808  TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler);
809  return signal (sig, handler);
810}
811
812/*------------------------------------------------------------- timer_create */
813
814// map interposed symbol versions
815#if WSIZE(64)
816#if ARCH(SPARC) || ARCH(Intel)
817static int
818__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, struct sigevent *sevp,
819				 timer_t *timerid);
820
821SYMVER_ATTRIBUTE (__collector_timer_create_2_3_3, timer_create@@GLIBC_2.3.3)
822int
823__collector_timer_create_2_3_3 (clockid_t clockid, struct sigevent *sevp,
824				timer_t *timerid)
825{
826  if (NULL_PTR (timer_create))
827    init_interposition_intf ();
828  TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_3_3@%p\n", CALL_REAL (timer_create_2_3_3));
829  return __collector_timer_create_symver (CALL_REAL (timer_create_2_3_3), clockid, sevp, timerid);
830}
831#endif /* ARCH(SPARC) || ARCH(Intel)*/
832
833#if ARCH(SPARC)
834
835SYMVER_ATTRIBUTE (__collector_timer_create_2_2, timer_create@GLIBC_2.2)
836int
837__collector_timer_create_2_2 (clockid_t clockid, struct sigevent *sevp,
838			      timer_t *timerid)
839{
840  if (NULL_PTR (timer_create))
841    init_interposition_intf ();
842  TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2@%p\n", CALL_REAL (timer_create_2_2));
843  return __collector_timer_create_symver (CALL_REAL (timer_create_2_2), clockid, sevp, timerid);
844}
845
846#elif ARCH(Intel)
847
848SYMVER_ATTRIBUTE (__collector_timer_create_2_2_5, timer_create@GLIBC_2.2.5)
849int
850__collector_timer_create_2_2_5 (clockid_t clockid, struct sigevent *sevp,
851				timer_t *timerid)
852{
853  if (NULL_PTR (timer_create))
854    init_interposition_intf ();
855  TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2_5@%p\n", CALL_REAL (timer_create_2_2_5));
856  return __collector_timer_create_symver (CALL_REAL (timer_create_2_2_5), clockid, sevp, timerid);
857}
858#endif /* ARCH() */
859#endif /* WSIZE(64) */
860
861#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
862int timer_create (clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
863#else
864static int
865__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid,
866				 struct sigevent *sevp, timer_t *timerid)
867#endif
868{
869  int ret;
870
871  if (NULL_PTR (timer_create))
872    init_interposition_intf ();
873
874  /* collector reserves SIGPROF
875   */
876  if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL
877      || sevp->sigev_signo != SIGPROF)
878    {
879#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
880      ret = CALL_REAL (timer_create)(clockid, sevp, timerid);
881#else
882      ret = (real_timer_create) (clockid, sevp, timerid);
883#endif
884      TprintfT (DBG_LT2, "Real timer_create(%d) returned %d\n",
885		clockid, ret);
886      return ret;
887    }
888
889  /* log that application's timer_create request is overridden */
890  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
891				SP_JCMD_CWARN, COL_WARN_ITMROVR, -1);
892  ret = -1;
893  errno = EBUSY;
894  TprintfT (DBG_LT2, "timer_create() returning %d\n", ret);
895  return ret;
896}
897/*------------------------------------------------------------- setitimer */
898int
899_setitimer (int which, const struct itimerval *nval,
900	    struct itimerval *oval)
901{
902  int ret;
903  int period;
904
905  if (NULL_PTR (setitimer))
906    init_interposition_intf ();
907
908  if (nval == NULL)
909    period = -1;
910  else
911    period = (nval->it_interval.tv_sec * MICROSEC) +
912    nval->it_interval.tv_usec;
913  TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period);
914
915  /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF
916   * uses the same signal (SIGPROF) so it must also be reserved
917   */
918  if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL))
919    {
920      ret = CALL_REAL (setitimer)(which, nval, oval);
921      if (oval == NULL)
922	period = -1;
923      else
924	period = (oval->it_interval.tv_sec * MICROSEC) +
925	oval->it_interval.tv_usec;
926      TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n",
927		which, ret, period);
928      return ret;
929    }
930  /* log that application's setitimer request is overridden */
931  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
932				SP_JCMD_CWARN, COL_WARN_ITMROVR, period);
933  if (oval == NULL)
934    period = -1;
935  else
936    {
937      getitimer (which, oval); /* return current itimer setting */
938      period = (oval->it_interval.tv_sec * MICROSEC) +
939	      oval->it_interval.tv_usec;
940    }
941  ret = -1;
942  errno = EBUSY;
943  TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period);
944  return ret;
945}
946
947/*--------------------------------------------------------------- sigprocmask */
948int
949__collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset)
950{
951  int err = 0;
952  if (NULL_PTR (sigprocmask))
953    err = init_interposition_intf ();
954  if (err)
955    return -1;
956  TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how);
957  sigset_t lsigset;
958  sigset_t* lset = NULL;
959  if (iset)
960    {
961      lsigset = *iset;
962      lset = &lsigset;
963      if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
964	protect_profiling_signals (lset);
965    }
966  int ret = CALL_REAL (sigprocmask)(how, lset, oset);
967  TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret);
968  return ret;
969}
970
971/*------------------------------------------------------------ thr_sigsetmask */
972int
973__collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset)
974{
975  if (NULL_PTR (thr_sigsetmask))
976    init_interposition_intf ();
977  TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how);
978  sigset_t lsigset;
979  sigset_t* lset = NULL;
980  if (iset)
981    {
982      lsigset = *iset;
983      lset = &lsigset;
984      if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
985	protect_profiling_signals (lset);
986    }
987  int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset);
988  TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret);
989  return ret;
990}
991
992/*----------------------------------------------------------- pthread_sigmask */
993
994int
995pthread_sigmask (int how, const sigset_t* iset, sigset_t* oset)
996{
997  if (NULL_PTR (pthread_sigmask))
998    init_interposition_intf ();
999  TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) interposing\n", how);
1000  sigset_t lsigset;
1001  sigset_t* lset = NULL;
1002  if (iset)
1003    {
1004      lsigset = *iset;
1005      lset = &lsigset;
1006      if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
1007	protect_profiling_signals (lset);
1008    }
1009  int ret = CALL_REAL (pthread_sigmask)(how, lset, oset);
1010  TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) returning %d\n", how, ret);
1011  return ret;
1012}
1013/*----------------------------------------------------------- pthread_create */
1014typedef struct _CollectorArgs
1015{
1016  void *(*func)(void*);
1017  void *arg;
1018  void *stack;
1019  int isPthread;
1020} CollectorArgs;
1021
1022static void *
1023collector_root (void *cargs)
1024{
1025  /* save the real arguments and free cargs */
1026  void *(*func)(void*) = ((CollectorArgs*) cargs)->func;
1027  void *arg = ((CollectorArgs*) cargs)->arg;
1028  void *stack = ((CollectorArgs*) cargs)->stack;
1029  int isPthread = ((CollectorArgs*) cargs)->isPthread;
1030  __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1031
1032  /* initialize tsd for this thread */
1033  if (__collector_tsd_allocate () == 0)
1034    /* init tsd for unwind, called right after __collector_tsd_allocate()*/
1035    __collector_ext_unwind_key_init (isPthread, stack);
1036
1037  if (!isPthread)
1038    __collector_mutex_lock (&collector_clone_libc_lock);
1039
1040  /* set the profile timer */
1041  timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
1042  timer_t timerid = NULL;
1043  if (timeridptr != NULL)
1044    {
1045      collector_timer_create (timeridptr);
1046      if (*timeridptr != NULL)
1047	collector_timer_settime (itimer_period_requested, *timeridptr);
1048      timerid = *timeridptr;
1049    }
1050  int hwc_rc = __collector_ext_hwc_lwp_init ();
1051
1052  if (!isPthread)
1053    __collector_mutex_unlock (&collector_clone_libc_lock);
1054  /* call the real function */
1055  void *ret = func (arg);
1056  if (!isPthread)
1057    __collector_mutex_lock (&collector_clone_libc_lock);
1058  if (timerid != NULL)
1059    CALL_REAL (timer_delete)(timerid);
1060  if (!hwc_rc)
1061    /* pthread_kill not handled here */
1062    __collector_ext_hwc_lwp_fini ();
1063
1064  if (!isPthread)
1065    __collector_mutex_unlock (&collector_clone_libc_lock);
1066  /* if we have this chance, release tsd */
1067  __collector_tsd_release ();
1068
1069  return ret;
1070}
1071
1072// map interposed symbol versions
1073#if ARCH(Intel) && WSIZE(32)
1074static int
1075__collector_pthread_create_symver (int(real_pthread_create) (),
1076				   pthread_t *thread,
1077				   const pthread_attr_t *attr,
1078				   void *(*func)(void*),
1079				   void *arg);
1080
1081SYMVER_ATTRIBUTE (__collector_pthread_create_2_1, pthread_create@@GLIBC_2.1)
1082int
1083__collector_pthread_create_2_1 (pthread_t *thread,
1084				const pthread_attr_t *attr,
1085				void *(*func)(void*),
1086				void *arg)
1087{
1088  if (NULL_PTR (pthread_create))
1089    init_interposition_intf ();
1090  TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_1@%p\n", CALL_REAL (pthread_create_2_1));
1091  return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_1), thread, attr, func, arg);
1092}
1093
1094SYMVER_ATTRIBUTE (__collector_pthread_create_2_0, pthread_create@GLIBC_2.0)
1095int
1096__collector_pthread_create_2_0 (pthread_t *thread,
1097				const pthread_attr_t *attr,
1098				void *(*func)(void*),
1099				void *arg)
1100{
1101  if (NULL_PTR (pthread_create))
1102    init_interposition_intf ();
1103  TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_0@%p\n", CALL_REAL (pthread_create_2_0));
1104  return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_0), thread, attr, func, arg);
1105}
1106
1107#endif
1108
1109#if ARCH(Intel) && WSIZE(32)
1110static int
1111__collector_pthread_create_symver (int(real_pthread_create) (),
1112				   pthread_t *thread,
1113				   const pthread_attr_t *attr,
1114				   void *(*func)(void*),
1115				   void *arg)
1116#else
1117int
1118pthread_create (pthread_t *thread, const pthread_attr_t *attr,
1119		void *(*func)(void*), void *arg)
1120#endif
1121{
1122  if (NULL_PTR (pthread_create))
1123    init_interposition_intf ();
1124
1125  TprintfT (DBG_LT1, "pthread_create interposition called\n");
1126
1127  if (dispatch_mode != DISPATCH_ON)
1128    {
1129#if ARCH(Intel) && WSIZE(32)
1130      return (real_pthread_create) (thread, attr, func, arg);
1131#else
1132      return CALL_REAL (pthread_create)(thread, attr, func, arg);
1133#endif
1134    }
1135  CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
1136
1137  if (cargs == NULL)
1138    {
1139#if ARCH(Intel) && WSIZE(32)
1140      return (real_pthread_create) (thread, attr, func, arg);
1141#else
1142      return CALL_REAL (pthread_create)(thread, attr, func, arg);
1143#endif
1144    }
1145  cargs->func = func;
1146  cargs->arg = arg;
1147  cargs->stack = NULL;
1148  cargs->isPthread = 1;
1149  int ret = -1;
1150#if ARCH(Intel) && WSIZE(32)
1151  ret = (real_pthread_create) (thread, attr, &collector_root, cargs);
1152#else
1153  ret = CALL_REAL (pthread_create)(thread, attr, &collector_root, cargs);
1154#endif
1155  if (ret)
1156    __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1157  TprintfT (DBG_LT1, "pthread_create returning %d\n", ret);
1158  return ret;
1159}
1160
1161int
1162__collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
1163			       va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1164{
1165  if (NULL_PTR (clone))
1166    init_interposition_intf ();
1167  TprintfT (0, "clone thread interposing\n");
1168  pid_t * ptid = NULL;
1169  struct user_desc * tls = NULL;
1170  pid_t * ctid = NULL;
1171  int num_args = 0;
1172  if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
1173    {
1174      ptid = va_arg (va, pid_t *);
1175      tls = va_arg (va, struct user_desc*);
1176      ctid = va_arg (va, pid_t *);
1177      num_args = 3;
1178    }
1179  else if (flags & CLONE_SETTLS)
1180    {
1181      ptid = va_arg (va, pid_t *);
1182      tls = va_arg (va, struct user_desc*);
1183      num_args = 2;
1184    }
1185  else if (flags & CLONE_PARENT_SETTID)
1186    {
1187      ptid = va_arg (va, pid_t *);
1188      num_args = 1;
1189    }
1190  int ret = 0;
1191  if (dispatch_mode != DISPATCH_ON)
1192    {
1193      switch (num_args)
1194	{
1195	case 3:
1196	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1197	  break;
1198	case 2:
1199	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1200	  break;
1201	case 1:
1202	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1203	  break;
1204	default:
1205	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1206	  break;
1207	}
1208      return ret;
1209    }
1210  CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
1211  if (cargs == NULL)
1212    {
1213      switch (num_args)
1214	{
1215	case 3:
1216	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1217	  break;
1218	case 2:
1219	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1220	  break;
1221	case 1:
1222	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1223	  break;
1224	default:
1225	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1226	  break;
1227	}
1228      return ret;
1229    }
1230
1231  cargs->func = (void *(*)(void*))fn;
1232  cargs->arg = arg;
1233  cargs->stack = child_stack;
1234  cargs->isPthread = 0;
1235
1236  switch (num_args)
1237    {
1238    case 3:
1239      ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid);
1240      break;
1241    case 2:
1242      ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls);
1243      break;
1244    case 1:
1245      ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid);
1246      break;
1247    default:
1248      ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs);
1249      break;
1250    }
1251
1252  if (ret < 0)
1253    __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1254  TprintfT (DBG_LT1, "clone thread returning %d\n", ret);
1255  return ret;
1256}
1257
1258// weak symbols:
1259int sigprocmask () __attribute__ ((weak, alias ("__collector_sigprocmask")));
1260int thr_sigsetmask () __attribute__ ((weak, alias ("__collector_thr_sigsetmask")));
1261int setitimer () __attribute__ ((weak, alias ("_setitimer")));
1262