[PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm

Pedro Alves
2016-05-06T12:35:55Z

I noticed that if we step into an inline function, step_1 never
reaches proceed, and thus nevers sets the thread's
tp->control.command_interp. Because of that,
should_print_stop_to_console fails to determine that is should print
stop output to the console.

The fix is to set the thread's command_interp earlier. However, I
realized that we can move that field to the thread_fsm, given that its
lifetime is exactly the same as thread_fsm. So the patch plumbs all
fsms constructors to take the command interp and store it in the
thread_fsm.

We can see the fix in action, with e.g., the gdb.opt/inline-cmds.exp
test, and issuing a step when stopped at line 67:

&"s\n"
^running
*running,thread-id="all"
(gdb)
~"67\t result = func2 ();\n"
*stopped,reason="end-stepping-range",frame={addr="0x00000000004004d0",func="main",args=[],file="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
(gdb)
s
&"s\n"
^running
*running,thread-id="all"
(gdb)
+ ~"func2 () at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c:67\n"
+ ~"67\t result = func2 ();\n"
*stopped,reason="end-stepping-range",frame={addr="0x00000000004004d0",func="func2",args=[],file="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
(gdb)

(The inline-cmds.exp command is adjusted to exercise this.)

(Due to the follow_fork change, this also fixes "next N" across a fork
with "set follow-fork child" with "set detach-on-fork on". Commands
that rely on internal breakpoints, like "finish" will still require
more work to migrate breakpoints etc. to the child thread.)

gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>

* breakpoint.c (new_until_break_fsm): Add 'cmd_interp' parameter.
(until_break_fsm_should_stop, until_break_fsm_clean_up): Add
thread parameter.
(until_break_command): Pass command interpreter to thread fsm
ctor.
* cli/cli-interp.c (should_print_stop_to_console): Adjust.
* gdbthread.h (struct thread_control_state) <command_interp>:
Delete field.
* infcall.c (new_call_thread_fsm): Add 'cmd_interp' parameter.
Pass it down.
(call_thread_fsm_should_stop): Add thread parameter.
(call_function_by_hand_dummy): Pass command interpreter to thread
fsm ctor. Pass thread pointer to fsm clean up method.
* infcmd.c: Include interps.h.
(struct step_command_fsm) <thread>: Delete field.
(new_step_command_fsm): Add 'cmd_interp' parameter. Pass it down.
(step_command_fsm_prepare): Remove references to fsm's thread
field.
(step_1): Pass command interpreter to thread
fsm ctor. Pass thread pointer to fsm clean up method.
(step_command_fsm_should_stop, step_command_fsm_clean_up): Add
thread parameter and use it.
(new_until_next_fsm): Add 'cmd_interp' parameter. Pass it down.
(until_next_fsm_should_stop, until_next_fsm_clean_up): Add thread
parameter and use it.
(until_next_command): Pass command interpreter to thread fsm ctor.
(struct finish_command_fsm) <thread>: Delete field.
(finish_command_fsm_ops): Add NULL slot for should_notify_stop.
(new_finish_command_fsm): Add 'cmd_interp' parameter and pass it
down. Remove thread parameter and adjust.
(finish_command_fsm_should_stop, finish_command_fsm_clean_up): Add
thread parameter and use it.
(finish_command): Pass command interpreter to thread fsm ctor.
Don't pass thread.
* infrun.c (follow_fork): Move thread fsm to child fork instead of
command interpreter, only.
(clear_proceed_status_thread): Remove reference to command_interp.
(proceed): Don't record the thread's command interpreter.
(clean_up_just_stopped_threads_fsms): Pass thread to fsm clean_up
method.
(fetch_inferior_event): Pass thread to fsm should_stop method.
* thread-fsm.c (thread_fsm_ctor): Add 'cmd_interp' parameter.
Store it.
(thread_fsm_clean_up, thread_fsm_should_stop): Add thread
parameter and pass it down.
* thread-fsm.h (struct thread_fsm) <command_interp>: New field.
(struct thread_fsm_ops) <clean_up, should_stop>: Add thread
parameter.
(thread_fsm_ctor): Add 'cmd_interp' parameter.
(thread_fsm_clean_up, thread_fsm_should_stop): Add thread
parameter.
* thread.c (thread_cancel_execution_command): Pass thread to
thread fsm clean_up method.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>

* gdb.opt/inline-cmds.c: Add "set mi break here" marker.
* gdb.opt/inline-cmds.exp: Add MI tests.
---
gdb/breakpoint.c | 19 +++++----
gdb/cli/cli-interp.c | 7 ++--
gdb/gdbthread.h | 5 ---
gdb/infcall.c | 14 ++++---
gdb/infcmd.c | 74 +++++++++++++++++------------------
gdb/infrun.c | 23 ++++-------
gdb/testsuite/gdb.opt/inline-cmds.c | 2 +-
gdb/testsuite/gdb.opt/inline-cmds.exp | 62 +++++++++++++++++++++++++++++
gdb/thread-fsm.c | 12 +++---
gdb/thread-fsm.h | 23 ++++++++---
gdb/thread.c | 2 +-
11 files changed, 153 insertions(+), 90 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a28e956..d181597 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11614,8 +11614,10 @@ struct until_break_fsm
struct breakpoint *caller_breakpoint;
};

-static void until_break_fsm_clean_up (struct thread_fsm *self);
-static int until_break_fsm_should_stop (struct thread_fsm *self);
+static void until_break_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
+static int until_break_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
static enum async_reply_reason
until_break_fsm_async_reply_reason (struct thread_fsm *self);

@@ -11633,14 +11635,14 @@ static struct thread_fsm_ops until_break_fsm_ops =
/* Allocate a new until_break_command_fsm. */

static struct until_break_fsm *
-new_until_break_fsm (int thread,
+new_until_break_fsm (struct interp *cmd_interp, int thread,
struct breakpoint *location_breakpoint,
struct breakpoint *caller_breakpoint)
{
struct until_break_fsm *sm;

sm = XCNEW (struct until_break_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &until_break_fsm_ops);
+ thread_fsm_ctor (&sm->thread_fsm, &until_break_fsm_ops, cmd_interp);

sm->thread = thread;
sm->location_breakpoint = location_breakpoint;
@@ -11653,10 +11655,10 @@ new_until_break_fsm (int thread,
until(location)/advance commands. */

static int
-until_break_fsm_should_stop (struct thread_fsm *self)
+until_break_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
{
struct until_break_fsm *sm = (struct until_break_fsm *) self;
- struct thread_info *tp = inferior_thread ();

if (bpstat_find_breakpoint (tp->control.stop_bpstat,
sm->location_breakpoint) != NULL
@@ -11672,7 +11674,8 @@ until_break_fsm_should_stop (struct thread_fsm *self)
until(location)/advance commands. */

static void
-until_break_fsm_clean_up (struct thread_fsm *self)
+until_break_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread)
{
struct until_break_fsm *sm = (struct until_break_fsm *) self;

@@ -11794,7 +11797,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
stack_frame_id, bp_until);
make_cleanup_delete_breakpoint (location_breakpoint);

- sm = new_until_break_fsm (tp->global_num,
+ sm = new_until_break_fsm (command_interp (), tp->global_num,
location_breakpoint, caller_breakpoint);
tp->thread_fsm = &sm->thread_fsm;

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index bbe287c..e6f104b 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -77,10 +77,9 @@ should_print_stop_to_console (struct interp *console_interp,
{
if ((bpstat_what (tp->control.stop_bpstat).main_action
== BPSTAT_WHAT_STOP_NOISY)
- || !(tp->thread_fsm != NULL
- && thread_fsm_finished_p (tp->thread_fsm))
- || (tp->control.command_interp != NULL
- && tp->control.command_interp == console_interp))
+ || tp->thread_fsm == NULL
+ || tp->thread_fsm->command_interp == console_interp
+ || !thread_fsm_finished_p (tp->thread_fsm))
return 1;
return 0;
}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index bdd2bb0..af2dc86 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -136,11 +136,6 @@ struct thread_control_state
at. */
bpstat stop_bpstat;

- /* The interpreter that issued the execution command. NULL if the
- thread was resumed as a result of a command applied to some other
- thread (e.g., "next" with scheduler-locking off). */
- struct interp *command_interp;
-
/* Whether the command that started the thread was a stepping
command. This is used to decide whether "set scheduler-locking
step" behaves like "on" or "off". */
diff --git a/gdb/infcall.c b/gdb/infcall.c
index d491f95..8199bdd 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -470,7 +470,8 @@ struct call_thread_fsm
struct ui *waiting_ui;
};

-static int call_thread_fsm_should_stop (struct thread_fsm *self);
+static int call_thread_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
static int call_thread_fsm_should_notify_stop (struct thread_fsm *self);

/* call_thread_fsm's vtable. */
@@ -488,7 +489,7 @@ static struct thread_fsm_ops call_thread_fsm_ops =
/* Allocate a new call_thread_fsm object. */

static struct call_thread_fsm *
-new_call_thread_fsm (struct ui *waiting_ui,
+new_call_thread_fsm (struct ui *waiting_ui, struct interp *cmd_interp,
struct gdbarch *gdbarch, struct value *function,
struct type *value_type,
int struct_return_p, CORE_ADDR struct_addr)
@@ -496,7 +497,7 @@ new_call_thread_fsm (struct ui *waiting_ui,
struct call_thread_fsm *sm;

sm = XCNEW (struct call_thread_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &call_thread_fsm_ops);
+ thread_fsm_ctor (&sm->thread_fsm, &call_thread_fsm_ops, cmd_interp);

sm->return_meta_info.gdbarch = gdbarch;
sm->return_meta_info.function = function;
@@ -512,7 +513,8 @@ new_call_thread_fsm (struct ui *waiting_ui,
/* Implementation of should_stop method for infcalls. */

static int
-call_thread_fsm_should_stop (struct thread_fsm *self)
+call_thread_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread)
{
struct call_thread_fsm *f = (struct call_thread_fsm *) self;

@@ -1135,7 +1137,7 @@ call_function_by_hand_dummy (struct value *function,
not report the stop to the user, and captures the return value
before the dummy frame is popped. run_inferior_call registers
it with the thread ASAP. */
- sm = new_call_thread_fsm (current_ui,
+ sm = new_call_thread_fsm (current_ui, command_interp (),
gdbarch, function,
values_type,
struct_return || hidden_first_param_p,
@@ -1167,7 +1169,7 @@ call_function_by_hand_dummy (struct value *function,

/* Clean up / destroy the call FSM, and restore the
original one. */
- thread_fsm_clean_up (tp->thread_fsm);
+ thread_fsm_clean_up (tp->thread_fsm, tp);
thread_fsm_delete (tp->thread_fsm);
tp->thread_fsm = saved_sm;

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index a1d4d5d..6b1d6a4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -57,6 +57,7 @@
#include "infcall.h"
#include "thread-fsm.h"
#include "top.h"
+#include "interps.h"

/* Local functions: */

@@ -925,13 +926,12 @@ struct step_command_fsm

/* If true, this is a stepi/nexti, otherwise a step/step. */
int single_inst;
-
- /* The thread that the command was run on. */
- int thread;
};

-static void step_command_fsm_clean_up (struct thread_fsm *self);
-static int step_command_fsm_should_stop (struct thread_fsm *self);
+static void step_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
+static int step_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
static enum async_reply_reason
step_command_fsm_async_reply_reason (struct thread_fsm *self);

@@ -949,12 +949,12 @@ static struct thread_fsm_ops step_command_fsm_ops =
/* Allocate a new step_command_fsm. */

static struct step_command_fsm *
-new_step_command_fsm (void)
+new_step_command_fsm (struct interp *cmd_interp)
{
struct step_command_fsm *sm;

sm = XCNEW (struct step_command_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops);
+ thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops, cmd_interp);

return sm;
}
@@ -970,7 +970,6 @@ step_command_fsm_prepare (struct step_command_fsm *sm,
sm->skip_subroutines = skip_subroutines;
sm->single_inst = single_inst;
sm->count = count;
- sm->thread = thread->global_num;

/* Leave the si command alone. */
if (!sm->single_inst || sm->skip_subroutines)
@@ -1010,7 +1009,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
/* Setup the execution command state machine to handle all the COUNT
steps. */
thr = inferior_thread ();
- step_sm = new_step_command_fsm ();
+ step_sm = new_step_command_fsm (command_interp ());
thr->thread_fsm = &step_sm->thread_fsm;

step_command_fsm_prepare (step_sm, skip_subroutines,
@@ -1028,7 +1027,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)

/* Stepped into an inline frame. Pretend that we've
stopped. */
- thread_fsm_clean_up (thr->thread_fsm);
+ thread_fsm_clean_up (thr->thread_fsm, thr);
proceeded = normal_stop ();
if (!proceeded)
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
@@ -1043,10 +1042,9 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
will need to keep going. */

static int
-step_command_fsm_should_stop (struct thread_fsm *self)
+step_command_fsm_should_stop (struct thread_fsm *self, struct thread_info *tp)
{
struct step_command_fsm *sm = (struct step_command_fsm *) self;
- struct thread_info *tp = find_thread_global_id (sm->thread);

if (tp->control.stop_step)
{
@@ -1064,12 +1062,12 @@ step_command_fsm_should_stop (struct thread_fsm *self)
/* Implementation of the 'clean_up' FSM method for stepping commands. */

static void
-step_command_fsm_clean_up (struct thread_fsm *self)
+step_command_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
{
struct step_command_fsm *sm = (struct step_command_fsm *) self;

if (!sm->single_inst || sm->skip_subroutines)
- delete_longjmp_breakpoint (sm->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}

/* Implementation of the 'async_reply_reason' FSM method for stepping
@@ -1411,8 +1409,10 @@ struct until_next_fsm
int thread;
};

-static int until_next_fsm_should_stop (struct thread_fsm *self);
-static void until_next_fsm_clean_up (struct thread_fsm *self);
+static int until_next_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
+static void until_next_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
static enum async_reply_reason
until_next_fsm_async_reply_reason (struct thread_fsm *self);

@@ -1430,12 +1430,12 @@ static struct thread_fsm_ops until_next_fsm_ops =
/* Allocate a new until_next_fsm. */

static struct until_next_fsm *
-new_until_next_fsm (int thread)
+new_until_next_fsm (struct interp *cmd_interp, int thread)
{
struct until_next_fsm *sm;

sm = XCNEW (struct until_next_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops);
+ thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops, cmd_interp);

sm->thread = thread;

@@ -1446,10 +1446,9 @@ new_until_next_fsm (int thread)
no arg) command. */

static int
-until_next_fsm_should_stop (struct thread_fsm *self)
+until_next_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
{
- struct thread_info *tp = inferior_thread ();
-
if (tp->control.stop_step)
thread_fsm_set_finished (self);

@@ -1460,11 +1459,11 @@ until_next_fsm_should_stop (struct thread_fsm *self)
arg) command. */

static void
-until_next_fsm_clean_up (struct thread_fsm *self)
+until_next_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
{
struct until_next_fsm *sm = (struct until_next_fsm *) self;

- delete_longjmp_breakpoint (sm->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}

/* Implementation of the 'async_reply_reason' FSM method for the until
@@ -1534,7 +1533,7 @@ until_next_command (int from_tty)
set_longjmp_breakpoint (tp, get_frame_id (frame));
old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);

- sm = new_until_next_fsm (tp->global_num);
+ sm = new_until_next_fsm (command_interp (), tp->global_num);
tp->thread_fsm = &sm->thread_fsm;
discard_cleanups (old_chain);

@@ -1729,9 +1728,6 @@ struct finish_command_fsm
/* The base class. */
struct thread_fsm thread_fsm;

- /* The thread that was current when the command was executed. */
- int thread;
-
/* The momentary breakpoint set at the function's return address in
the caller. */
struct breakpoint *breakpoint;
@@ -1744,8 +1740,10 @@ struct finish_command_fsm
struct return_value_info return_value;
};

-static int finish_command_fsm_should_stop (struct thread_fsm *self);
-static void finish_command_fsm_clean_up (struct thread_fsm *self);
+static int finish_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
+static void finish_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
static struct return_value_info *
finish_command_fsm_return_value (struct thread_fsm *self);
static enum async_reply_reason
@@ -1760,19 +1758,18 @@ static struct thread_fsm_ops finish_command_fsm_ops =
finish_command_fsm_should_stop,
finish_command_fsm_return_value,
finish_command_fsm_async_reply_reason,
+ NULL, /* should_notify_stop */
};

/* Allocate a new finish_command_fsm. */

static struct finish_command_fsm *
-new_finish_command_fsm (int thread)
+new_finish_command_fsm (struct interp *cmd_interp)
{
struct finish_command_fsm *sm;

sm = XCNEW (struct finish_command_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops);
-
- sm->thread = thread;
+ thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);

return sm;
}
@@ -1783,11 +1780,11 @@ new_finish_command_fsm (int thread)
marks the FSM finished. */

static int
-finish_command_fsm_should_stop (struct thread_fsm *self)
+finish_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
{
struct finish_command_fsm *f = (struct finish_command_fsm *) self;
struct return_value_info *rv = &f->return_value;
- struct thread_info *tp = find_thread_global_id (f->thread);

if (f->function != NULL
&& bpstat_find_breakpoint (tp->control.stop_bpstat,
@@ -1825,7 +1822,8 @@ finish_command_fsm_should_stop (struct thread_fsm *self)
commands. */

static void
-finish_command_fsm_clean_up (struct thread_fsm *self)
+finish_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread)
{
struct finish_command_fsm *f = (struct finish_command_fsm *) self;

@@ -1834,7 +1832,7 @@ finish_command_fsm_clean_up (struct thread_fsm *self)
delete_breakpoint (f->breakpoint);
f->breakpoint = NULL;
}
- delete_longjmp_breakpoint (f->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}

/* Implementation of the 'return_value' FSM method for the finish
@@ -1980,7 +1978,7 @@ finish_command (char *arg, int from_tty)

tp = inferior_thread ();

- sm = new_finish_command_fsm (tp->global_num);
+ sm = new_finish_command_fsm (command_interp ());

tp->thread_fsm = &sm->thread_fsm;

diff --git a/gdb/infrun.c b/gdb/infrun.c
index cc793c3..a7b5a60 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -683,7 +683,7 @@ follow_fork (void)
CORE_ADDR step_range_start = 0;
CORE_ADDR step_range_end = 0;
struct frame_id step_frame_id = { 0 };
- struct interp *command_interp = NULL;
+ struct thread_fsm *thread_fsm = NULL;

if (!non_stop)
{
@@ -735,7 +735,7 @@ follow_fork (void)
step_frame_id = tp->control.step_frame_id;
exception_resume_breakpoint
= clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
- command_interp = tp->control.command_interp;
+ thread_fsm = tp->thread_fsm;

/* For now, delete the parent's sr breakpoint, otherwise,
parent/child sr breakpoints are considered duplicates,
@@ -747,7 +747,7 @@ follow_fork (void)
tp->control.step_range_end = 0;
tp->control.step_frame_id = null_frame_id;
delete_exception_resume_breakpoint (tp);
- tp->control.command_interp = NULL;
+ tp->thread_fsm = NULL;
}

parent = inferior_ptid;
@@ -793,7 +793,7 @@ follow_fork (void)
tp->control.step_frame_id = step_frame_id;
tp->control.exception_resume_breakpoint
= exception_resume_breakpoint;
- tp->control.command_interp = command_interp;
+ tp->thread_fsm = thread_fsm;
}
else
{
@@ -2852,7 +2852,6 @@ clear_proceed_status_thread (struct thread_info *tp)

tp->control.proceed_to_finish = 0;

- tp->control.command_interp = NULL;
tp->control.stepping_command = 0;

/* Discard any remaining commands or status from previous stop. */
@@ -3046,14 +3045,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
if (siggnal != GDB_SIGNAL_DEFAULT)
tp->suspend.stop_signal = siggnal;

- /* Record the interpreter that issued the execution command that
- caused this thread to resume. If the top level interpreter is
- MI/async, and the execution command was a CLI command
- (next/step/etc.), we'll want to print stop event output to the MI
- console channel (the stepped-to line, etc.), as if the user
- entered the execution command on a real GDB console. */
- tp->control.command_interp = command_interp ();
-
resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);

/* If an exception is thrown from this point on, make sure to
@@ -3827,7 +3818,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
struct thread_info *thr = ecs->event_thread;

if (thr != NULL && thr->thread_fsm != NULL)
- thread_fsm_clean_up (thr->thread_fsm);
+ thread_fsm_clean_up (thr->thread_fsm, thr);

if (!non_stop)
{
@@ -3839,7 +3830,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
continue;

switch_to_thread (thr->ptid);
- thread_fsm_clean_up (thr->thread_fsm);
+ thread_fsm_clean_up (thr->thread_fsm, thr);
}

if (ecs->event_thread != NULL)
@@ -3997,7 +3988,7 @@ fetch_inferior_event (void *client_data)
struct thread_fsm *thread_fsm = thr->thread_fsm;

if (thread_fsm != NULL)
- should_stop = thread_fsm_should_stop (thread_fsm);
+ should_stop = thread_fsm_should_stop (thread_fsm, thr);
}

if (!should_stop)
diff --git a/gdb/testsuite/gdb.opt/inline-cmds.c b/gdb/testsuite/gdb.opt/inline-cmds.c
index 20e1d0b..59631d7 100644
--- a/gdb/testsuite/gdb.opt/inline-cmds.c
+++ b/gdb/testsuite/gdb.opt/inline-cmds.c
@@ -61,7 +61,7 @@ int main (void)
int val;

x = 7;
- y = 8;
+ y = 8; /* set mi break here */

result = func1 ();
result = func2 ();
diff --git a/gdb/testsuite/gdb.opt/inline-cmds.exp b/gdb/testsuite/gdb.opt/inline-cmds.exp
index d57a333..684f4dd 100644
--- a/gdb/testsuite/gdb.opt/inline-cmds.exp
+++ b/gdb/testsuite/gdb.opt/inline-cmds.exp
@@ -13,6 +13,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
standard_testfile .c inline-markers.c

if {[prepare_for_testing $testfile.exp $testfile \
@@ -315,3 +318,62 @@ gdb_test "up" "#3 .*outer_inline2.*" "up to outer_inline2"
gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined"
gdb_test "up" "#4 main.*" "up from outer_inline2"
gdb_test "info frame" ".*\n caller of frame.*" "main not inlined"
+
+gdb_exit
+
+# Send a CLI "step" command over MI. CLI_OUTPUT_RE is a regexp that
+# matches the expected CLI output. MESSAGE is used as test message.
+
+proc mi_cli_step {cli_output_re message} {
+ global mi_gdb_prompt
+ global srcfile
+ global decimal
+
+ send_gdb "interpreter-exec console \"step\"\n"
+ gdb_expect {
+ -re "\\^running\r\n\\*running,thread-id=\"all\"\r\n${mi_gdb_prompt}${cli_output_re}" {
+ pass $message
+ }
+ timeout {
+ fail "$message (timeout)"
+ }
+ eof {
+ fail "$message (eof)"
+ }
+ }
+
+ # mi_expect_stop handles "set mi-async on/off" differences.
+ mi_expect_stop "end-stepping-range" "\[^\r\n\]*" "" ".*$srcfile" "$decimal" \
+ "" "got *stopped for $message"
+}
+
+# Test that stepping into an inlined function with the CLI "step"
+# command run while the top interpreter is MI results in the expected
+# CLI output sent to MI's console.
+with_test_prefix "mi" {
+ if [mi_gdb_start] {
+ continue
+ }
+ mi_gdb_load ${binfile}
+ mi_runto main
+
+ set line_number [gdb_get_line_number "set mi break here"]
+ mi_gdb_test "-break-insert ${srcfile}:${line_number}" \
+ {\^done,bkpt=.number="2",type="breakpoint".*\}} \
+ "set breakpoint"
+
+ mi_execute_to "exec-continue" "breakpoint-hit" "main" "" ".*" ".*" \
+ { "" "disp=\"keep\"" } "breakpoint hit"
+
+ incr line_number 2
+
+ # Step to the line that does an inline call.
+ set re "~\"$line_number\\\\t result = func1 \\(\\);\\\\n\"\r\n"
+ mi_cli_step "${re}" "step to inline call"
+
+ # Step into the inlined function.
+ set re [multi_line \
+ "~\"func1 \\(\\) at .*$srcfile:$decimal\\\\n\"" \
+ "~\"$decimal\\\\t bar \\(\\);\\\\n\"\r\n"]
+ mi_cli_step "${re}" "step into inline call"
+}
diff --git a/gdb/thread-fsm.c b/gdb/thread-fsm.c
index 52b4eb8..5ba4d56 100644
--- a/gdb/thread-fsm.c
+++ b/gdb/thread-fsm.c
@@ -22,8 +22,10 @@
/* See thread-fsm.h. */

void
-thread_fsm_ctor (struct thread_fsm *self, struct thread_fsm_ops *ops)
+thread_fsm_ctor (struct thread_fsm *self, struct thread_fsm_ops *ops,
+ struct interp *cmd_interp)
{
+ self->command_interp = cmd_interp;
self->finished = 0;
self->ops = ops;
}
@@ -44,18 +46,18 @@ thread_fsm_delete (struct thread_fsm *self)
/* See thread-fsm.h. */

void
-thread_fsm_clean_up (struct thread_fsm *self)
+thread_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
{
if (self->ops->clean_up != NULL)
- self->ops->clean_up (self);
+ self->ops->clean_up (self, thread);
}

/* See thread-fsm.h. */

int
-thread_fsm_should_stop (struct thread_fsm *self)
+thread_fsm_should_stop (struct thread_fsm *self, struct thread_info *thread)
{
- return self->ops->should_stop (self);
+ return self->ops->should_stop (self, thread);
}

/* See thread-fsm.h. */
diff --git a/gdb/thread-fsm.h b/gdb/thread-fsm.h
index b0f4c44..86fb81f 100644
--- a/gdb/thread-fsm.h
+++ b/gdb/thread-fsm.h
@@ -35,6 +35,14 @@ struct thread_fsm

/* Whether the FSM is done successfully. */
int finished;
+
+ /* The interpreter that issued the execution command that caused
+ this thread to resume. If the top level interpreter is MI/async,
+ and the execution command was a CLI command (next/step/etc.),
+ we'll want to print stop event output to the MI console channel
+ (the stepped-to line, etc.), as if the user entered the execution
+ command on a real GDB console. */
+ struct interp *command_interp;
};

/* The virtual table of a thread_fsm. */
@@ -49,7 +57,7 @@ struct thread_fsm_ops
/* Called to clean up target resources after the FSM. E.g., if the
FSM created internal breakpoints, this is where they should be
deleted. */
- void (*clean_up) (struct thread_fsm *self);
+ void (*clean_up) (struct thread_fsm *self, struct thread_info *thread);

/* Called after handle_inferior_event decides the target is done
(that is, after stop_waiting). The FSM is given a chance to
@@ -58,7 +66,7 @@ struct thread_fsm_ops
should be re-resumed. This is a good place to cache target data
too. For example, the "finish" command saves the just-finished
function's return value here. */
- int (*should_stop) (struct thread_fsm *self);
+ int (*should_stop) (struct thread_fsm *self, struct thread_info *thread);

/* If this FSM saved a function's return value, you can use this
method to retrieve it. Otherwise, this returns NULL. */
@@ -72,17 +80,20 @@ struct thread_fsm_ops
int (*should_notify_stop) (struct thread_fsm *self);
};
/* Initialize FSM. */
-extern void thread_fsm_ctor (struct thread_fsm *fsm,
- struct thread_fsm_ops *ops);
+extern void thread_fsm_ctor (struct thread_fsm *self,
+ struct thread_fsm_ops *ops,
+ struct interp *cmd_interp);

/* Calls the FSM's dtor method, and then frees FSM. */
extern void thread_fsm_delete (struct thread_fsm *fsm);

/* Calls the FSM's clean_up method. */
-extern void thread_fsm_clean_up (struct thread_fsm *fsm);
+extern void thread_fsm_clean_up (struct thread_fsm *fsm,
+ struct thread_info *thread);

/* Calls the FSM's should_stop method. */
-extern int thread_fsm_should_stop (struct thread_fsm *fsm);
+extern int thread_fsm_should_stop (struct thread_fsm *fsm,
+ struct thread_info *thread);

/* Calls the FSM's return_value method. */
extern struct return_value_info *
diff --git a/gdb/thread.c b/gdb/thread.c
index 75bfb47..91967e9 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -166,7 +166,7 @@ thread_cancel_execution_command (struct thread_info *thr)
{
if (thr->thread_fsm != NULL)
{
- thread_fsm_clean_up (thr->thread_fsm);
+ thread_fsm_clean_up (thr->thread_fsm, thr);
thread_fsm_delete (thr->thread_fsm);
thr->thread_fsm = NULL;
}
--
2.5.5