detach-step-over.exp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. # Copyright 2021-2022 Free Software Foundation, Inc.
  2. # This program is free software; you can redistribute it and/or modify
  3. # it under the terms of the GNU General Public License as published by
  4. # the Free Software Foundation; either version 3 of the License, or
  5. # (at your option) any later version.
  6. #
  7. # This program is distributed in the hope that it will be useful,
  8. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. # GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. # Test detaching from a process that is running and has threads
  15. # constantly hitting a breakpoint and stepping over it, in all
  16. # combinations of:
  17. #
  18. # - maint target non-stop off/on
  19. # - set non-stop on/off
  20. # - displaced stepping on/off
  21. #
  22. # This stresses the edge cases of detaching while a displaced step or
  23. # an in-line step over are in progress.
  24. #
  25. # A fail mode is that the inferior process dies after being detached.
  26. # This can happen because e.g.:
  27. #
  28. # - GDB leaves a breakpoint installed behind, or
  29. #
  30. # - GDB leaves a thread running in the displaced step scratch buffer.
  31. # With no debugger around to run the finish step, the thread runs
  32. # off of the scratch buffer, with undefined results.
  33. #
  34. # To exercise this, the testcase reattaches to the process shortly
  35. # after detaching, ensuring the process is still alive and well.
  36. #
  37. # In addition, since GDB may pause threads of all processes for
  38. # stepping over a breakpoint, it needs to re-resume all threads if it
  39. # detaches from the process that was just stepping over the
  40. # breakpoint. To ensure that, the testcase actually runs a second
  41. # process at the same time as the one that is used to test detaching.
  42. # After the first process is detached, the testcase sends a SIGUSR1 to
  43. # the second process. If threads failed to be resumed, then the
  44. # SIGUSR1 is never reported to the user, resulting in timeout. The
  45. # threads of this second process will also be constantly stepping over
  46. # a breakpoint, which has helped with exposing further corner case
  47. # bugs.
  48. if {![can_spawn_for_attach]} {
  49. return 0
  50. }
  51. standard_testfile
  52. set bp_lineno [gdb_get_line_number "Set breakpoint here"]
  53. # The test proper. See description above.
  54. proc test {condition_eval target_non_stop non_stop displaced} {
  55. global binfile srcfile
  56. global gdb_prompt
  57. global decimal
  58. global bp_lineno
  59. global GDBFLAGS
  60. # Number of threads started by the program.
  61. set n_threads 10
  62. save_vars { GDBFLAGS } {
  63. append GDBFLAGS " -ex \"maint set target-non-stop $target_non_stop\""
  64. append GDBFLAGS " -ex \"set non-stop $non_stop\""
  65. append GDBFLAGS " -ex \"set displaced $displaced\""
  66. append GDBFLAGS " -ex \"set schedule-multiple on\""
  67. clean_restart $binfile
  68. }
  69. set test_spawn_id [spawn_wait_for_attach $binfile]
  70. set testpid [spawn_id_get_pid $test_spawn_id]
  71. set any "\[^\r\n\]*"
  72. gdb_test "add-inferior" "Added inferior 2.*"
  73. gdb_test "inferior 2" "Switching to .*"
  74. gdb_load $binfile
  75. if ![runto setup_done] then {
  76. fail "can't run to setup_done"
  77. kill_wait_spawned_process $test_spawn_id
  78. return
  79. }
  80. gdb_test_no_output "set breakpoint condition-evaluation $condition_eval"
  81. # Get the PID of the test process.
  82. set pid_inf2 ""
  83. gdb_test_multiple "p mypid" "get pid of inferior 2" {
  84. -re " = ($decimal)\r\n$gdb_prompt $" {
  85. set pid_inf2 $expect_out(1,string)
  86. pass $gdb_test_name
  87. }
  88. }
  89. set attempts 3
  90. for {set attempt 1} { $attempt <= $attempts } { incr attempt } {
  91. with_test_prefix "iter $attempt" {
  92. gdb_test "inferior 1" "Switching to .*"
  93. with_timeout_factor 2 {
  94. set attached 0
  95. set saw_attaching 0
  96. set eperm 0
  97. set test "attach"
  98. gdb_test_multiple "attach $testpid" $test {
  99. -re "Attaching to program.*process $testpid\r\n" {
  100. set saw_attaching 1
  101. exp_continue
  102. }
  103. -re "new threads in iteration" {
  104. # Seen when "set debug libthread_db" is on.
  105. exp_continue
  106. }
  107. -re "Reading symbols from|Expanding full symbols from" {
  108. # Prevent -readnow timeout.
  109. exp_continue
  110. }
  111. -re "is a zombie - the process has already terminated.*$gdb_prompt " {
  112. fail $gdb_test_name
  113. }
  114. -re "Unable to attach: .*$gdb_prompt " {
  115. fail $gdb_test_name
  116. }
  117. -re "\r\n$gdb_prompt " {
  118. if { $saw_attaching } {
  119. set attached 1
  120. pass $test
  121. } else {
  122. fail $test
  123. }
  124. }
  125. }
  126. }
  127. if {!$attached} {
  128. kill_wait_spawned_process $test_spawn_id
  129. return
  130. }
  131. if {$non_stop} {
  132. # In non-stop, we will see one stop per thread after
  133. # the prompt.
  134. set stops 0
  135. set tid_re "$::decimal\.$::decimal"
  136. set test "seen all stops"
  137. for {set thread 1} { $thread <= $n_threads } { incr thread } {
  138. if {[gdb_test_multiple "" $test {
  139. -re "Thread ${tid_re} ${any} stopped" {
  140. incr stops
  141. }
  142. }] != 0} {
  143. break
  144. }
  145. }
  146. # If we haven't seen all stops, then the
  147. # gdb_test_multiple in the loop above will have
  148. # already issued a FAIL.
  149. if {$stops != $n_threads} {
  150. kill_wait_spawned_process $test_spawn_id
  151. return
  152. }
  153. pass $test
  154. }
  155. # Set threads stepping over a breakpoint continuously.
  156. gdb_test "break $srcfile:$bp_lineno if 0" "Breakpoint.*" \
  157. "break LOC if 0"
  158. if {$attempt < $attempts} {
  159. # Kick the time out timer for another round.
  160. gdb_test "print again = 1" " = 1" "reset timer in the inferior"
  161. # Show the time we had left in the logs, in case
  162. # something goes wrong.
  163. gdb_test "print seconds_left" " = .*"
  164. }
  165. if {$non_stop} {
  166. set cont_cmd "continue -a &"
  167. } else {
  168. set cont_cmd "continue &"
  169. }
  170. set cont_cmd_re [string_to_regexp $cont_cmd]
  171. gdb_test_multiple $cont_cmd "" {
  172. -re "^$cont_cmd_re\r\nContinuing\.\r\n$gdb_prompt " {
  173. pass $gdb_test_name
  174. }
  175. }
  176. # Wait a bit, to give time for the threads to hit the
  177. # breakpoint.
  178. sleep 1
  179. set running_count 0
  180. set interrupted 0
  181. gdb_test_multiple "info threads" "all threads running" {
  182. -re "\\(running\\)" {
  183. incr running_count
  184. exp_continue
  185. }
  186. -re "Cannot execute this command while the target is running.*$gdb_prompt $" {
  187. # Testing against a remote server that doesn't do
  188. # non-stop mode. Explicitly interrupt. This
  189. # doesn't test the same code paths in GDB, but
  190. # it's still something.
  191. set interrupted 1
  192. gdb_test_multiple "interrupt" "" {
  193. -re "$gdb_prompt " {
  194. gdb_test_multiple "" $gdb_test_name {
  195. -re "received signal SIGINT, Interrupt" {
  196. pass $gdb_test_name
  197. }
  198. }
  199. }
  200. }
  201. }
  202. -re "$gdb_prompt $" {
  203. gdb_assert {$running_count == ($n_threads + 1) * 2} $gdb_test_name
  204. }
  205. }
  206. gdb_test "detach" "Detaching from.*"
  207. if {!$interrupted} {
  208. # Now test whether inferior 2's thread were really left
  209. # running. Currently an inline step-over stops all
  210. # threads of all processes. If detach aborts such a step
  211. # over, then threads of other inferiors should be
  212. # re-resumed. Test for that by sending a signal to
  213. # inferior 2.
  214. remote_exec target "kill -SIGUSR1 ${pid_inf2}"
  215. gdb_test_multiple "" "stop with SIGUSR1" {
  216. -re "received signal SIGUSR1" {
  217. pass $gdb_test_name
  218. }
  219. }
  220. }
  221. delete_breakpoints
  222. }
  223. }
  224. kill_wait_spawned_process $test_spawn_id
  225. }
  226. # The test program exits after a while, in case GDB crashes. Make it
  227. # wait at least as long as we may wait before declaring a time out
  228. # failure.
  229. set options { "additional_flags=-DTIMEOUT=$timeout" debug pthreads }
  230. if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options] == -1} {
  231. return -1
  232. }
  233. if ![runto_main] {
  234. return -1
  235. }
  236. # Probe support for "set breakpoint condition-evaluation target".
  237. # This setting influences who steps over the breakpoint, the (remote)
  238. # target (e.g. gdbserver) or gdb, thus exposing issues on either the
  239. # target or gdb.
  240. set supports_condition_eval_target 1
  241. set cmd "set breakpoint condition-evaluation target"
  242. gdb_test_multiple $cmd "probe condition-evaluation target support" {
  243. -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" {
  244. # Target doesn't support breakpoint condition evaluation on
  245. # its side.
  246. set supports_condition_eval_target 0
  247. pass $gdb_test_name
  248. }
  249. -re "^$cmd\r\n$gdb_prompt $" {
  250. pass $gdb_test_name
  251. }
  252. }
  253. foreach_with_prefix breakpoint-condition-evaluation {"host" "target"} {
  254. if {!$supports_condition_eval_target && ${breakpoint-condition-evaluation} == "target"} {
  255. continue
  256. }
  257. foreach_with_prefix target-non-stop {"off" "on"} {
  258. foreach_with_prefix non-stop {"off" "on"} {
  259. if {${non-stop} && !${target-non-stop}} {
  260. # "set non-stop" overrides "maint set
  261. # target-non-stop", no use testing this combination.
  262. continue
  263. }
  264. foreach_with_prefix displaced {"off" "auto"} {
  265. test ${breakpoint-condition-evaluation} ${target-non-stop} ${non-stop} ${displaced}
  266. }
  267. }
  268. }
  269. }