Mirror of the gdb mailing list
 help / color / mirror / Atom feed
* Any solution to not being able to interrupt step in GDB ?
@ 2008-02-27 22:12 Antony KING
  2008-02-27 22:45 ` Daniel Jacobowitz
  0 siblings, 1 reply; 6+ messages in thread
From: Antony KING @ 2008-02-27 22:12 UTC (permalink / raw)
  To: gdb

I am currently using a version of GDB 6.6 (utilising our own remote
target interface) and I am trying to come up with a solution to the
problem we are seeing with the "step" command.

The problem is that GDB is not making it easy :-) for me to interrupt
the target when a "step" command has been issued on a statement of the
following form:

    while (okay) continue;

(where okay is a volatile that will be changed by an interrupt handler).

Please note that the above example is an illustration of a general
problem we encounter when debugging real-time multi-threaded embedded
applications with pre-emptive scheduling and interrupts.

GDB attempts to step the statement but the PC never falls outside the
bounds of the statement address range and so GDB is forever performing a
single instruction step.

As a result I can only interrupt the "step" command when I press Ctrl-C
while GDB executing target_wait(). If Ctrl-C is pressed outside of
target_wait() (which in my implementation provides its own SIGINT
handler), then GDB does not notice the event, as it is stuck in the
following loop in wait_for_inferior() because ecs->wait_some_more is
always TRUE:

    while (1)
      {
        if (deprecated_target_wait_hook)
          ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid,
ecs->wp);
        else
          ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);

        /* Now figure out what to do with the result of the result.  */
        handle_inferior_event (ecs);

        if (!ecs->wait_some_more)
          break;
      }

This means that the user has to continually press Ctrl-C in the hope of
hitting the sweet spot.

Is there any clean solution I can use which allows me to break out this
loop if there is a pending SIGINT event waiting to be processed ? There
seems a be a need for a way to "stop stepping" when Ctrl-C is pressed.
One thought I have is to fake a target SIGINT signal by checking for a
pending SIGINT event after returning from target_wait() and modifying
ecs before calling handle_inferior_event().

Of course the same issue arises when using the MI interface (with, for
example, Eclipse) but is worse since only a single stop request is issued.

[
I have seen that the subject has been raised here:

    http://sourceware.org/ml/gdb/2007-03/msg00228.html

but this did not seem to end with a solution.
]

Any advice would be appreciated.

Cheers,

Antony.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Any solution to not being able to interrupt step in GDB ?
  2008-02-27 22:12 Any solution to not being able to interrupt step in GDB ? Antony KING
@ 2008-02-27 22:45 ` Daniel Jacobowitz
  2008-02-27 22:46   ` Antony KING
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Jacobowitz @ 2008-02-27 22:45 UTC (permalink / raw)
  To: Antony KING; +Cc: gdb

On Wed, Feb 27, 2008 at 09:59:53PM +0000, Antony KING wrote:
> Is there any clean solution I can use which allows me to break out this
> loop if there is a pending SIGINT event waiting to be processed ? There
> seems a be a need for a way to "stop stepping" when Ctrl-C is pressed.
> One thought I have is to fake a target SIGINT signal by checking for a
> pending SIGINT event after returning from target_wait() and modifying
> ecs before calling handle_inferior_event().

I can refer you to the reply to the message you linked; which signal
handler is running when not in your "sweet spot"?

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Any solution to not being able to interrupt step in GDB ?
  2008-02-27 22:45 ` Daniel Jacobowitz
@ 2008-02-27 22:46   ` Antony KING
  2008-02-27 22:56     ` Daniel Jacobowitz
  0 siblings, 1 reply; 6+ messages in thread
From: Antony KING @ 2008-02-27 22:46 UTC (permalink / raw)
  To: gdb

Daniel Jacobowitz wrote:
> On Wed, Feb 27, 2008 at 09:59:53PM +0000, Antony KING wrote:
>> Is there any clean solution I can use which allows me to break out this
>> loop if there is a pending SIGINT event waiting to be processed ? There
>> seems a be a need for a way to "stop stepping" when Ctrl-C is pressed.
>> One thought I have is to fake a target SIGINT signal by checking for a
>> pending SIGINT event after returning from target_wait() and modifying
>> ecs before calling handle_inferior_event().
> 
> I can refer you to the reply to the message you linked; which signal
> handler is running when not in your "sweet spot"?
> 

The signal handler is the restored default handler, "handle_sigint". My 
target interface only substitutes that default SIGINT handler when 
implementing the target_wait() functionality (it is modelled on remote.c).

My first thought was that QUIT should achieve the effect I need but 
quit_flag, as was pointed out, is not being set soon enough. Also, 
forcing an immediate_quit is not suitable since I would like to stop the 
stepping cleanly with a target SIGINT (plus it breaks my target 
interface, but that is my problem :-).

Cheers,

Antony


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Any solution to not being able to interrupt step in GDB ?
  2008-02-27 22:46   ` Antony KING
@ 2008-02-27 22:56     ` Daniel Jacobowitz
  2008-02-29 22:09       ` Antony KING
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Jacobowitz @ 2008-02-27 22:56 UTC (permalink / raw)
  To: Antony KING; +Cc: gdb

On Wed, Feb 27, 2008 at 10:44:56PM +0000, Antony KING wrote:
> The signal handler is the restored default handler, "handle_sigint". My  
> target interface only substitutes that default SIGINT handler when  
> implementing the target_wait() functionality (it is modelled on remote.c).
>
> My first thought was that QUIT should achieve the effect I need but  
> quit_flag, as was pointed out, is not being set soon enough. Also,  
> forcing an immediate_quit is not suitable since I would like to stop the  
> stepping cleanly with a target SIGINT (plus it breaks my target  
> interface, but that is my problem :-).

Why doesn't quit_flag get set?  That's how I think we ought to do
this.  Avoid immediate_quit, that's dangerous to mess with.

I'm not sure why you'd want to use a target SIGINT for this case.
If we're between steps, we should just make sure we don't send
another step.  I suppose I hadn't thought about the case between
stepping and waiting...

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Any solution to not being able to interrupt step in GDB ?
  2008-02-27 22:56     ` Daniel Jacobowitz
@ 2008-02-29 22:09       ` Antony KING
  2008-02-29 22:49         ` Daniel Jacobowitz
  0 siblings, 1 reply; 6+ messages in thread
From: Antony KING @ 2008-02-29 22:09 UTC (permalink / raw)
  To: gdb

[-- Attachment #1: Type: text/plain, Size: 2069 bytes --]

Daniel Jacobowitz wrote:
> On Wed, Feb 27, 2008 at 10:44:56PM +0000, Antony KING wrote:
>> The signal handler is the restored default handler, "handle_sigint". My  
>> target interface only substitutes that default SIGINT handler when  
>> implementing the target_wait() functionality (it is modelled on remote.c).
>>
>> My first thought was that QUIT should achieve the effect I need but  
>> quit_flag, as was pointed out, is not being set soon enough. Also,  
>> forcing an immediate_quit is not suitable since I would like to stop the  
>> stepping cleanly with a target SIGINT (plus it breaks my target  
>> interface, but that is my problem :-).
> 
> Why doesn't quit_flag get set?  That's how I think we ought to do
> this.  Avoid immediate_quit, that's dangerous to mess with.

In my grep'ing of the (6.6) sources, I could only find quit_flag being 
set when async_request_quit() is called, by the event processing loop. 
It is also set in request_quit() but this API does not seem to be used.

> I'm not sure why you'd want to use a target SIGINT for this case.
> If we're between steps, we should just make sure we don't send
> another step.  I suppose I hadn't thought about the case between
> stepping and waiting...

I was thinking that a target SIGINT notification would be suitable since 
this is what the user would see if they interrupted a continue; I did 
not think interrupting a step, from a user perspective, would be any 
different. Of course, it is a lie since the target did not generate the 
SIGINT and so this would be confusing, although for the targets I have 
to support this is not a problem. Also, it was just easier for me to see 
how to apply a fix without getting too mired in understanding how the 
target event handling worked in handle_inferior_event() :-) and the 
mechanics of cleanly stopping.

Anyway, I have attached a patch fyi, which is my attempt at providing a 
solution using a faked target SIGINT which seems to work for me. It is a 
bit of a bodge since it subverts the main event loop but ce la vie.

Cheers,

Antony.

[-- Attachment #2: stepping-patch.txt --]
[-- Type: text/plain, Size: 2841 bytes --]

--- event-top.c@@/main/11	2007-07-31 12:22:19.000000000 +0100
+++ event-top.c	2008-02-29 20:37:01.000000000 +0000
@@ -959,6 +959,8 @@
 void
 handle_sigint (int sig)
 {
+  extern int in_wait_for_inferior, stop_wait_for_inferior;
+
   signal (sig, handle_sigint);
 
   /* If immediate_quit is set, we go ahead and process the SIGINT right
@@ -968,8 +970,12 @@
      processed only the next time through the event loop.  To get to
      that point, though, the command that we want to interrupt needs to
      finish first, which is unacceptable. */
+  /* However, if currently waiting for the target in wait_for_inferior
+     just signal wait_for_inferior that a SIGINT is pending. */
   if (immediate_quit)
     async_request_quit (0);
+  else if (in_wait_for_inferior)
+    stop_wait_for_inferior = 1;
   else
     /* If immediate quit is not set, we process SIGINT the next time
        through the loop, which is fine. */
--- infrun.c@@/main/12	2007-07-31 12:22:19.000000000 +0100
+++ infrun.c	2008-02-29 20:50:59.000000000 +0000
@@ -99,6 +99,12 @@
   fprintf_filtered (file, _("Mode of the step operation is %s.\n"), value);
 }
 
+/* Set by default SIGINT handler when a SIGINT occurs outside of a
+   target wait but still waiting for more inferior events. When set
+   "fake" a SIGINT event when target stops. */
+volatile int stop_wait_for_inferior = 0;
+int in_wait_for_inferior = 0;
+
 /* In asynchronous mode, but simulating synchronous execution. */
 
 int sync_execution = 0;
@@ -965,6 +971,13 @@
    When this function actually returns it means the inferior
    should be left stopped and GDB should read more commands.  */
 
+static void
+wait_for_inferior_cleanup (void *ignore)
+{
+  in_wait_for_inferior = 0;
+  delete_step_resume_breakpoint(&step_resume_breakpoint);
+}
+   
 void
 wait_for_inferior (void)
 {
@@ -975,8 +988,7 @@
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog, "infrun: wait_for_inferior\n");
 
-  old_cleanups = make_cleanup (delete_step_resume_breakpoint,
-			       &step_resume_breakpoint);
+  old_cleanups = make_cleanup (wait_for_inferior_cleanup, 0);
 
   /* wfi still stays in a loop, so it's OK just to take the address of
      a local to get the ecs pointer.  */
@@ -998,6 +1010,10 @@
 
   registers_changed ();
 
+  /* Reset state. */
+  in_wait_for_inferior = 1;
+  stop_wait_for_inferior = 0;
+
   while (1)
     {
       if (deprecated_target_wait_hook)
@@ -1005,6 +1021,12 @@
       else
 	ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
 
+      /* Override stop reason if interrupted. */
+      if (stop_wait_for_inferior
+	  && (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
+	  && (ecs->ws.value.sig == TARGET_SIGNAL_TRAP))
+	ecs->ws.value.sig = TARGET_SIGNAL_INT;
+
       /* Now figure out what to do with the result of the result.  */
       handle_inferior_event (ecs);
 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Any solution to not being able to interrupt step in GDB ?
  2008-02-29 22:09       ` Antony KING
@ 2008-02-29 22:49         ` Daniel Jacobowitz
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2008-02-29 22:49 UTC (permalink / raw)
  To: Antony KING; +Cc: gdb

On Fri, Feb 29, 2008 at 10:05:44PM +0000, Antony KING wrote:
> Daniel Jacobowitz wrote:
>> Why doesn't quit_flag get set?  That's how I think we ought to do
>> this.  Avoid immediate_quit, that's dangerous to mess with.
>
> In my grep'ing of the (6.6) sources, I could only find quit_flag being  
> set when async_request_quit() is called, by the event processing loop. It 
> is also set in request_quit() but this API does not seem to be used.

Are you working on 6.6 rather than HEAD?  Fred Fish moved quit_flag
setting from async_request_quit to handle_sigint on 2007-02-09, which
is later than your sources.  That should simplify things a bit!

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-02-29 22:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-27 22:12 Any solution to not being able to interrupt step in GDB ? Antony KING
2008-02-27 22:45 ` Daniel Jacobowitz
2008-02-27 22:46   ` Antony KING
2008-02-27 22:56     ` Daniel Jacobowitz
2008-02-29 22:09       ` Antony KING
2008-02-29 22:49         ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox