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