1 /* Test case for forgotten hw-watchpoints after fork()-off of a process. 2 3 Copyright 2012-2015 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 <assert.h> 21 #include <unistd.h> 22 #include <sys/wait.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 26 /* pthread_yield is a GNU extension. */ 27 #define _GNU_SOURCE 28 #include <pthread.h> 29 30 #include <asm/unistd.h> 31 #include <unistd.h> 32 #define gettid() syscall (__NR_gettid) 33 34 #include "watchpoint-fork.h" 35 36 /* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP 37 variable. Hit-comments need to be duplicated there to catch both at-stops 38 and behind-stops, depending on the target. */ 39 40 volatile int var; 41 42 void 43 marker (void) 44 { 45 } 46 47 static void 48 empty (void) 49 { 50 } 51 52 static void 53 mark_exit (void) 54 { 55 } 56 57 pthread_t thread; 58 volatile int step; 59 60 static void * 61 start (void *arg) 62 { 63 int i; 64 65 if (step >= 3) 66 goto step_3; 67 68 while (step != 1) 69 { 70 i = pthread_yield (); 71 assert (i == 0); 72 } 73 74 var++; /* validity-thread-B */ 75 empty (); /* validity-thread-B */ 76 step = 2; 77 while (step != 3) 78 { 79 if (step == 99) 80 goto step_99; 81 82 i = pthread_yield (); 83 assert (i == 0); 84 } 85 86 step_3: 87 if (step >= 5) 88 goto step_5; 89 90 var++; /* after-fork1-B */ 91 empty (); /* after-fork1-B */ 92 step = 4; 93 while (step != 5) 94 { 95 if (step == 99) 96 goto step_99; 97 98 i = pthread_yield (); 99 assert (i == 0); 100 } 101 102 step_5: 103 var++; /* after-fork2-B */ 104 empty (); /* after-fork2-B */ 105 return (void *) 5UL; 106 107 step_99: 108 /* We must not get caught here (against a forgotten breakpoint). */ 109 var++; 110 marker (); 111 return (void *) 99UL; 112 } 113 114 int 115 main (void) 116 { 117 int i; 118 void *thread_result; 119 120 setbuf (stdout, NULL); 121 printf ("main: %d\n", (int) gettid ()); 122 123 /* General hardware breakpoints and watchpoints validity. */ 124 marker (); 125 var++; /* validity-first */ 126 empty (); /* validity-first */ 127 128 i = pthread_create (&thread, NULL, start, NULL); 129 assert (i == 0); 130 131 var++; /* validity-thread-A */ 132 empty (); /* validity-thread-A */ 133 step = 1; 134 while (step != 2) 135 { 136 i = pthread_yield (); 137 assert (i == 0); 138 } 139 140 /* Hardware watchpoints got disarmed here. */ 141 forkoff (1); 142 143 var++; /* after-fork1-A */ 144 empty (); /* after-fork1-A */ 145 step = 3; 146 #ifdef FOLLOW_CHILD 147 /* Spawn new thread as it was deleted in the child of FORK. */ 148 i = pthread_create (&thread, NULL, start, NULL); 149 assert (i == 0); 150 #endif 151 while (step != 4) 152 { 153 i = pthread_yield (); 154 assert (i == 0); 155 } 156 157 /* A sanity check for double hardware watchpoints removal. */ 158 forkoff (2); 159 160 var++; /* after-fork2-A */ 161 empty (); /* after-fork2-A */ 162 step = 5; 163 #ifdef FOLLOW_CHILD 164 /* Spawn new thread as it was deleted in the child of FORK. */ 165 i = pthread_create (&thread, NULL, start, NULL); 166 assert (i == 0); 167 #endif 168 169 i = pthread_join (thread, &thread_result); 170 assert (i == 0); 171 assert (thread_result == (void *) 5UL); 172 173 mark_exit (); 174 return 0; 175 } 176