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