1 /* Test case for forgotten hw-watchpoints after fork()-off of a process. 2 3 Copyright 2012-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "watchpoint-fork.h" 21 22 #include <assert.h> 23 #include <unistd.h> 24 #include <sys/wait.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <pthread.h> 28 29 #include <asm/unistd.h> 30 #include <unistd.h> 31 #define gettid() syscall (__NR_gettid) 32 33 /* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP 34 variable. Hit-comments need to be duplicated there to catch both at-stops 35 and behind-stops, depending on the target. */ 36 37 volatile int var; 38 39 void 40 marker (void) 41 { 42 } 43 44 static void 45 empty (void) 46 { 47 } 48 49 static void 50 mark_exit (void) 51 { 52 } 53 54 pthread_t thread; 55 volatile int step; 56 57 static void * 58 start (void *arg) 59 { 60 int i; 61 62 if (step >= 3) 63 goto step_3; 64 65 while (step != 1) 66 { 67 i = pthread_yield (); 68 assert (i == 0); 69 } 70 71 var++; /* validity-thread-B */ 72 empty (); /* validity-thread-B */ 73 step = 2; 74 while (step != 3) 75 { 76 if (step == 99) 77 goto step_99; 78 79 i = pthread_yield (); 80 assert (i == 0); 81 } 82 83 step_3: 84 if (step >= 5) 85 goto step_5; 86 87 var++; /* after-fork1-B */ 88 empty (); /* after-fork1-B */ 89 step = 4; 90 while (step != 5) 91 { 92 if (step == 99) 93 goto step_99; 94 95 i = pthread_yield (); 96 assert (i == 0); 97 } 98 99 step_5: 100 var++; /* after-fork2-B */ 101 empty (); /* after-fork2-B */ 102 return (void *) 5UL; 103 104 step_99: 105 /* We must not get caught here (against a forgotten breakpoint). */ 106 var++; 107 marker (); 108 return (void *) 99UL; 109 } 110 111 int 112 main (void) 113 { 114 int i; 115 void *thread_result; 116 117 #if DEBUG 118 setbuf (stdout, NULL); 119 printf ("main: %d\n", (int) gettid ()); 120 #endif 121 122 /* General hardware breakpoints and watchpoints validity. */ 123 marker (); 124 var++; /* validity-first */ 125 empty (); /* validity-first */ 126 127 i = pthread_create (&thread, NULL, start, NULL); 128 assert (i == 0); 129 130 var++; /* validity-thread-A */ 131 empty (); /* validity-thread-A */ 132 step = 1; 133 while (step != 2) 134 { 135 i = pthread_yield (); 136 assert (i == 0); 137 } 138 139 /* Hardware watchpoints got disarmed here. */ 140 forkoff (1); 141 142 var++; /* after-fork1-A */ 143 empty (); /* after-fork1-A */ 144 step = 3; 145 #ifdef FOLLOW_CHILD 146 /* Spawn new thread as it was deleted in the child of FORK. */ 147 i = pthread_create (&thread, NULL, start, NULL); 148 assert (i == 0); 149 #endif 150 while (step != 4) 151 { 152 i = pthread_yield (); 153 assert (i == 0); 154 } 155 156 /* A sanity check for double hardware watchpoints removal. */ 157 forkoff (2); 158 159 var++; /* after-fork2-A */ 160 empty (); /* after-fork2-A */ 161 step = 5; 162 #ifdef FOLLOW_CHILD 163 /* Spawn new thread as it was deleted in the child of FORK. */ 164 i = pthread_create (&thread, NULL, start, NULL); 165 assert (i == 0); 166 #endif 167 168 i = pthread_join (thread, &thread_result); 169 assert (i == 0); 170 assert (thread_result == (void *) 5UL); 171 172 mark_exit (); 173 return 0; 174 } 175