OSDN Git Service

Fix for PR gdb/1543.
[pf3gnuchains/pf3gnuchains4x.git] / gdb / testsuite / gdb.threads / tls.exp
1 # tls.exp -- Expect script to test thread-local storage
2 # Copyright (C) 1992, 2003, 2007, 2008 Free Software Foundation, Inc.
3
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 set testfile tls
18 set srcfile ${testfile}.c
19 set binfile ${objdir}/${subdir}/${testfile}
20
21 if [istarget "*-*-linux"] then {
22     set target_cflags "-D_MIT_POSIX_THREADS"
23 } else {
24     set target_cflags ""
25 }
26
27 if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
28     return -1
29 }
30
31 ### Compute the value of the a_thread_local variable.
32 proc compute_expected_value {value} {
33     set expected_value 0
34     set i 0
35     while { $i <= $value} {
36         incr expected_value $i
37         incr i
38     }
39     return $expected_value
40 }
41
42 ### Get the value of the variable 'me' for the current thread.
43 proc get_me_variable {tnum} {
44     global expect_out
45     global gdb_prompt
46     global decimal
47
48     set value_of_me -1
49     send_gdb "print me\n"
50     gdb_expect {
51         -re ".*= ($decimal).*\r\n$gdb_prompt $" {
52             set value_of_me $expect_out(1,string)
53             pass "$tnum thread print me"
54         }
55         -re "$gdb_prompt $" {
56             fail "$tnum thread print me"
57         }
58         timeout {
59             fail "$tnum thread print me (timeout)" 
60         }
61     }
62     return ${value_of_me}
63 }
64
65 ### Check the values of the thread local variables in the thread.
66 ### Also check that info address print the right things.
67 proc check_thread_local {number} {
68     set me_variable [get_me_variable $number]
69     set expected_value [compute_expected_value ${me_variable}]
70
71     gdb_test "p a_thread_local" \
72             "= $expected_value" \
73             "${number} thread local storage"
74
75     gdb_test "p another_thread_local" \
76             "= $me_variable" \
77             "${number} another thread local storage"
78
79     gdb_test "info address a_thread_local" \
80             ".*a_thread_local.*a thread-local variable at offset.*" \
81             "${number} info address a_thread_local"
82
83     gdb_test "info address another_thread_local" \
84             ".*another_thread_local.*a thread-local variable at offset.*" \
85             "${number} info address another_thread_local"
86 }
87
88 ### Select a particular thread.
89 proc select_thread {thread} {
90     global gdb_prompt
91
92     send_gdb "thread $thread\n"
93     gdb_expect {
94         -re "\\\[Switching to thread .*\\\].*\r\n$gdb_prompt $" {
95             pass "selected thread: $thread"
96         }
97         -re "$gdb_prompt $" {
98             fail "selected thread: $thread"
99         }
100         timeout {
101             fail "selected thread: $thread (timeout)"
102         }
103     }
104 }
105
106 ### Do a backtrace for the current thread, and check that the 'spin' routine
107 ### is in it. This means we have one of the threads we created, rather
108 ### than the main thread. Record the thread in the spin_threads 
109 ### array. Also remember the level of the 'spin' routine in the backtrace, for 
110 ### later use.
111 proc check_thread_stack {number spin_threads spin_threads_level} {
112     global gdb_prompt
113     global expect_out
114     global decimal
115     global hex
116     upvar $spin_threads tarr
117     upvar $spin_threads_level tarrl
118
119     select_thread $number
120     send_gdb "where\n"
121     gdb_expect {
122         -re ".*(\[0-9\]+)\[ \t\]+$hex in spin \\(vp=(0x\[0-9a-f\]+).*\r\n$gdb_prompt $" {
123             if {[info exists tarr($number)]} {
124                 fail "backtrace of thread number $number in spin"
125             } else {
126                 pass "backtrace of thread number $number in spin"
127                 set level $expect_out(1,string)
128                 set tarrl($number) $level
129                 set tarr($number) 1
130             }
131         }
132         -re ".*$gdb_prompt $" {
133          set tarr($number) 0
134          set tarrl($number) 0
135          pass "backtrace of thread number $number not relevant"
136         }
137         timeout {
138             fail "backtrace of thread number $number (timeout)" 
139         }
140     }
141 }
142
143 gdb_exit
144 gdb_start
145 gdb_reinitialize_dir $srcdir/$subdir
146
147 gdb_load ${binfile}
148 if ![runto_main] then {
149    fail "Can't run to main"
150    return 0
151 }
152
153 # Set a breakpoint at the "spin" routine to
154 # test the thread local's value.  
155 #
156 gdb_test "b [gdb_get_line_number "here we know tls value"]" \
157          ".*Breakpoint 2.*tls.*"   "set breakpoint at all threads"
158
159 # Set a bp at a point where we know all threads are alive.
160 #
161 gdb_test "b [gdb_get_line_number "still alive"]" \
162          ".*Breakpoint 3.*tls.*" "set breakpoint at synch point"
163
164 # Set a bp at the end to see if all threads are finished.
165 #
166 gdb_test "b [gdb_get_line_number "before exit"]" \
167          ".*Breakpoint 4.*tls.*" "set breakpoint at exit"
168
169 send_gdb "continue\n"
170 gdb_expect {
171     -re ".*Program received signal SIGSEGV.*a_thread_local = 0;.*$gdb_prompt $" {
172         # This is the first symptom if the gcc and binutils versions
173         # in use support TLS, but the system glibc does not.
174         unsupported "continue to first thread: system does not support TLS"
175         return -1
176     }
177     -re ".*Program exited normally.*$gdb_prompt $" {
178         fail "continue to first thread: program runaway"
179     }
180     -re ".*Pass 0 done.*Pass 1 done.*$gdb_prompt $" {
181         fail "continue to first thread: program runaway 2"
182     }
183     -re ".*Breakpoint 2.*tls value.*$gdb_prompt $" {
184         pass "continue to first thread: get to thread"
185     }
186     -re ".*$gdb_prompt $" {
187         fail "continue to first thread: no progress?"
188     }
189     timeout { fail "continue to first thread (timeout)" }
190 }
191
192 gdb_test "info thread" ".*Thread.*spin.*" \
193         "at least one th in spin while stopped at first th"
194
195 check_thread_local "first"
196
197 gdb_test "continue" ".*Breakpoint 2.*tls value.*" "continue to second thread"
198 gdb_test "info thread" "Thread.*spin.*" \
199         "at least one th in spin while stopped at second th"
200
201 check_thread_local "second"
202
203 gdb_test "continue" ".*Breakpoint 2.*tls value.*" "continue to third thread"
204 gdb_test "info thread" ".*Thread.*spin.*" \
205         "at least one th in spin while stopped at third th"
206
207 check_thread_local "third"
208
209 gdb_test "continue" ".*Breakpoint 3.*still alive.*" "continue to synch point"
210
211 set no_of_threads 0
212 send_gdb "info thread\n"
213 gdb_expect {
214         -re "^info thread\[ \t\r\n\]+(\[0-9\]+) Thread.*$gdb_prompt $" {
215            set no_of_threads $expect_out(1,string)
216            pass "get number of threads"
217         }
218         -re "$gdb_prompt $" {
219             fail "get number of threads"
220         }
221         timeout {
222             fail "get number of threads (timeout)"
223         }
224 }
225
226 array set spin_threads {}
227 unset spin_threads
228 array set spin_threads_level {}
229 unset spin_threads_level
230
231 # For each thread check its backtrace to see if it is stopped at the
232 # spin routine. 
233 for {set i 1} {$i <= $no_of_threads} {incr i} {
234     check_thread_stack $i spin_threads spin_threads_level
235 }
236
237 ### Loop through the threads and check the values of the tls variables.
238 ### keep track of how many threads we find in the spin routine.
239 set thrs_in_spin 0
240 foreach i [array names spin_threads] {
241     if {$spin_threads($i) == 1} {
242       incr thrs_in_spin
243       select_thread $i
244       set level $spin_threads_level($i)
245       # We expect to be in sem_wait, but if the thread has not yet
246       # been scheduled, we might be in sem_post still.  We could be at
247       # any intermediate point in spin, too, but that is much less
248       # likely.
249       gdb_test "up $level" ".*spin.*sem_(wait|post).*" "thread $i up"
250       check_thread_local $i 
251     }
252 }
253
254 if {$thrs_in_spin == 0} {
255   fail "No thread backtrace reported spin (vsyscall kernel problem?)"
256 }
257
258 gdb_test "continue" ".*Breakpoint 4.*before exit.*" "threads exited"
259
260 send_gdb "info thread\n" 
261 gdb_expect {
262     -re ".* 1 Thread.*2 Thread.*$gdb_prompt $" {
263         fail "Too many threads left at end"
264     }
265     -re ".*\\\* 1 Thread.*main.*$gdb_prompt $" {
266         pass "Expect only base thread at end"
267     }
268     -re ".*No stack.*$gdb_prompt $" {
269         fail "runaway at end"
270     }
271     -re ".*$gdb_prompt $" {
272         fail "mess at end"
273     }
274     timeout { fail "at end (timeout)" }
275 }
276
277 # Start over and do some "info address" stuff
278 #
279 runto spin
280
281 gdb_test "info address a_global" \
282         ".*a_global.*static storage at address.*" "info address a_global"
283
284 setup_kfail "gdb/1294" "*-*-*"
285 gdb_test "info address me" ".*me.*is a variable at offset.*" "info address me"
286
287 # Done!
288 #
289 gdb_exit
290
291 return 0