1/* Test dwfl_linux_proc_attach works without any modules.
2   Copyright (C) 2015 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19#include <inttypes.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <errno.h>
23#include <unistd.h>
24#ifdef __linux__
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/user.h>
28#include <fcntl.h>
29#include <string.h>
30#include ELFUTILS_HEADER(dwfl)
31#include <pthread.h>
32#endif
33#include "system.h"
34
35#ifndef __linux__
36int
37main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
38{
39  printf ("dwfl_linux_proc_attach unsupported.\n");
40  return 77;
41}
42#else /* __linux__ */
43
44static pthread_t thread1;
45static pthread_t thread2;
46
47static void *
48sleeper (void* d __attribute__ ((unused)))
49{
50  sleep (60);
51  return NULL;
52}
53
54static char *debuginfo_path = NULL;
55
56static const Dwfl_Callbacks proc_callbacks =
57  {
58    .find_elf = dwfl_linux_proc_find_elf,
59    .find_debuginfo = dwfl_standard_find_debuginfo,
60    .debuginfo_path = &debuginfo_path,
61  };
62
63static int
64thread_callback (Dwfl_Thread *thread, void *thread_arg)
65{
66  int *threads = (int *) thread_arg;
67  pid_t tid = dwfl_thread_tid (thread);
68  printf ("thread tid: %d\n", tid);
69  (*threads)++;
70
71  return DWARF_CB_OK;
72}
73
74int
75main (int argc __attribute__ ((unused)),
76      char **argv __attribute__ ((unused)))
77{
78  /* Create two extra threads to iterate through.  */
79  int err;
80  if ((err = pthread_create (&thread1, NULL, sleeper, NULL)) != 0)
81    error (-1, err, "Couldn't create thread1");
82  if ((err = pthread_create (&thread2, NULL, sleeper, NULL)) != 0)
83    error (-1, err, "Couldn't create thread2");
84
85  Dwfl *dwfl = dwfl_begin (&proc_callbacks);
86  if (dwfl == NULL)
87    error (-1, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
88
89  pid_t pid = getpid ();
90  /* This used to fail, since we don't have any modules yet.  */
91  if (dwfl_linux_proc_attach (dwfl, pid, false) < 0)
92    error (-1, 0, "dwfl_linux_proc_attach pid %d: %s", pid,
93	   dwfl_errmsg (-1));
94
95  /* Did we see all 3 threads?  */
96  int threads = 0;
97  if (dwfl_getthreads (dwfl, thread_callback, &threads) != DWARF_CB_OK)
98    error (-1, 0, "dwfl_getthreads failed: %s", dwfl_errmsg (-1));
99
100  dwfl_end (dwfl);
101
102  pthread_cancel (thread1);
103  pthread_cancel (thread2);
104  pthread_join (thread1, NULL);
105  pthread_join (thread2, NULL);
106
107  return (threads == 3) ? 0 : -1;
108}
109
110/* HACK. This is a simple workaround for a combination of old glibc
111   and valgrind. libdw will try to dlopen libdebuginfod this causes
112   some unsuppressable memory leak warnings when the process is
113   multi-threaded under valgrind because of some bad backtraces.
114   So simply override dlopen and always return NULL so libdebuginfod
115   (and libcurl) are never loaded.  This test doesn't rely on
116   libdebuginfod anyway.  */
117void *dlopen (void)
118{
119  return NULL;
120}
121
122#endif /* __linux__ */
123