1 1.1 christos /* This testcase is part of GDB, the GNU debugger. 2 1.1 christos 3 1.1.1.4 christos Copyright 2018-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 1.1 christos 18 1.1 christos /* This file contains a library that can be preloaded into GDB on Linux 19 1.1 christos using the LD_PRELOAD technique. 20 1.1 christos 21 1.1 christos The library intercepts calls to WAITPID and SIGSUSPEND in order to 22 1.1.1.5 christos simulate the behavior of a heavily loaded kernel. 23 1.1 christos 24 1.1 christos When GDB wants to stop all threads in an inferior each thread is sent a 25 1.1 christos SIGSTOP, GDB will then wait for the signal to be received by the thread 26 1.1 christos with a waitpid call. 27 1.1 christos 28 1.1 christos If the kernel is slow in either delivering the signal, or making the 29 1.1 christos result available to the waitpid call then GDB will enter a sigsuspend 30 1.1 christos call in order to wait for the inferior threads to change state, this is 31 1.1 christos signalled to GDB with a SIGCHLD. 32 1.1 christos 33 1.1 christos A bug in GDB meant that in some cases we would deadlock during this 34 1.1 christos process. This was rarely seen as the kernel is usually quick at 35 1.1 christos delivering signals and making the results available to waitpid, so quick 36 1.1 christos that GDB would gather the statuses from all inferior threads in the 37 1.1 christos original pass. 38 1.1 christos 39 1.1 christos The idea in this library is to rate limit calls to waitpid (where pid is 40 1.1 christos -1 and the WNOHANG option is set) so that only 1 per second can return 41 1.1 christos an answer. Any additional calls will report that no threads are 42 1.1.1.5 christos currently ready. This should match the behavior we see on a slow 43 1.1 christos kernel. 44 1.1 christos 45 1.1 christos However, given that usually when using this library, the kernel does 46 1.1 christos have the waitpid result ready this means that the kernel will never send 47 1.1 christos GDB a SIGCHLD. This means that when GDB enters sigsuspend it will block 48 1.1 christos forever. Alternatively, if GDB enters its polling loop the lack of 49 1.1 christos SIGCHLD means that we will never see an event on the child threads. To 50 1.1 christos resolve these problems the library intercepts calls to sigsuspend and 51 1.1 christos forces the call to exit if there is a pending waitpid result. Also, 52 1.1 christos when we know that there's a waitpid result that we've ignored, we create 53 1.1 christos a new thread which, after a short delay, will send GDB a SIGCHLD. */ 54 1.1 christos 55 1.1 christos #define _GNU_SOURCE 56 1.1 christos 57 1.1 christos #include <sys/types.h> 58 1.1 christos #include <sys/wait.h> 59 1.1 christos #include <sys/time.h> 60 1.1 christos #include <stdlib.h> 61 1.1 christos #include <stdio.h> 62 1.1 christos #include <dlfcn.h> 63 1.1 christos #include <string.h> 64 1.1 christos #include <stdarg.h> 65 1.1 christos #include <signal.h> 66 1.1 christos #include <errno.h> 67 1.1 christos #include <pthread.h> 68 1.1 christos #include <unistd.h> 69 1.1 christos 70 1.1 christos /* Logging. */ 71 1.1 christos 72 1.1 christos static void 73 1.1 christos log_msg (const char *fmt, ...) 74 1.1 christos { 75 1.1 christos #ifdef LOGGING 76 1.1 christos va_list ap; 77 1.1 christos 78 1.1 christos va_start (ap, fmt); 79 1.1 christos vfprintf (stderr, fmt, ap); 80 1.1 christos va_end (ap); 81 1.1 christos #endif /* LOGGING */ 82 1.1 christos } 83 1.1 christos 84 1.1 christos /* Error handling, message and exit. */ 85 1.1 christos 86 1.1 christos static void 87 1.1 christos error (const char *fmt, ...) 88 1.1 christos { 89 1.1 christos va_list ap; 90 1.1 christos 91 1.1 christos va_start (ap, fmt); 92 1.1 christos vfprintf (stderr, fmt, ap); 93 1.1 christos va_end (ap); 94 1.1 christos 95 1.1 christos exit (EXIT_FAILURE); 96 1.1 christos } 97 1.1 christos 98 1.1 christos /* Cache the result of a waitpid call that has not been reported back to 99 1.1 christos GDB yet. We only ever cache a single result. Once we have a result 100 1.1 christos cached then later calls to waitpid with the WNOHANG option will return a 101 1.1 christos result of 0. */ 102 1.1 christos 103 1.1 christos static struct 104 1.1 christos { 105 1.1 christos /* Flag to indicate when we have a result cached. */ 106 1.1 christos int cached_p; 107 1.1 christos 108 1.1 christos /* The cached result fields from a waitpid call. */ 109 1.1 christos pid_t pid; 110 1.1 christos int wstatus; 111 1.1 christos } cached_wait_status; 112 1.1 christos 113 1.1 christos /* Lock to hold when modifying SIGNAL_THREAD_ACTIVE_P. */ 114 1.1 christos 115 1.1 christos static pthread_mutex_t thread_creation_lock_obj = PTHREAD_MUTEX_INITIALIZER; 116 1.1 christos #define thread_creation_lock (&thread_creation_lock_obj) 117 1.1 christos 118 1.1 christos /* This flag is only modified while holding the THREAD_CREATION_LOCK mutex. 119 1.1 christos When this flag is true then there is a signal thread alive that will be 120 1.1 christos sending a SIGCHLD at some point in the future. */ 121 1.1 christos 122 1.1 christos static int signal_thread_active_p; 123 1.1 christos 124 1.1 christos /* When we last allowed a waitpid to complete. */ 125 1.1 christos 126 1.1 christos static struct timeval last_waitpid_time = { 0, 0 }; 127 1.1 christos 128 1.1 christos /* The number of seconds that must elapse between calls to waitpid where 129 1.1 christos the pid is -1 and the WNOHANG option is set. If calls occur faster than 130 1.1 christos this then we force a result of 0 to be returned from waitpid. */ 131 1.1 christos 132 1.1 christos #define WAITPID_MIN_TIME (1) 133 1.1 christos 134 1.1 christos /* Return true (non-zero) if we should skip this call to waitpid, or false 135 1.1 christos (zero) if this waitpid call should be handled with a call to the "real" 136 1.1 christos waitpid function. Allows 1 waitpid call per second. */ 137 1.1 christos 138 1.1 christos static int 139 1.1 christos should_skip_waitpid (void) 140 1.1 christos { 141 1.1 christos struct timeval *tv = &last_waitpid_time; 142 1.1 christos if (tv->tv_sec == 0) 143 1.1 christos { 144 1.1 christos if (gettimeofday (tv, NULL) < 0) 145 1.1 christos error ("error: gettimeofday failed\n"); 146 1.1 christos return 0; /* Don't skip. */ 147 1.1 christos } 148 1.1 christos else 149 1.1 christos { 150 1.1 christos struct timeval new_tv; 151 1.1 christos 152 1.1 christos if (gettimeofday (&new_tv, NULL) < 0) 153 1.1 christos error ("error: gettimeofday failed\n"); 154 1.1 christos 155 1.1 christos if ((new_tv.tv_sec - tv->tv_sec) < WAITPID_MIN_TIME) 156 1.1 christos return 1; /* Skip. */ 157 1.1 christos 158 1.1 christos *tv = new_tv; 159 1.1 christos } 160 1.1 christos 161 1.1 christos /* Don't skip. */ 162 1.1 christos return 0; 163 1.1 christos } 164 1.1 christos 165 1.1 christos /* Perform a real waitpid call. */ 166 1.1 christos 167 1.1 christos static pid_t 168 1.1 christos real_waitpid (pid_t pid, int *wstatus, int options) 169 1.1 christos { 170 1.1 christos typedef pid_t (*fptr_t) (pid_t, int *, int); 171 1.1 christos static fptr_t real_func = NULL; 172 1.1 christos 173 1.1 christos if (real_func == NULL) 174 1.1 christos { 175 1.1 christos real_func = dlsym (RTLD_NEXT, "waitpid"); 176 1.1 christos if (real_func == NULL) 177 1.1 christos error ("error: failed to find real waitpid\n"); 178 1.1 christos } 179 1.1 christos 180 1.1 christos return (*real_func) (pid, wstatus, options); 181 1.1 christos } 182 1.1 christos 183 1.1 christos /* Thread worker created when we cache a waitpid result. Delays for a 184 1.1 christos short period of time and then sends SIGCHLD to the GDB process. This 185 1.1 christos should trigger GDB to call waitpid again, at which point we will make 186 1.1 christos the cached waitpid result available. */ 187 1.1 christos 188 1.1 christos static void* 189 1.1 christos send_sigchld_thread (void *arg) 190 1.1 christos { 191 1.1 christos /* Delay one second longer than WAITPID_MIN_TIME so that there can be no 192 1.1 christos chance that a call to SHOULD_SKIP_WAITPID will return true once the 193 1.1 christos SIGCHLD is delivered and handled. */ 194 1.1 christos sleep (WAITPID_MIN_TIME + 1); 195 1.1 christos 196 1.1 christos pthread_mutex_lock (thread_creation_lock); 197 1.1 christos signal_thread_active_p = 0; 198 1.1 christos 199 1.1 christos if (cached_wait_status.cached_p) 200 1.1 christos { 201 1.1 christos log_msg ("signal-thread: sending SIGCHLD\n"); 202 1.1 christos kill (getpid (), SIGCHLD); 203 1.1 christos } 204 1.1 christos 205 1.1 christos pthread_mutex_unlock (thread_creation_lock); 206 1.1 christos return NULL; 207 1.1 christos } 208 1.1 christos 209 1.1 christos /* The waitpid entry point function. */ 210 1.1 christos 211 1.1 christos pid_t 212 1.1 christos waitpid (pid_t pid, int *wstatus, int options) 213 1.1 christos { 214 1.1 christos log_msg ("waitpid: waitpid (%d, %p, 0x%x)\n", pid, wstatus, options); 215 1.1 christos 216 1.1 christos if ((options & WNOHANG) != 0 217 1.1 christos && pid == -1 218 1.1 christos && should_skip_waitpid ()) 219 1.1 christos { 220 1.1 christos if (!cached_wait_status.cached_p) 221 1.1 christos { 222 1.1 christos /* Do the waitpid call, but hold the result back. */ 223 1.1 christos pid_t tmp_pid; 224 1.1 christos int tmp_wstatus; 225 1.1 christos 226 1.1 christos tmp_pid = real_waitpid (-1, &tmp_wstatus, options); 227 1.1 christos if (tmp_pid > 0) 228 1.1 christos { 229 1.1 christos log_msg ("waitpid: delaying waitpid result (pid = %d)\n", 230 1.1 christos tmp_pid); 231 1.1 christos 232 1.1 christos /* Cache the result. */ 233 1.1 christos cached_wait_status.pid = tmp_pid; 234 1.1 christos cached_wait_status.wstatus = tmp_wstatus; 235 1.1 christos cached_wait_status.cached_p = 1; 236 1.1 christos 237 1.1 christos /* Is there a thread around that will be sending a signal in 238 1.1 christos the near future? The prevents us from creating one 239 1.1 christos thread per call to waitpid when the calls occur in a 240 1.1 christos sequence. */ 241 1.1 christos pthread_mutex_lock (thread_creation_lock); 242 1.1 christos if (!signal_thread_active_p) 243 1.1 christos { 244 1.1 christos sigset_t old_ss, new_ss; 245 1.1 christos pthread_t thread_id; 246 1.1 christos pthread_attr_t attr; 247 1.1 christos 248 1.1 christos /* Create the new signal sending thread in detached 249 1.1 christos state. This means that the thread doesn't need to be 250 1.1 christos pthread_join'ed. Which is fine as there's no result 251 1.1 christos we care about. */ 252 1.1 christos pthread_attr_init (&attr); 253 1.1 christos pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 254 1.1 christos 255 1.1 christos /* Ensure the signal sending thread has all signals 256 1.1 christos blocked. We don't want any signals to GDB to be 257 1.1 christos handled in that thread. */ 258 1.1 christos sigfillset (&new_ss); 259 1.1 christos sigprocmask (SIG_BLOCK, &new_ss, &old_ss); 260 1.1 christos 261 1.1 christos log_msg ("waitpid: spawn thread to signal us\n"); 262 1.1 christos if (pthread_create (&thread_id, &attr, 263 1.1 christos send_sigchld_thread, NULL) != 0) 264 1.1 christos error ("error: pthread_create failed\n"); 265 1.1 christos 266 1.1 christos signal_thread_active_p = 1; 267 1.1 christos sigprocmask (SIG_SETMASK, &old_ss, NULL); 268 1.1 christos pthread_attr_destroy (&attr); 269 1.1 christos } 270 1.1 christos 271 1.1 christos pthread_mutex_unlock (thread_creation_lock); 272 1.1 christos } 273 1.1 christos } 274 1.1 christos 275 1.1 christos log_msg ("waitpid: skipping\n"); 276 1.1 christos return 0; 277 1.1 christos } 278 1.1 christos 279 1.1 christos /* If we have a cached result that is a suitable reply for this call to 280 1.1 christos waitpid then send that cached result back now. */ 281 1.1 christos if (cached_wait_status.cached_p 282 1.1 christos && (pid == -1 || pid == cached_wait_status.pid)) 283 1.1 christos { 284 1.1 christos pid_t pid; 285 1.1 christos 286 1.1 christos pid = cached_wait_status.pid; 287 1.1 christos log_msg ("waitpid: return cached result (%d)\n", pid); 288 1.1 christos *wstatus = cached_wait_status.wstatus; 289 1.1 christos cached_wait_status.cached_p = 0; 290 1.1 christos return pid; 291 1.1 christos } 292 1.1 christos 293 1.1 christos log_msg ("waitpid: real waitpid call\n"); 294 1.1 christos return real_waitpid (pid, wstatus, options); 295 1.1 christos } 296 1.1 christos 297 1.1 christos /* Perform a real sigsuspend call. */ 298 1.1 christos 299 1.1 christos static int 300 1.1 christos real_sigsuspend (const sigset_t *mask) 301 1.1 christos { 302 1.1 christos typedef int (*fptr_t) (const sigset_t *); 303 1.1 christos static fptr_t real_func = NULL; 304 1.1 christos 305 1.1 christos if (real_func == NULL) 306 1.1 christos { 307 1.1 christos real_func = dlsym (RTLD_NEXT, "sigsuspend"); 308 1.1 christos if (real_func == NULL) 309 1.1 christos error ("error: failed to find real sigsuspend\n"); 310 1.1 christos } 311 1.1 christos 312 1.1 christos return (*real_func) (mask); 313 1.1 christos } 314 1.1 christos 315 1.1 christos /* The sigsuspend entry point function. */ 316 1.1 christos 317 1.1 christos int 318 1.1 christos sigsuspend (const sigset_t *mask) 319 1.1 christos { 320 1.1 christos log_msg ("sigsuspend: sigsuspend (0x%p)\n", ((void *) mask)); 321 1.1 christos 322 1.1 christos /* If SIGCHLD is _not_ in MASK, and is therefore deliverable, then if we 323 1.1 christos have a pending wait status pretend that a signal arrived. We will 324 1.1 christos have a thread alive that is going to deliver a signal but doing this 325 1.1 christos will boost the speed as we don't have to wait for a signal. If the 326 1.1 christos signal ends up being delivered then it should be harmless, we'll just 327 1.1 christos perform an additional waitpid call. */ 328 1.1 christos if (!sigismember (mask, SIGCHLD)) 329 1.1 christos { 330 1.1 christos if (cached_wait_status.cached_p) 331 1.1 christos { 332 1.1 christos log_msg ("sigsuspend: interrupt for cached waitstatus\n"); 333 1.1 christos last_waitpid_time.tv_sec = 0; 334 1.1 christos last_waitpid_time.tv_usec = 0; 335 1.1 christos errno = EINTR; 336 1.1 christos return -1; 337 1.1 christos } 338 1.1 christos } 339 1.1 christos 340 1.1 christos log_msg ("sigsuspend: real sigsuspend call\n"); 341 1.1 christos return real_sigsuspend (mask); 342 1.1 christos } 343