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__
36 int
main(int argc,char ** argv)37 main (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
44 static pthread_t thread1;
45 static pthread_t thread2;
46
47 static void *
sleeper(void * d)48 sleeper (void* d __attribute__ ((unused)))
49 {
50 sleep (60);
51 return NULL;
52 }
53
54 static char *debuginfo_path = NULL;
55
56 static 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
63 static int
thread_callback(Dwfl_Thread * thread,void * thread_arg)64 thread_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
74 int
main(int argc,char ** argv)75 main (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. */
dlopen(void)117 void *dlopen (void)
118 {
119 return NULL;
120 }
121
122 #endif /* __linux__ */
123