1 /* Test case for forgotten hw-watchpoints after fork()-off of a process. 2 3 Copyright 2012-2019 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 setbuf (stdout, NULL); 118 printf ("main: %d\n", (int) gettid ()); 119 120 /* General hardware breakpoints and watchpoints validity. */ 121 marker (); 122 var++; /* validity-first */ 123 empty (); /* validity-first */ 124 125 i = pthread_create (&thread, NULL, start, NULL); 126 assert (i == 0); 127 128 var++; /* validity-thread-A */ 129 empty (); /* validity-thread-A */ 130 step = 1; 131 while (step != 2) 132 { 133 i = pthread_yield (); 134 assert (i == 0); 135 } 136 137 /* Hardware watchpoints got disarmed here. */ 138 forkoff (1); 139 140 var++; /* after-fork1-A */ 141 empty (); /* after-fork1-A */ 142 step = 3; 143 #ifdef FOLLOW_CHILD 144 /* Spawn new thread as it was deleted in the child of FORK. */ 145 i = pthread_create (&thread, NULL, start, NULL); 146 assert (i == 0); 147 #endif 148 while (step != 4) 149 { 150 i = pthread_yield (); 151 assert (i == 0); 152 } 153 154 /* A sanity check for double hardware watchpoints removal. */ 155 forkoff (2); 156 157 var++; /* after-fork2-A */ 158 empty (); /* after-fork2-A */ 159 step = 5; 160 #ifdef FOLLOW_CHILD 161 /* Spawn new thread as it was deleted in the child of FORK. */ 162 i = pthread_create (&thread, NULL, start, NULL); 163 assert (i == 0); 164 #endif 165 166 i = pthread_join (thread, &thread_result); 167 assert (i == 0); 168 assert (thread_result == (void *) 5UL); 169 170 mark_exit (); 171 return 0; 172 } 173