15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2005-2007, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Markus Gutschke
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/linuxthreads.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef THREADS
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __cplusplus
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sched.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/linux_syscall_support.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/thread_lister.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef CLONE_UNTRACED
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CLONE_UNTRACED 0x00800000
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Synchronous signals that should not be blocked while in the lister thread.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int sync_signals[]  = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     SIGXCPU, SIGXFSZ };
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* itoa() is not a standard function, and we cannot safely call printf()
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * after suspending threads. So, we just implement our own copy. A
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * recursive approach is the easiest here.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *local_itoa(char *buf, int i) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i < 0) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf++ = '-';
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return local_itoa(buf, -i);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i >= 10)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf = local_itoa(buf, i/10);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf++ = (i%10) + '0';
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *buf   = '\000';
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buf;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Wrapper around clone() that runs "fn" on the same stack as the
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * caller! Unlike fork(), the cloned thread shares the same address space.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The caller must be careful to use only minimal amounts of stack until
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the cloned thread has returned.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * There is a good chance that the cloned thread and the caller will share
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the same copy of errno!
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __GNUC__
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 || __GNUC__ > 3
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Try to force this function into a separate stack frame, and make sure
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that arguments are passed on the stack.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int local_clone (int (*fn)(void *), void *arg, ...)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __attribute__ ((noinline));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int local_clone (int (*fn)(void *), void *arg, ...) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Leave 4kB of gap between the callers stack and the new clone. This
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * should be more than sufficient for the caller to call waitpid() until
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * the cloned thread terminates.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * It is important that we set the CLONE_UNTRACED flag, because newer
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * versions of "gdb" otherwise attempt to attach to our thread, and will
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * attempt to reap its status codes. This subsequently results in the
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * caller hanging indefinitely in waitpid(), waiting for a change in
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * status that will never happen. By setting the CLONE_UNTRACED flag, we
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * prevent "gdb" from stealing events, but we still expect the thread
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * lister to fail, because it cannot PTRACE_ATTACH to the process that
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * is being debugged. This is OK and the error code will be reported
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * correctly.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sys_clone(fn, (char *)&arg - 4096,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_UNTRACED, arg, 0, 0, 0);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Local substitute for the atoi() function, which is not necessarily safe
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to call once threads are suspended (depending on whether libc looks up
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * locale information,  when executing atoi()).
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int local_atoi(const char *s) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n   = 0;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int neg = *s == '-';
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (neg)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s++;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (*s >= '0' && *s <= '9')
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = 10*n + (*s++ - '0');
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return neg ? -n : n;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Re-runs fn until it doesn't cause EINTR
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Wrap a class around system calls, in order to give us access to
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * a private copy of errno. This only works in C++, but it has the
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * advantage of not needing nested functions, which are a non-standard
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * language extension.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __cplusplus
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class SysCalls {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #define SYS_CPLUSPLUS
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #define SYS_ERRNO     my_errno
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #define SYS_INLINE    inline
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #define SYS_PREFIX    -1
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #undef  SYS_LINUX_SYSCALL_SUPPORT_H
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #include "linux_syscall_support.h"
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SysCalls() : my_errno(0) { }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int my_errno;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERRNO sys.my_errno
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ERRNO my_errno
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Wrapper for open() which is guaranteed to never return EINTR.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int c_open(const char *fname, int flags, int mode) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssize_t rc;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NO_INTR(rc = sys_open(fname, flags, mode));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* abort() is not safely reentrant, and changes it's behavior each time
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * it is called. This means, if the main application ever called abort()
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * we cannot safely call it again. This would happen if we were called
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * from a SIGABRT signal handler in the main application. So, document
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that calling SIGABRT from the thread lister makes it not signal safe
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (and vice-versa).
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Also, since we share address space with the main application, we
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * cannot call abort() from the callback and expect the main application
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to behave correctly afterwards. In fact, the only thing we can do, is
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to terminate the main application with extreme prejudice (aka
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PTRACE_KILL).
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * We set up our own SIGABRT handler to do this.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * In order to find the main application from the signal handler, we
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * need to store information about it in global variables. This is
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * safe, because the main application should be suspended at this
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * time. If the callback ever called ResumeAllProcessThreads(), then
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * we are running a higher risk, though. So, try to avoid calling
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * abort() after calling ResumeAllProcessThreads.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static volatile int *sig_pids, sig_num_threads, sig_proc, sig_marker;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Signal handler to help us recover from dying while we are attached to
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * other threads.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void SignalHandler(int signum, siginfo_t *si, void *data) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sig_pids != NULL) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (signum == SIGABRT) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (sig_num_threads-- > 0) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Not sure if sched_yield is really necessary here, but it does not */
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* hurt, and it might be necessary for the same reasons that we have */
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* to do so in sys_ptrace_detach().                                  */
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys_sched_yield();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys_ptrace(PTRACE_KILL, sig_pids[sig_num_threads], 0, 0);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (sig_num_threads > 0) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResumeAllProcessThreads(sig_num_threads, (int *)sig_pids);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sig_pids = NULL;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sig_marker >= 0)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NO_INTR(sys_close(sig_marker));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sig_marker = -1;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sig_proc >= 0)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NO_INTR(sys_close(sig_proc));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sig_proc = -1;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys__exit(signum == SIGABRT ? 1 : 2);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Try to dirty the stack, and hope that the compiler is not smart enough
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to optimize this function away. Or worse, the compiler could inline the
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * function and permanently allocate the data on the stack.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void DirtyStack(size_t amount) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf[amount];
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(buf, 0, amount);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys_read(-1, buf, amount);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Data structure for passing arguments to the lister thread.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ALT_STACKSIZE (MINSIGSTKSZ + 4096)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ListerParams {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int         result, err;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char        *altstack_mem;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListAllProcessThreadsCallBack callback;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void        *parameter;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list     ap;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ListerThread(struct ListerParams *args) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int                found_parent = 0;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pid_t              clone_pid  = sys_gettid(), ppid = sys_getppid();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char               proc_self_task[80], marker_name[48], *marker_path;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char         *proc_paths[3];
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *const  *proc_path = proc_paths;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int                proc = -1, marker = -1, num_threads = 0;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int                max_threads = 0, sig;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct kernel_stat marker_sb, proc_sb;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stack_t            altstack;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Create "marker" that we can use to detect threads sharing the same
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * address space and the same file handles. By setting the FD_CLOEXEC flag
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * we minimize the risk of misidentifying child processes as threads;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * and since there is still a race condition,  we will filter those out
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * later, anyway.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((marker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0 ||
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys_fcntl(marker, F_SETFD, FD_CLOEXEC) < 0) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  failure:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args->result = -1;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args->err    = errno;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (marker >= 0)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NO_INTR(sys_close(marker));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig_marker = marker = -1;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (proc >= 0)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NO_INTR(sys_close(proc));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig_proc = proc = -1;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys__exit(1);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Compute search paths for finding thread directories in /proc            */
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_itoa(strrchr(strcpy(proc_self_task, "/proc/"), '\000'), ppid);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strcpy(marker_name, proc_self_task);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  marker_path = marker_name + strlen(marker_name);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strcat(proc_self_task, "/task/");
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proc_paths[0] = proc_self_task; /* /proc/$$/task/                          */
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proc_paths[1] = "/proc/";       /* /proc/                                  */
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proc_paths[2] = NULL;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Compute path for marker socket in /proc                                 */
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_itoa(strcpy(marker_path, "/fd/") + 4, marker);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sys_stat(marker_name, &marker_sb) < 0) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto failure;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Catch signals on an alternate pre-allocated stack. This way, we can
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * safely execute the signal handler even if we ran out of memory.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&altstack, 0, sizeof(altstack));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  altstack.ss_sp    = args->altstack_mem;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  altstack.ss_flags = 0;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  altstack.ss_size  = ALT_STACKSIZE;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys_sigaltstack(&altstack, (const stack_t *)NULL);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Some kernels forget to wake up traced processes, when the
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * tracer dies.  So, intercept synchronous signals and make sure
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * that we wake up our tracees before dying. It is the caller's
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * responsibility to ensure that asynchronous signals do not
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * interfere with this function.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sig_marker = marker;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sig_proc   = -1;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (sig = 0; sig < sizeof(sync_signals)/sizeof(*sync_signals); sig++) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct kernel_sigaction sa;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&sa, 0, sizeof(sa));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sa.sa_sigaction_ = SignalHandler;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_sigfillset(&sa.sa_mask);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sa.sa_flags      = SA_ONSTACK|SA_SIGINFO|SA_RESETHAND;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_sigaction(sync_signals[sig], &sa, (struct kernel_sigaction *)NULL);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Read process directories in /proc/...                                   */
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Some kernels know about threads, and hide them in "/proc"
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * (although they are still there, if you know the process
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * id). Threads are moved into a separate "task" directory. We
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * check there first, and then fall back on the older naming
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * convention if necessary.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((sig_proc = proc = c_open(*proc_path, O_RDONLY|O_DIRECTORY, 0)) < 0) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*++proc_path != NULL)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sys_fstat(proc, &proc_sb) < 0)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto failure;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Since we are suspending threads, we cannot call any libc
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * functions that might acquire locks. Most notably, we cannot
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * call malloc(). So, we have to allocate memory on the stack,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * instead. Since we do not know how much memory we need, we
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * make a best guess. And if we guessed incorrectly we retry on
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * a second iteration (by jumping to "detach_threads").
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Unless the number of threads is increasing very rapidly, we
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * should never need to do so, though, as our guestimate is very
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * conservative.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (max_threads < proc_sb.st_nlink + 100)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_threads = proc_sb.st_nlink + 100;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* scope */ {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pid_t pids[max_threads];
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int   added_entries = 0;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sig_num_threads     = num_threads;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sig_pids            = pids;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (;;) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        struct kernel_dirent *entry;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        char buf[4096];
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ssize_t nbytes = sys_getdents(proc, (struct kernel_dirent *)buf,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      sizeof(buf));
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nbytes < 0)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          goto failure;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else if (nbytes == 0) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (added_entries) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /* Need to keep iterating over "/proc" in multiple
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * passes until we no longer find any more threads. This
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * algorithm eventually completes, when all threads have
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * been suspended.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             */
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            added_entries = 0;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sys_lseek(proc, 0, SEEK_SET);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (entry = (struct kernel_dirent *)buf;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             entry < (struct kernel_dirent *)&buf[nbytes];
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             entry = (struct kernel_dirent *)((char *)entry+entry->d_reclen)) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (entry->d_ino != 0) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const char *ptr = entry->d_name;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            pid_t pid;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /* Some kernels hide threads by preceding the pid with a '.'     */
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (*ptr == '.')
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              ptr++;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /* If the directory is not numeric, it cannot be a
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * process/thread
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             */
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (*ptr < '0' || *ptr > '9')
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              continue;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            pid = local_atoi(ptr);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /* Attach (and suspend) all threads                              */
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (pid && pid != clone_pid) {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              struct kernel_stat tmp_sb;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              char fname[entry->d_reclen + 48];
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              strcat(strcat(strcpy(fname, "/proc/"),
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            entry->d_name), marker_path);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              /* Check if the marker is identical to the one we created      */
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if (sys_stat(fname, &tmp_sb) >= 0 &&
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  marker_sb.st_ino == tmp_sb.st_ino) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long i, j;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                /* Found one of our threads, make sure it is no duplicate    */
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                for (i = 0; i < num_threads; i++) {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  /* Linear search is slow, but should not matter much for
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * the typically small number of threads.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   */
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  if (pids[i] == pid) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    /* Found a duplicate; most likely on second pass         */
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    goto next_entry;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                /* Check whether data structure needs growing                */
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (num_threads >= max_threads) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  /* Back to square one, this time with more memory          */
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  NO_INTR(sys_close(proc));
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  goto detach_threads;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                /* Attaching to thread suspends it                           */
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                pids[num_threads++] = pid;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                sig_num_threads     = num_threads;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0,
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               (void *)0) < 0) {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  /* If operation failed, ignore thread. Maybe it
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * just died?  There might also be a race
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * condition with a concurrent core dumper or
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * with a debugger. In that case, we will just
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * make a best effort, rather than failing
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * entirely.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   */
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  num_threads--;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  sig_num_threads = num_threads;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  goto next_entry;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                while (sys_waitpid(pid, (int *)0, __WALL) < 0) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  if (errno != EINTR) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    sys_ptrace_detach(pid);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    num_threads--;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    sig_num_threads = num_threads;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    goto next_entry;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i++ != j ||
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    sys_ptrace(PTRACE_PEEKDATA, pid, &i, &j) || i   != j) {
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  /* Address spaces are distinct, even though both
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * processes show the "marker". This is probably
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   * a forked child process rather than a thread.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   */
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  sys_ptrace_detach(pid);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  num_threads--;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  sig_num_threads = num_threads;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                } else {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  found_parent |= pid == ppid;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  added_entries++;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              }
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_entry:;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NO_INTR(sys_close(proc));
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sig_proc = proc = -1;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* If we failed to find any threads, try looking somewhere else in
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       * /proc. Maybe, threads are reported differently on this system.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       */
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (num_threads > 1 || !*++proc_path) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NO_INTR(sys_close(marker));
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sig_marker = marker = -1;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* If we never found the parent process, something is very wrong.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Most likely, we are running in debugger. Any attempt to operate
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * on the threads would be very incomplete. Let's just report an
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * error to the caller.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!found_parent) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ResumeAllProcessThreads(num_threads, pids);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sys__exit(3);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Now we are ready to call the callback,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * which takes care of resuming the threads for us.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args->result = args->callback(args->parameter, num_threads,
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      pids, args->ap);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args->err = errno;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Callback should have resumed threads, but better safe than sorry  */
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ResumeAllProcessThreads(num_threads, pids)) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          /* Callback forgot to resume at least one thread, report error     */
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          args->err    = EINVAL;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          args->result = -1;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys__exit(0);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detach_threads:
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* Resume all threads prior to retrying the operation                  */
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResumeAllProcessThreads(num_threads, pids);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sig_pids = NULL;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_threads = 0;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sig_num_threads = num_threads;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_threads += 100;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* This function gets the list of all linux threads of the current process
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * passes them to the 'callback' along with the 'parameter' pointer; at the
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * call back call time all the threads are paused via
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PTRACE_ATTACH.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The callback is executed from a separate thread which shares only the
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * address space, the filesystem, and the filehandles with the caller. Most
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notably, it does not share the same pid and ppid; and if it terminates,
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the rest of the application is still there. 'callback' is supposed to do
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * or arrange for ResumeAllProcessThreads. This happens automatically, if
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the thread raises a synchronous signal (e.g. SIGSEGV); asynchronous
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * signals are blocked. If the 'callback' decides to unblock them, it must
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ensure that they cannot terminate the application, or that
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ResumeAllProcessThreads will get called.
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * It is an error for the 'callback' to make any library calls that could
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * acquire locks. Most notably, this means that most system calls have to
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * avoid going through libc. Also, this means that it is not legal to call
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * exit() or abort().
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * We return -1 on error and the return value of 'callback' on success.
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ListAllProcessThreads(void *parameter,
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          ListAllProcessThreadsCallBack callback, ...) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char                   altstack_mem[ALT_STACKSIZE];
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct ListerParams    args;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pid_t                  clone_pid;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int                    dumpable = 1, sig;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct kernel_sigset_t sig_blocked, sig_old;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(args.ap, callback);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If we are short on virtual memory, initializing the alternate stack
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * might trigger a SIGSEGV. Let's do this early, before it could get us
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * into more trouble (i.e. before signal handlers try to use the alternate
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * stack, and before we attach to other threads).
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(altstack_mem, 0, sizeof(altstack_mem));
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Some of our cleanup functions could conceivable use more stack space.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Try to touch the stack right now. This could be defeated by the compiler
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * being too smart for it's own good, so try really hard.
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DirtyStack(32768);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Make this process "dumpable". This is necessary in order to ptrace()
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * after having called setuid().
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dumpable = sys_prctl(PR_GET_DUMPABLE, 0);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dumpable)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_prctl(PR_SET_DUMPABLE, 1);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Fill in argument block for dumper thread                                */
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.result       = -1;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.err          = 0;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.altstack_mem = altstack_mem;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.parameter    = parameter;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.callback     = callback;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Before cloning the thread lister, block all asynchronous signals, as we */
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* are not prepared to handle them.                                        */
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys_sigfillset(&sig_blocked);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (sig = 0; sig < sizeof(sync_signals)/sizeof(*sync_signals); sig++) {
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_sigdelset(&sig_blocked, sync_signals[sig]);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sys_sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old)) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args.err = errno;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args.result = -1;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto failed;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* scope */ {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* After cloning, both the parent and the child share the same instance
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * of errno. We must make sure that at least one of these processes
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * (in our case, the parent) uses modified syscall macros that update
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * a local copy of errno, instead.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #ifdef __cplusplus
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #define sys0_sigprocmask sys.sigprocmask
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #define sys0_waitpid     sys.waitpid
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SysCalls sys;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #else
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int my_errno;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #define SYS_ERRNO        my_errno
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #define SYS_INLINE       inline
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #define SYS_PREFIX       0
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #undef  SYS_LINUX_SYSCALL_SUPPORT_H
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #include "linux_syscall_support.h"
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #endif
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int clone_errno;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clone_pid = local_clone((int (*)(void *))ListerThread, &args);
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clone_errno = errno;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (clone_pid >= 0) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int status, rc;
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while ((rc = sys0_waitpid(clone_pid, &status, __WALL)) < 0 &&
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             ERRNO == EINTR) {
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             /* Keep waiting                                                 */
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (rc < 0) {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.err = ERRNO;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.result = -1;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (WIFEXITED(status)) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (WEXITSTATUS(status)) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          case 0: break;             /* Normal process termination           */
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          case 2: args.err = EFAULT; /* Some fault (e.g. SIGSEGV) detected   */
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  args.result = -1;
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  break;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          case 3: args.err = EPERM;  /* Process is already being traced      */
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  args.result = -1;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  break;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          default:args.err = ECHILD; /* Child died unexpectedly              */
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  args.result = -1;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  break;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (!WIFEXITED(status)) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.err    = EFAULT;        /* Terminated due to an unhandled signal*/
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.result = -1;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args.result = -1;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args.err    = clone_errno;
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Restore the "dumpable" state of the process                             */
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)failed:
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dumpable)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys_prctl(PR_SET_DUMPABLE, dumpable);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(args.ap);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  errno = args.err;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return args.result;
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* This function resumes the list of all linux threads that
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ListAllProcessThreads pauses before giving to its callback.
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The function returns non-zero if at least one thread was
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * suspended and has now been resumed.
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ResumeAllProcessThreads(int num_threads, pid_t *thread_pids) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int detached_at_least_one = 0;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (num_threads-- > 0) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    detached_at_least_one |= sys_ptrace_detach(thread_pids[num_threads]) >= 0;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return detached_at_least_one;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __cplusplus
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
666