summaryrefslogtreecommitdiff
path: root/gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-08-05 02:06:24 +0000
committerCoprDistGit <infra@openeuler.org>2024-08-05 02:06:24 +0000
commitfb9e94c608e22ae34d776deffbfd225a2be15a53 (patch)
tree4fa0b980b9deb3a41ba7b8a17845888d77150f31 /gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch
parentba9480ce1210dc551f343b938be2fa00759e1616 (diff)
automatic import of gdbopeneuler24.03_LTS
Diffstat (limited to 'gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch')
-rw-r--r--gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch413
1 files changed, 413 insertions, 0 deletions
diff --git a/gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch b/gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch
new file mode 100644
index 0000000..579e2f5
--- /dev/null
+++ b/gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch
@@ -0,0 +1,413 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Andrew Burgess <aburgess@redhat.com>
+Date: Wed, 18 Jan 2023 10:17:57 +0000
+Subject: gdb-rhel-13298-inferior-funcall-bp-condition-4-of-5.patch
+
+;;gdb: introduce unwind-on-timeout setting
+;;(Andrew Burgess, RHEL-13298)
+
+Now that inferior function calls can timeout (see the recent
+introduction of direct-call-timeout and indirect-call-timeout), this
+commit adds a new setting unwind-on-timeout.
+
+This new setting is just like the existing unwindonsignal and
+unwind-on-terminating-exception, but the new setting will cause GDB to
+unwind the stack if an inferior function call times out.
+
+The existing inferior function call timeout tests have been updated to
+cover the new setting.
+
+Reviewed-By: Eli Zaretskii <eliz@gnu.org>
+Tested-By: Luis Machado <luis.machado@arm.com>
+Tested-By: Keith Seitz <keiths@redhat.com>
+
+diff --git a/gdb/NEWS b/gdb/NEWS
+--- a/gdb/NEWS
++++ b/gdb/NEWS
+@@ -72,6 +72,15 @@ show indirect-call-timeout
+ ignored, GDB will wait indefinitely for an inferior function to
+ complete, unless interrupted by the user using Ctrl-C.
+
++set unwind-on-timeout on|off
++show unwind-on-timeout
++ These commands control whether GDB should unwind the stack when a
++ timeout occurs during an inferior function call. The default is
++ off, in which case the inferior will remain in the frame where the
++ timeout occurred. When on, GDB will unwind the stack removing the
++ dummy frame that was added for the inferior call, and restoring the
++ inferior state to how it was before the inferior call started.
++
+ * New features in the GDB remote stub, GDBserver
+
+ ** The --remote-debug and --event-loop-debug command line options
+diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
+--- a/gdb/doc/gdb.texinfo
++++ b/gdb/doc/gdb.texinfo
+@@ -20932,6 +20932,22 @@ the default C@t{++} exception handler and the inferior terminated.
+ Show the current setting of stack unwinding in the functions called by
+ @value{GDBN}.
+
++@anchor{set unwind-on-timeout}
++@item set unwind-on-timeout
++@kindex set unwind-on-timeout
++@cindex unwind stack in called functions when timing out
++@cindex call dummy stack unwinding on timeout.
++Set unwinding of the stack if a function called from @value{GDBN}
++times out. If set to @code{off} (the default), @value{GDBN} stops in
++the frame where the timeout occurred. If set to @code{on},
++@value{GDBN} unwinds the stack it created for the call and restores
++the context to what it was before the call.
++
++@item show unwind-on-timeout
++@kindex show unwind-on-timeout
++Show whether @value{GDBN} will unwind the stack if a function called
++from @value{GDBN} times out.
++
+ @item set may-call-functions
+ @kindex set may-call-functions
+ @cindex disabling calling functions in the program
+@@ -20963,11 +20979,11 @@ call by typing the interrupt character (often @kbd{Ctrl-c}).
+
+ If a called function is interrupted for any reason, including hitting
+ a breakpoint, or triggering a watchpoint, and the stack is not unwound
+-due to @code{set unwind-on-terminating-exception on} or @code{set
+-unwindonsignal on} (@pxref{stack unwind settings}),
+-then the dummy-frame, created by @value{GDBN} to facilitate the call
+-to the program function, will be visible in the backtrace, for example
+-frame @code{#3} in the following backtrace:
++due to @code{set unwind-on-terminating-exception on}, @code{set
++unwind-on-timeout on}, or @code{set unwindonsignal on} (@pxref{stack
++unwind settings}), then the dummy-frame, created by @value{GDBN} to
++facilitate the call to the program function, will be visible in the
++backtrace, for example frame @code{#3} in the following backtrace:
+
+ @smallexample
+ (@value{GDBP}) backtrace
+@@ -20992,6 +21008,11 @@ Execution}) @value{GDBN} can place a timeout on any functions called
+ from @value{GDBN}. If the timeout expires and the function call is
+ still ongoing, then @value{GDBN} will interrupt the program.
+
++If a function called from @value{GDBN} is interrupted by a timeout,
++then by default the inferior is left in the frame where the timeout
++occurred, this behaviour can be adjusted with @samp{set
++unwind-on-timeout} (@pxref{set unwind-on-timeout}).
++
+ For targets that don't support asynchronous execution
+ (@pxref{Background Execution}) then timeouts for functions called from
+ @value{GDBN} are not supported, the timeout settings described below
+diff --git a/gdb/infcall.c b/gdb/infcall.c
+--- a/gdb/infcall.c
++++ b/gdb/infcall.c
+@@ -218,6 +218,27 @@ show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty,
+ value);
+ }
+
++/* This boolean tells GDB what to do if an inferior function, called from
++ GDB, times out. If true, GDB unwinds the stack and restores the context
++ to what it was before the call. When false, GDB leaves the thread as it
++ is at the point of the timeout.
++
++ The default is to stop in the frame where the timeout occurred. */
++
++static bool unwind_on_timeout_p = false;
++
++/* Implement 'show unwind-on-timeout'. */
++
++static void
++show_unwind_on_timeout_p (struct ui_file *file, int from_tty,
++ struct cmd_list_element *c, const char *value)
++{
++ gdb_printf (file,
++ _("Unwinding of stack if a timeout occurs "
++ "while in a call dummy is %s.\n"),
++ value);
++}
++
+ /* Perform the standard coercions that are specified
+ for arguments to be passed to C, Ada or Fortran functions.
+
+@@ -574,6 +595,16 @@ struct call_thread_fsm : public thread_fsm
+ bool should_stop (struct thread_info *thread) override;
+
+ bool should_notify_stop () override;
++
++ /* Record that this thread timed out while performing an infcall. */
++ void timed_out ()
++ {
++ m_timed_out = true;
++ }
++
++private:
++ /* Set true if the thread timed out while performing an infcall. */
++ bool m_timed_out = false;
+ };
+
+ /* Allocate a new call_thread_fsm object. */
+@@ -649,7 +680,8 @@ call_thread_fsm::should_notify_stop ()
+
+ infcall_debug_printf ("inferior call didn't complete fully");
+
+- if (stopped_by_random_signal && unwind_on_signal_p)
++ if ((stopped_by_random_signal && unwind_on_signal_p)
++ || (m_timed_out && unwind_on_timeout_p))
+ {
+ infcall_debug_printf ("unwind-on-signal is on, don't notify");
+ return false;
+@@ -742,6 +774,9 @@ struct infcall_timer_controller
+
+ infcall_debug_printf ("Stopping thread %s",
+ m_thread->ptid.to_string ().c_str ());
++ call_thread_fsm *fsm
++ = gdb::checked_static_cast<call_thread_fsm *> (m_thread->thread_fsm ());
++ fsm->timed_out ();
+ target_stop (m_thread->ptid);
+ }
+ };
+@@ -1744,14 +1779,27 @@ When the function is done executing, GDB will silently stop."),
+ /* A timeout results in a signal being sent to the inferior. */
+ gdb_assert (stopped_by_random_signal);
+
+- /* Indentation is weird here. A later patch is going to move the
+- following block into an if/else, so I'm leaving the indentation
+- here to minimise the later patch.
++ if (unwind_on_timeout_p)
++ {
++ /* The user wants the context restored. */
++
++ /* We must get back to the frame we were before the
++ dummy call. */
++ dummy_frame_pop (dummy_id, call_thread.get ());
+
+- Also, the error message used below refers to 'set
+- unwind-on-timeout' which doesn't exist yet. This will be added
+- in a later commit, I'm leaving this in for now to minimise the
+- churn caused by the commit that adds unwind-on-timeout. */
++ /* We also need to restore inferior status to that before the
++ dummy call. */
++ restore_infcall_control_state (inf_status.release ());
++
++ error (_("\
++The program being debugged timed out while in a function called from GDB.\n\
++GDB has restored the context to what it was before the call.\n\
++To change this behavior use \"set unwind-on-timeout off\".\n\
++Evaluation of the expression containing the function\n\
++(%s) will be abandoned."),
++ name.c_str ());
++ }
++ else
+ {
+ /* The user wants to stay in the frame where we stopped
+ (default). Discard inferior status, we're not at the same
+@@ -1877,6 +1925,20 @@ The default is to unwind the frame."),
+ show_unwind_on_terminating_exception_p,
+ &setlist, &showlist);
+
++ add_setshow_boolean_cmd ("unwind-on-timeout", no_class,
++ &unwind_on_timeout_p, _("\
++Set unwinding of stack if a timeout occurs while in a call dummy."), _("\
++Show unwinding of stack if a timeout occurs while in a call dummy."),
++ _("\
++The unwind on timeout flag lets the user determine what gdb should do if\n\
++gdb times out while in a function called from gdb. If set, gdb unwinds\n\
++the stack and restores the context to what it was before the call. If\n\
++unset, gdb leaves the inferior in the frame where the timeout occurred.\n\
++The default is to stop in the frame where the timeout occurred."),
++ NULL,
++ show_unwind_on_timeout_p,
++ &setlist, &showlist);
++
+ add_setshow_uinteger_cmd ("direct-call-timeout", no_class,
+ &direct_call_timeout, _("\
+ Set the timeout, for direct calls to inferior function calls."), _("\
+diff --git a/gdb/testsuite/gdb.base/infcall-timeout.exp b/gdb/testsuite/gdb.base/infcall-timeout.exp
+--- a/gdb/testsuite/gdb.base/infcall-timeout.exp
++++ b/gdb/testsuite/gdb.base/infcall-timeout.exp
+@@ -28,7 +28,11 @@ if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
+ # then adjust the direct-call-timeout, and make an inferior function
+ # call that will never return. GDB should eventually timeout and stop
+ # the inferior.
+-proc run_test { target_async target_non_stop non_stop } {
++#
++# When UNWIND is "off" the inferior wil be left in the frame where the
++# timeout occurs, otherwise, when UNWIND is "on", GDB should unwind
++# back to the frame where the inferior call was made.
++proc run_test { target_async target_non_stop non_stop unwind } {
+ save_vars { ::GDBFLAGS } {
+ append ::GDBFLAGS \
+ " -ex \"maint set target-non-stop $target_non_stop\""
+@@ -45,28 +49,43 @@ proc run_test { target_async target_non_stop non_stop } {
+ }
+
+ gdb_test_no_output "set direct-call-timeout 5"
++ gdb_test_no_output "set unwind-on-timeout $unwind"
++
++ if { $unwind } {
++ gdb_test "print function_that_never_returns ()" \
++ [multi_line \
++ "The program being debugged timed out while in a function called from GDB\\." \
++ "GDB has restored the context to what it was before the call\\." \
++ "To change this behavior use \"set unwind-on-timeout off\"\\." \
++ "Evaluation of the expression containing the function" \
++ "\\(function_that_never_returns\\) will be abandoned\\."]
+
+- # When non-stop mode is off we get slightly different output from GDB.
+- if { ([target_info gdb_protocol] == "remote"
+- || [target_info gdb_protocol] == "extended-remote")
+- && !$target_non_stop } {
+- set stopped_line_pattern "Program received signal SIGINT, Interrupt\\."
++ gdb_test "bt" \
++ "#0\\s+main \\(\\).*"
+ } else {
+- set stopped_line_pattern "Program stopped\\."
+- }
++ # When non-stop mode is off we get slightly different output from GDB.
++ if { ([target_info gdb_protocol] == "remote"
++ || [target_info gdb_protocol] == "extended-remote")
++ && !$target_non_stop } {
++ set stopped_line_pattern "Program received signal SIGINT, Interrupt\\."
++ } else {
++ set stopped_line_pattern "Program stopped\\."
++ }
+
+- gdb_test "print function_that_never_returns ()" \
+- [multi_line \
+- $stopped_line_pattern \
+- ".*" \
+- "The program being debugged timed out while in a function called from GDB\\." \
+- "GDB remains in the frame where the timeout occurred\\." \
+- "To change this behavior use \"set unwind-on-timeout on\"\\." \
+- "Evaluation of the expression containing the function" \
+- "\\(function_that_never_returns\\) will be abandoned\\." \
+- "When the function is done executing, GDB will silently stop\\."]
+-
+- gdb_test "bt" ".* function_that_never_returns .*<function called from gdb>.*"
++ gdb_test "print function_that_never_returns ()" \
++ [multi_line \
++ $stopped_line_pattern \
++ ".*" \
++ "The program being debugged timed out while in a function called from GDB\\." \
++ "GDB remains in the frame where the timeout occurred\\." \
++ "To change this behavior use \"set unwind-on-timeout on\"\\." \
++ "Evaluation of the expression containing the function" \
++ "\\(function_that_never_returns\\) will be abandoned\\." \
++ "When the function is done executing, GDB will silently stop\\."]
++
++ gdb_test "bt" \
++ ".* function_that_never_returns .*<function called from gdb>.*"
++ }
+ }
+
+ foreach_with_prefix target_async { "on" "off" } {
+@@ -88,7 +107,9 @@ foreach_with_prefix target_async { "on" "off" } {
+ continue
+ }
+
+- run_test $target_async $target_non_stop $non_stop
++ foreach_with_prefix unwind { "on" "off" } {
++ run_test $target_async $target_non_stop $non_stop $unwind
++ }
+ }
+ }
+ }
+diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp
+--- a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp
++++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp
+@@ -41,7 +41,12 @@ set segfault_line [gdb_get_line_number "Segfault here"]
+ # thread, on which the inferior call relies, either hits a breakpoint
+ # (when OTHER_THREAD_BP is true), or crashes (when OTHER_THREAD_BP is
+ # false).
+-proc run_test { target_async target_non_stop non_stop other_thread_bp } {
++#
++# When UNWIND is "on" GDB will unwind the thread which performed the
++# inferior function call back to the state where the inferior call was
++# made (when the inferior call times out). Otherwise, when UNWIND is
++# "off", the inferior is left in the frame where the timeout occurred.
++proc run_test { target_async target_non_stop non_stop other_thread_bp unwind } {
+ save_vars { ::GDBFLAGS } {
+ append ::GDBFLAGS " -ex \"maint set target-non-stop $target_non_stop\""
+ append ::GDBFLAGS " -ex \"maint non-stop $non_stop\""
+@@ -72,6 +77,7 @@ proc run_test { target_async target_non_stop non_stop other_thread_bp } {
+ # for this timeout. For now though, we just hope 5 seconds is
+ # enough.
+ gdb_test_no_output "set indirect-call-timeout 5"
++ gdb_test_no_output "set unwind-on-timeout $unwind"
+
+ gdb_breakpoint \
+ "${::srcfile}:${::cond_bp_line} if (condition_func ())"
+@@ -92,27 +98,43 @@ proc run_test { target_async target_non_stop non_stop other_thread_bp } {
+ "get number for segfault breakpoint"]
+ }
+
+- # When non-stop mode is off we get slightly different output from GDB.
+- if { ([target_info gdb_protocol] == "remote"
+- || [target_info gdb_protocol] == "extended-remote")
+- && !$target_non_stop} {
+- set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" received signal SIGINT, Interrupt\\."
++ if { $unwind } {
++ gdb_test "continue" \
++ [multi_line \
++ "Error in testing condition for breakpoint ${bp_num}:" \
++ "The program being debugged timed out while in a function called from GDB\\." \
++ "GDB has restored the context to what it was before the call\\." \
++ "To change this behavior use \"set unwind-on-timeout off\"\\." \
++ "Evaluation of the expression containing the function" \
++ "\\(condition_func\\) will be abandoned\\.(\r\n\\\[New Thread \[^\r\n\]+\\\])*" \
++ "" \
++ "Thread ${::decimal}\[^\r\n\]*hit Breakpoint ${bp_num}, \[^\r\n\]+" \
++ "\[^\r\n\]+ Conditional breakpoint here\\. \[^\r\n\]+"] \
++ "expected timeout waiting for inferior call to complete"
+ } else {
+- set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" stopped\\."
+- }
++ # When non-stop mode is off we get slightly different output from GDB.
++ if { ([target_info gdb_protocol] == "remote"
++ || [target_info gdb_protocol] == "extended-remote")
++ && !$target_non_stop} {
++ set stopped_line_pattern \
++ "Thread ${::decimal} \"\[^\r\n\"\]+\" received signal SIGINT, Interrupt\\."
++ } else {
++ set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" stopped\\."
++ }
+
+- gdb_test "continue" \
+- [multi_line \
+- $stopped_line_pattern \
+- ".*" \
+- "Error in testing condition for breakpoint ${bp_num}:" \
+- "The program being debugged timed out while in a function called from GDB\\." \
+- "GDB remains in the frame where the timeout occurred\\." \
+- "To change this behavior use \"set unwind-on-timeout on\"\\." \
+- "Evaluation of the expression containing the function" \
+- "\\(condition_func\\) will be abandoned\\." \
+- "When the function is done executing, GDB will silently stop\\."] \
+- "expected timeout waiting for inferior call to complete"
++ gdb_test "continue" \
++ [multi_line \
++ "$stopped_line_pattern" \
++ ".*" \
++ "Error in testing condition for breakpoint ${bp_num}:" \
++ "The program being debugged timed out while in a function called from GDB\\." \
++ "GDB remains in the frame where the timeout occurred\\." \
++ "To change this behavior use \"set unwind-on-timeout on\"\\." \
++ "Evaluation of the expression containing the function" \
++ "\\(condition_func\\) will be abandoned\\." \
++ "When the function is done executing, GDB will silently stop\\."] \
++ "expected timeout waiting for inferior call to complete"
++ }
+
+ # Remember that other thread that either crashed (with a segfault)
+ # or hit a breakpoint? Now that the inferior call has timed out,
+@@ -158,8 +180,11 @@ foreach_with_prefix target_async {"on" "off" } {
+ # disabled.
+ continue
+ }
+- foreach_with_prefix other_thread_bp { true false } {
+- run_test $target_async $target_non_stop $non_stop $other_thread_bp
++ foreach_with_prefix unwind {"off" "on"} {
++ foreach_with_prefix other_thread_bp { true false } {
++ run_test $target_async $target_non_stop $non_stop \
++ $other_thread_bp $unwind
++ }
+ }
+ }
+ }