1# Copyright 1997-2015 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16if { [is_remote target] || ![isnative] } then { 17 continue 18} 19 20# Until "catch exec" is implemented on other targets... 21# 22if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then { 23 continue 24} 25 26standard_testfile foll-exec.c 27 28set testfile2 "execd-prog" 29set srcfile2 ${testfile2}.c 30set binfile2 [standard_output_file ${testfile2}] 31 32set compile_options debug 33set dirname [relative_filename [pwd] [file dirname $binfile]] 34lappend compile_options "additional_flags=-DBASEDIR=\"$dirname\"" 35 36# build the first test case 37if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable $compile_options] != "" } { 38 untested foll-exec.exp 39 return -1 40} 41 42if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $compile_options] != "" } { 43 untested foll-exec.exp 44 return -1 45} 46 47proc zap_session {} { 48 global gdb_prompt 49 global binfile 50 51 send_gdb "kill\n" 52 gdb_expect { 53 -re ".*Kill the program being debugged.*y or n. $" { 54 gdb_test_no_output "y" "" 55 send_gdb "file $binfile\n" 56 gdb_expect { 57 -re ".*Load new symbol table from.*y or n. $" { 58 send_gdb "y\n" 59 gdb_expect { 60 -re "Reading symbols from.*$gdb_prompt $" {} 61 timeout { fail "loading symbols (timeout)"; return } 62 } 63 } 64 -re ".*gdb_prompt $" {} 65 timeout { fail "loading symbols (timeout)"; return } 66 } 67 } 68 -re ".*$gdb_prompt $" {} 69 timeout { fail "killing inferior (timeout)" ; return } 70 } 71} 72 73proc do_exec_tests {} { 74 global gdb_prompt 75 global binfile 76 global srcfile 77 global srcfile2 78 global testfile 79 global testfile2 80 81 # Start the program running, and stop at main. 82 # 83 if ![runto_main] then { 84 perror "Couldn't run ${testfile}" 85 return 86 } 87 88 # Verify that the system supports "catch exec". 89 gdb_test "catch exec" "Catchpoint \[0-9\]* \\(exec\\)" "insert first exec catchpoint" 90 set has_exec_catchpoints 0 91 gdb_test_multiple "continue" "continue to first exec catchpoint" { 92 -re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" { 93 unsupported "continue to first exec catchpoint" 94 } 95 -re ".*Catchpoint.*$gdb_prompt $" { 96 set has_exec_catchpoints 1 97 pass "continue to first exec catchpoint" 98 } 99 } 100 101 if {$has_exec_catchpoints == 0} { 102 unsupported "exec catchpoints" 103 return 104 } 105 106 zap_session 107 108 # Start the program running, and stop at main. 109 # 110 if ![runto_main] then { 111 perror "Couldn't run ${testfile}" 112 return 113 } 114 115 # Verify that we can see various global and local variables 116 # in this program, and that they have expected values. Some 117 # of these variables are also declared in the program we'll 118 # exec in a moment. 119 # 120 send_gdb "next 3\n" 121 gdb_expect { 122 -re "execlp \\(.*$gdb_prompt $"\ 123 {pass "step to exec call"} 124 -re "$gdb_prompt $" {fail "step to exec call"} 125 timeout {fail "(timeout) step to exec call"} 126 } 127 send_gdb "print global_i\n" 128 gdb_expect { 129 -re ".* = 100.*$gdb_prompt $"\ 130 {pass "print follow-exec/global_i"} 131 -re "$gdb_prompt $" {fail "print follow-exec/global_i"} 132 timeout {fail "(timeout) print follow-exec/global_i"} 133 } 134 send_gdb "print local_j\n" 135 gdb_expect { 136 -re ".* = 101.*$gdb_prompt $"\ 137 {pass "print follow-exec/local_j"} 138 -re "$gdb_prompt $" {fail "print follow-exec/local_j"} 139 timeout {fail "(timeout) print follow-exec/local_j"} 140 } 141 send_gdb "print local_k\n" 142 gdb_expect { 143 -re ".* = 102.*$gdb_prompt $"\ 144 {pass "print follow-exec/local_k"} 145 -re "$gdb_prompt $" {fail "print follow-exec/local_k"} 146 timeout {fail "(timeout) print follow-exec/local_k"} 147 } 148 149 # Try stepping through an execlp call, without catching it. 150 # We should stop in execd-program, at its first statement. 151 # 152 set execd_line [gdb_get_line_number "after-exec" $srcfile2] 153 send_gdb "next\n" 154 gdb_expect { 155 -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int local_j = argc;.*$gdb_prompt $"\ 156 {pass "step through execlp call"} 157 -re "$gdb_prompt $" {fail "step through execlp call"} 158 timeout {fail "(timeout) step through execlp call"} 159 } 160 161 # Verify that we can see the variables defined in the newly-exec'd 162 # program, and CANNOT see those defined in the exec'ing program. 163 # 164 send_gdb "next\n" 165 gdb_expect { 166 -re "printf \\(.Hello .*$gdb_prompt $"\ 167 {pass "step after execlp call"} 168 -re "$gdb_prompt $" {fail "step after execlp call"} 169 timeout {fail "(timeout) step after execlp call"} 170 } 171 send_gdb "print global_i\n" 172 gdb_expect { 173 -re ".* = 0.*$gdb_prompt $"\ 174 {pass "print execd-program/global_i (after execlp)"} 175 -re "$gdb_prompt $" {fail "print execd-program/global_i (after execlp)"} 176 timeout {fail "(timeout) print execd-program/global_i (after execlp)"} 177 } 178 send_gdb "print local_j\n" 179 gdb_expect { 180 -re ".* = 2.*$gdb_prompt $"\ 181 {pass "print execd-program/local_j (after execlp)"} 182 -re "$gdb_prompt $" {fail "print execd-program/local_j (after execlp)"} 183 timeout {fail "(timeout) print execd-program/local_j (after execlp)"} 184 } 185 send_gdb "print local_k\n" 186 gdb_expect { 187 -re "No symbol \"local_k\" in current context.*$gdb_prompt $"\ 188 {pass "print follow-exec/local_k (after execlp)"} 189 -re "$gdb_prompt $" {fail "print follow-exec/local_k (after execlp)"} 190 timeout {fail "(timeout) print follow-exec/local_k (after execlp)"} 191 } 192 193 # Explicitly kill this program, or a subsequent rerun actually runs 194 # the exec'd program, not the original program... 195 zap_session 196 197 # Start the program running, and stop at main. 198 # 199 if ![runto_main] then { 200 perror "Couldn't run ${testfile} (2nd try)" 201 return 202 } 203 204 # Verify that we can catch an exec event, and then continue 205 # to follow through the exec. (Since there's a breakpoint on 206 # "main", it'll also be transferred to the exec'd program, 207 # and we expect to stop there.) 208 # 209 send_gdb "catch exec\n" 210 gdb_expect { 211 -re "Catchpoint .*(exec).*$gdb_prompt $"\ 212 {pass "set catch exec"} 213 -re "$gdb_prompt $" {fail "set catch exec"} 214 timeout {fail "(timeout) set catch exec"} 215 } 216 217 # Verify that the catchpoint is mentioned in an "info breakpoints", 218 # and further that the catchpoint mentions no program name. 219 # 220 set msg "info shows catchpoint without exec pathname" 221 gdb_test_multiple "info breakpoints" $msg { 222 -re ".*catchpoint.*keep y.*exec\[\n\r\]+$gdb_prompt $" { 223 pass $msg 224 } 225 } 226 227 # DTS CLLbs16760 228 # PA64 doesn't know about $START$ in dld.sl at this point. It should. 229 # - Michael Coulter 230 setup_xfail hppa2.0w-hp-hpux* CLLbs16760 231 send_gdb "continue\n" 232 gdb_expect { 233 -re ".*xecuting new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\ 234 {pass "hit catch exec"} 235 -re "$gdb_prompt $" {fail "hit catch exec"} 236 timeout {fail "(timeout) hit catch exec"} 237 } 238 239 # DTS CLLbs16760 240 # test gets out of sync if previous test fails. 241 gdb_test "bt" ".*" "sync up after possible failure 1" 242 gdb_test "bt" "#0.*" "sync up after possible failure 2" 243 244 # Verify that the catchpoint is mentioned in an "info breakpoints", 245 # and further that the catchpoint managed to capture the exec'd 246 # program's name. 247 # 248 set msg "info shows catchpoint exec pathname" 249 gdb_test_multiple "info breakpoints" $msg { 250 -re ".*catchpoint.*keep y.*exec, program \".*${testfile2}\".*$gdb_prompt $" { 251 pass $msg 252 } 253 } 254 255 # Verify that we can continue from the catchpoint, and land in the 256 # main of the newly-exec'd program. 257 # 258 send_gdb "continue\n" 259 gdb_expect { 260 -re ".*${srcfile2}:${execd_line}.*$gdb_prompt $"\ 261 {pass "continue after hit catch exec"} 262 -re "$gdb_prompt $" {fail "continue after hit catch exec"} 263 timeout {fail "(timeout) continue after hit catch exec"} 264 } 265 266 # Explicitly kill this program, or a subsequent rerun actually runs 267 # the exec'd program, not the original program... 268 zap_session 269 270 # Start the program running, and stop at main. 271 # 272 if ![runto_main] then { 273 perror "Couldn't run ${testfile} (3rd try)" 274 return 275 } 276 277 # Verify that we can follow through follow an execl() 278 # call. (We must jump around earlier exec* calls.) 279 # 280 set tbreak_line [gdb_get_line_number "tbreak-execl" $srcfile] 281 send_gdb "tbreak ${tbreak_line}\n" 282 gdb_expect { 283 -re "Temporary breakpoint .*file .*${srcfile}, line ${tbreak_line}.*$gdb_prompt $"\ 284 {pass "prepare to jump to execl call"} 285 -re "$gdb_prompt $" {fail "prepare to jump to execl call"} 286 timeout {fail "(timeout) prepare to jump to execl call"} 287 } 288 send_gdb "jump ${tbreak_line}\n" 289 gdb_expect { 290 -re "main.* at .*${srcfile}:${tbreak_line}.*$gdb_prompt $"\ 291 {pass "jump to execl call"} 292 -re "$gdb_prompt $" {fail "jump to execl call"} 293 timeout {fail "(timeout) jump to execl call"} 294 } 295 # Note that stepping through an exec call causes the step-count 296 # to be reset to zero. I.e.: you may specify "next 2" at the 297 # call, but you'll actually stop at the first breakpoint set in 298 # the newly-exec'd program, not after the remaining step-count 299 # reaches zero. 300 # 301 send_gdb "next 2\n" 302 gdb_expect { 303 -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int local_j = argc;.*$gdb_prompt $"\ 304 {pass "step through execl call"} 305 -re "$gdb_prompt $" {fail "step through execl call"} 306 timeout {fail "(timeout) step through execl call"} 307 } 308 send_gdb "next\n" 309 gdb_expect { 310 -re "printf \\(.Hello .*$gdb_prompt $"\ 311 {pass "step after execl call"} 312 -re "$gdb_prompt $" {fail "step after execl call"} 313 timeout {fail "(timeout) step after execl call"} 314 } 315 316 # Verify that we can print a local variable (which happens to be 317 # assigned the value of main's argc). 318 # 319 send_gdb "print local_j\n" 320 gdb_expect { 321 -re ".* = 3.*$gdb_prompt $"\ 322 {pass "print execd-program/local_j (after execl)"} 323 -re "$gdb_prompt $" {fail "print execd-program/local_j (after execl)"} 324 timeout {fail "(timeout) print execd-program/local_j (after execl)"} 325 } 326 327 # Explicitly kill this program, or a subsequent rerun actually runs 328 # the exec'd program, not the original program... 329 zap_session 330 331 # Start the program running, and stop at main. 332 # 333 if ![runto_main] then { 334 perror "Couldn't run ${testfile} (4th try)" 335 return 336 } 337 338 # Verify that we can follow through follow an execv() 339 # call. (We must jump around earlier exec* calls.) 340 # 341 set tbreak_line [gdb_get_line_number "tbreak-execv"] 342 send_gdb "tbreak ${tbreak_line}\n" 343 gdb_expect { 344 -re "Temporary breakpoint .*file .*${srcfile}, line ${tbreak_line}.*$gdb_prompt $"\ 345 {pass "prepare to jump to execv call"} 346 -re "$gdb_prompt $" {fail "prepare to jump to execv call"} 347 timeout {fail "(timeout) prepare to jump to execv call"} 348 } 349 send_gdb "jump ${tbreak_line}\n" 350 gdb_expect { 351 -re "main.* at .*${srcfile}:${tbreak_line}.*$gdb_prompt $"\ 352 {pass "jump to execv call"} 353 -re "$gdb_prompt $" {fail "jump to execv call"} 354 timeout {fail "(timeout) jump to execv call"} 355 } 356 send_gdb "next\n" 357 gdb_expect { 358 -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int local_j = argc;.*$gdb_prompt $"\ 359 {pass "step through execv call"} 360 -re "$gdb_prompt $" {fail "step through execv call"} 361 timeout {fail "(timeout) step through execv call"} 362 } 363 send_gdb "next\n" 364 gdb_expect { 365 -re "printf \\(.Hello .*$gdb_prompt $"\ 366 {pass "step after execv call"} 367 -re "$gdb_prompt $" {fail "step after execv call"} 368 timeout {fail "(timeout) step after execv call"} 369 } 370 371 # Verify that we can print a local variable (which happens to be 372 # assigned the value of main's argc). 373 # 374 send_gdb "print local_j\n" 375 gdb_expect { 376 -re ".* = 2.*$gdb_prompt $"\ 377 {pass "print execd-program/local_j (after execv)"} 378 -re "$gdb_prompt $" {fail "print execd-program/local_j (after execv)"} 379 timeout {fail "(timeout) print execd-program/local_j (after execv)"} 380 } 381 382 # Explicitly kill this program, or a subsequent rerun actually runs 383 # the exec'd program, not the original program... 384 zap_session 385 386 # Start the program running, and stop at main. 387 # 388 if ![runto_main] then { 389 perror "Couldn't run ${testfile} (5th try)" 390 return 391 } 392 393 # Verify that we can just continue and thereby follow through an 394 # exec call. (Since the breakpoint on "main" is reset, we should 395 # just stop in main of the newly-exec'd program.) 396 # 397 send_gdb "continue\n" 398 gdb_expect { 399 -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int local_j = argc;.*$gdb_prompt $"\ 400 {pass "continue through exec"} 401 -re "$gdb_prompt $" {fail "continue through exec"} 402 timeout {fail "(timeout) continue through exec"} 403 } 404} 405 406# Start with a fresh gdb 407 408gdb_exit 409gdb_start 410gdb_reinitialize_dir $srcdir/$subdir 411gdb_load ${binfile} 412 413 414# This is a test of gdb's ability to follow a process through a 415# Unix exec() system call. 416# 417do_exec_tests 418 419return 0 420