Push thread->control.command_interp to the struct thread_fsm

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:
2016-06-21  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:
2016-06-21  Pedro Alves  <palves@redhat.com>

	* gdb.opt/inline-cmds.c: Add "set mi break here" marker.
	* gdb.opt/inline-cmds.exp: Add MI tests.
This commit is contained in:
Pedro Alves
2016-06-21 01:11:53 +01:00
parent 26cde2cc30
commit 8980e177bb
13 changed files with 214 additions and 90 deletions

View File

@ -1,3 +1,59 @@
2016-06-21 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.
2016-06-21 Pedro Alves <palves@redhat.com> 2016-06-21 Pedro Alves <palves@redhat.com>
* cli/cli-interp.c: Include gdbthread.h and thread-fsm.h. * cli/cli-interp.c: Include gdbthread.h and thread-fsm.h.

View File

@ -11605,8 +11605,10 @@ struct until_break_fsm
struct breakpoint *caller_breakpoint; struct breakpoint *caller_breakpoint;
}; };
static void until_break_fsm_clean_up (struct thread_fsm *self); static void until_break_fsm_clean_up (struct thread_fsm *self,
static int until_break_fsm_should_stop (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 static enum async_reply_reason
until_break_fsm_async_reply_reason (struct thread_fsm *self); until_break_fsm_async_reply_reason (struct thread_fsm *self);
@ -11624,14 +11626,14 @@ static struct thread_fsm_ops until_break_fsm_ops =
/* Allocate a new until_break_command_fsm. */ /* Allocate a new until_break_command_fsm. */
static struct until_break_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 *location_breakpoint,
struct breakpoint *caller_breakpoint) struct breakpoint *caller_breakpoint)
{ {
struct until_break_fsm *sm; struct until_break_fsm *sm;
sm = XCNEW (struct until_break_fsm); 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->thread = thread;
sm->location_breakpoint = location_breakpoint; sm->location_breakpoint = location_breakpoint;
@ -11644,10 +11646,10 @@ new_until_break_fsm (int thread,
until(location)/advance commands. */ until(location)/advance commands. */
static int 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 until_break_fsm *sm = (struct until_break_fsm *) self;
struct thread_info *tp = inferior_thread ();
if (bpstat_find_breakpoint (tp->control.stop_bpstat, if (bpstat_find_breakpoint (tp->control.stop_bpstat,
sm->location_breakpoint) != NULL sm->location_breakpoint) != NULL
@ -11663,7 +11665,8 @@ until_break_fsm_should_stop (struct thread_fsm *self)
until(location)/advance commands. */ until(location)/advance commands. */
static void 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; struct until_break_fsm *sm = (struct until_break_fsm *) self;
@ -11785,7 +11788,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
stack_frame_id, bp_until); stack_frame_id, bp_until);
make_cleanup_delete_breakpoint (location_breakpoint); 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); location_breakpoint, caller_breakpoint);
tp->thread_fsm = &sm->thread_fsm; tp->thread_fsm = &sm->thread_fsm;

View File

@ -77,10 +77,9 @@ should_print_stop_to_console (struct interp *console_interp,
{ {
if ((bpstat_what (tp->control.stop_bpstat).main_action if ((bpstat_what (tp->control.stop_bpstat).main_action
== BPSTAT_WHAT_STOP_NOISY) == BPSTAT_WHAT_STOP_NOISY)
|| !(tp->thread_fsm != NULL || tp->thread_fsm == NULL
&& thread_fsm_finished_p (tp->thread_fsm)) || tp->thread_fsm->command_interp == console_interp
|| (tp->control.command_interp != NULL || !thread_fsm_finished_p (tp->thread_fsm))
&& tp->control.command_interp == console_interp))
return 1; return 1;
return 0; return 0;
} }

View File

@ -136,11 +136,6 @@ struct thread_control_state
at. */ at. */
bpstat stop_bpstat; 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 /* Whether the command that started the thread was a stepping
command. This is used to decide whether "set scheduler-locking command. This is used to decide whether "set scheduler-locking
step" behaves like "on" or "off". */ step" behaves like "on" or "off". */

View File

@ -470,7 +470,8 @@ struct call_thread_fsm
struct ui *waiting_ui; 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); static int call_thread_fsm_should_notify_stop (struct thread_fsm *self);
/* call_thread_fsm's vtable. */ /* 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. */ /* Allocate a new call_thread_fsm object. */
static struct call_thread_fsm * 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 gdbarch *gdbarch, struct value *function,
struct type *value_type, struct type *value_type,
int struct_return_p, CORE_ADDR struct_addr) 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; struct call_thread_fsm *sm;
sm = XCNEW (struct call_thread_fsm); 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.gdbarch = gdbarch;
sm->return_meta_info.function = function; 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. */ /* Implementation of should_stop method for infcalls. */
static int 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; 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 not report the stop to the user, and captures the return value
before the dummy frame is popped. run_inferior_call registers before the dummy frame is popped. run_inferior_call registers
it with the thread ASAP. */ it with the thread ASAP. */
sm = new_call_thread_fsm (current_ui, sm = new_call_thread_fsm (current_ui, command_interp (),
gdbarch, function, gdbarch, function,
values_type, values_type,
struct_return || hidden_first_param_p, 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 /* Clean up / destroy the call FSM, and restore the
original one. */ original one. */
thread_fsm_clean_up (tp->thread_fsm); thread_fsm_clean_up (tp->thread_fsm, tp);
thread_fsm_delete (tp->thread_fsm); thread_fsm_delete (tp->thread_fsm);
tp->thread_fsm = saved_sm; tp->thread_fsm = saved_sm;

View File

@ -57,6 +57,7 @@
#include "infcall.h" #include "infcall.h"
#include "thread-fsm.h" #include "thread-fsm.h"
#include "top.h" #include "top.h"
#include "interps.h"
/* Local functions: */ /* Local functions: */
@ -925,13 +926,12 @@ struct step_command_fsm
/* If true, this is a stepi/nexti, otherwise a step/step. */ /* If true, this is a stepi/nexti, otherwise a step/step. */
int single_inst; 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 void step_command_fsm_clean_up (struct thread_fsm *self,
static int step_command_fsm_should_stop (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 static enum async_reply_reason
step_command_fsm_async_reply_reason (struct thread_fsm *self); 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. */ /* Allocate a new step_command_fsm. */
static struct 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; struct step_command_fsm *sm;
sm = XCNEW (struct step_command_fsm); 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; return sm;
} }
@ -970,7 +970,6 @@ step_command_fsm_prepare (struct step_command_fsm *sm,
sm->skip_subroutines = skip_subroutines; sm->skip_subroutines = skip_subroutines;
sm->single_inst = single_inst; sm->single_inst = single_inst;
sm->count = count; sm->count = count;
sm->thread = thread->global_num;
/* Leave the si command alone. */ /* Leave the si command alone. */
if (!sm->single_inst || sm->skip_subroutines) 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 /* Setup the execution command state machine to handle all the COUNT
steps. */ steps. */
thr = inferior_thread (); thr = inferior_thread ();
step_sm = new_step_command_fsm (); step_sm = new_step_command_fsm (command_interp ());
thr->thread_fsm = &step_sm->thread_fsm; thr->thread_fsm = &step_sm->thread_fsm;
step_command_fsm_prepare (step_sm, skip_subroutines, 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 /* Stepped into an inline frame. Pretend that we've
stopped. */ stopped. */
thread_fsm_clean_up (thr->thread_fsm); thread_fsm_clean_up (thr->thread_fsm, thr);
proceeded = normal_stop (); proceeded = normal_stop ();
if (!proceeded) if (!proceeded)
inferior_event_handler (INF_EXEC_COMPLETE, NULL); 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. */ will need to keep going. */
static int 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 step_command_fsm *sm = (struct step_command_fsm *) self;
struct thread_info *tp = find_thread_global_id (sm->thread);
if (tp->control.stop_step) 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. */ /* Implementation of the 'clean_up' FSM method for stepping commands. */
static void 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; struct step_command_fsm *sm = (struct step_command_fsm *) self;
if (!sm->single_inst || sm->skip_subroutines) 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 /* Implementation of the 'async_reply_reason' FSM method for stepping
@ -1411,8 +1409,10 @@ struct until_next_fsm
int thread; int thread;
}; };
static int until_next_fsm_should_stop (struct thread_fsm *self); static int until_next_fsm_should_stop (struct thread_fsm *self,
static void until_next_fsm_clean_up (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 static enum async_reply_reason
until_next_fsm_async_reply_reason (struct thread_fsm *self); 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. */ /* Allocate a new until_next_fsm. */
static struct 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; struct until_next_fsm *sm;
sm = XCNEW (struct until_next_fsm); 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; sm->thread = thread;
@ -1446,10 +1446,9 @@ new_until_next_fsm (int thread)
no arg) command. */ no arg) command. */
static int 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) if (tp->control.stop_step)
thread_fsm_set_finished (self); thread_fsm_set_finished (self);
@ -1460,11 +1459,11 @@ until_next_fsm_should_stop (struct thread_fsm *self)
arg) command. */ arg) command. */
static void 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; 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 /* 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)); set_longjmp_breakpoint (tp, get_frame_id (frame));
old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); 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; tp->thread_fsm = &sm->thread_fsm;
discard_cleanups (old_chain); discard_cleanups (old_chain);
@ -1729,9 +1728,6 @@ struct finish_command_fsm
/* The base class. */ /* The base class. */
struct thread_fsm thread_fsm; 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 momentary breakpoint set at the function's return address in
the caller. */ the caller. */
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
@ -1744,8 +1740,10 @@ struct finish_command_fsm
struct return_value_info return_value; struct return_value_info return_value;
}; };
static int finish_command_fsm_should_stop (struct thread_fsm *self); static int finish_command_fsm_should_stop (struct thread_fsm *self,
static void finish_command_fsm_clean_up (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 * static struct return_value_info *
finish_command_fsm_return_value (struct thread_fsm *self); finish_command_fsm_return_value (struct thread_fsm *self);
static enum async_reply_reason 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_should_stop,
finish_command_fsm_return_value, finish_command_fsm_return_value,
finish_command_fsm_async_reply_reason, finish_command_fsm_async_reply_reason,
NULL, /* should_notify_stop */
}; };
/* Allocate a new finish_command_fsm. */ /* Allocate a new finish_command_fsm. */
static struct 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; struct finish_command_fsm *sm;
sm = XCNEW (struct finish_command_fsm); sm = XCNEW (struct finish_command_fsm);
thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops); thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);
sm->thread = thread;
return sm; return sm;
} }
@ -1783,11 +1780,11 @@ new_finish_command_fsm (int thread)
marks the FSM finished. */ marks the FSM finished. */
static int 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 finish_command_fsm *f = (struct finish_command_fsm *) self;
struct return_value_info *rv = &f->return_value; struct return_value_info *rv = &f->return_value;
struct thread_info *tp = find_thread_global_id (f->thread);
if (f->function != NULL if (f->function != NULL
&& bpstat_find_breakpoint (tp->control.stop_bpstat, && bpstat_find_breakpoint (tp->control.stop_bpstat,
@ -1825,7 +1822,8 @@ finish_command_fsm_should_stop (struct thread_fsm *self)
commands. */ commands. */
static void 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; 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); delete_breakpoint (f->breakpoint);
f->breakpoint = NULL; f->breakpoint = NULL;
} }
delete_longjmp_breakpoint (f->thread); delete_longjmp_breakpoint (thread->global_num);
} }
/* Implementation of the 'return_value' FSM method for the finish /* Implementation of the 'return_value' FSM method for the finish
@ -2002,7 +2000,7 @@ finish_command (char *arg, int from_tty)
tp = inferior_thread (); tp = inferior_thread ();
sm = new_finish_command_fsm (tp->global_num); sm = new_finish_command_fsm (command_interp ());
tp->thread_fsm = &sm->thread_fsm; tp->thread_fsm = &sm->thread_fsm;

View File

@ -681,7 +681,7 @@ follow_fork (void)
CORE_ADDR step_range_start = 0; CORE_ADDR step_range_start = 0;
CORE_ADDR step_range_end = 0; CORE_ADDR step_range_end = 0;
struct frame_id step_frame_id = { 0 }; struct frame_id step_frame_id = { 0 };
struct interp *command_interp = NULL; struct thread_fsm *thread_fsm = NULL;
if (!non_stop) if (!non_stop)
{ {
@ -733,7 +733,7 @@ follow_fork (void)
step_frame_id = tp->control.step_frame_id; step_frame_id = tp->control.step_frame_id;
exception_resume_breakpoint exception_resume_breakpoint
= clone_momentary_breakpoint (tp->control.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, /* For now, delete the parent's sr breakpoint, otherwise,
parent/child sr breakpoints are considered duplicates, parent/child sr breakpoints are considered duplicates,
@ -745,7 +745,7 @@ follow_fork (void)
tp->control.step_range_end = 0; tp->control.step_range_end = 0;
tp->control.step_frame_id = null_frame_id; tp->control.step_frame_id = null_frame_id;
delete_exception_resume_breakpoint (tp); delete_exception_resume_breakpoint (tp);
tp->control.command_interp = NULL; tp->thread_fsm = NULL;
} }
parent = inferior_ptid; parent = inferior_ptid;
@ -791,7 +791,7 @@ follow_fork (void)
tp->control.step_frame_id = step_frame_id; tp->control.step_frame_id = step_frame_id;
tp->control.exception_resume_breakpoint tp->control.exception_resume_breakpoint
= exception_resume_breakpoint; = exception_resume_breakpoint;
tp->control.command_interp = command_interp; tp->thread_fsm = thread_fsm;
} }
else else
{ {
@ -2849,7 +2849,6 @@ clear_proceed_status_thread (struct thread_info *tp)
tp->control.proceed_to_finish = 0; tp->control.proceed_to_finish = 0;
tp->control.command_interp = NULL;
tp->control.stepping_command = 0; tp->control.stepping_command = 0;
/* Discard any remaining commands or status from previous stop. */ /* Discard any remaining commands or status from previous stop. */
@ -3042,14 +3041,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
if (siggnal != GDB_SIGNAL_DEFAULT) if (siggnal != GDB_SIGNAL_DEFAULT)
tp->suspend.stop_signal = siggnal; 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); resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
/* If an exception is thrown from this point on, make sure to /* If an exception is thrown from this point on, make sure to
@ -3823,7 +3814,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
struct thread_info *thr = ecs->event_thread; struct thread_info *thr = ecs->event_thread;
if (thr != NULL && thr->thread_fsm != NULL) 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) if (!non_stop)
{ {
@ -3835,7 +3826,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
continue; continue;
switch_to_thread (thr->ptid); 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) if (ecs->event_thread != NULL)
@ -3993,7 +3984,7 @@ fetch_inferior_event (void *client_data)
struct thread_fsm *thread_fsm = thr->thread_fsm; struct thread_fsm *thread_fsm = thr->thread_fsm;
if (thread_fsm != NULL) if (thread_fsm != NULL)
should_stop = thread_fsm_should_stop (thread_fsm); should_stop = thread_fsm_should_stop (thread_fsm, thr);
} }
if (!should_stop) if (!should_stop)

View File

@ -1,3 +1,8 @@
2016-06-21 Pedro Alves <palves@redhat.com>
* gdb.opt/inline-cmds.c: Add "set mi break here" marker.
* gdb.opt/inline-cmds.exp: Add MI tests.
2016-06-21 Pedro Alves <palves@redhat.com> 2016-06-21 Pedro Alves <palves@redhat.com>
* gdb.gdb/selftest.exp (do_steps_and_nexts): Add new regexp. * gdb.gdb/selftest.exp (do_steps_and_nexts): Add new regexp.

View File

@ -61,7 +61,7 @@ int main (void)
int val; int val;
x = 7; x = 7;
y = 8; y = 8; /* set mi break here */
result = func1 (); result = func1 ();
result = func2 (); result = func2 ();

View File

@ -13,6 +13,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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 standard_testfile .c inline-markers.c
if {[prepare_for_testing $testfile.exp $testfile \ 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 "info frame" ".*inlined into frame.*" "outer_inline2 inlined"
gdb_test "up" "#4 main.*" "up from outer_inline2" gdb_test "up" "#4 main.*" "up from outer_inline2"
gdb_test "info frame" ".*\n caller of frame.*" "main not inlined" 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"
}

View File

@ -22,8 +22,10 @@
/* See thread-fsm.h. */ /* See thread-fsm.h. */
void 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->finished = 0;
self->ops = ops; self->ops = ops;
} }
@ -44,18 +46,18 @@ thread_fsm_delete (struct thread_fsm *self)
/* See thread-fsm.h. */ /* See thread-fsm.h. */
void 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) if (self->ops->clean_up != NULL)
self->ops->clean_up (self); self->ops->clean_up (self, thread);
} }
/* See thread-fsm.h. */ /* See thread-fsm.h. */
int 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. */ /* See thread-fsm.h. */

View File

@ -35,6 +35,14 @@ struct thread_fsm
/* Whether the FSM is done successfully. */ /* Whether the FSM is done successfully. */
int finished; 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. */ /* 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 /* Called to clean up target resources after the FSM. E.g., if the
FSM created internal breakpoints, this is where they should be FSM created internal breakpoints, this is where they should be
deleted. */ 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 /* Called after handle_inferior_event decides the target is done
(that is, after stop_waiting). The FSM is given a chance to (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 should be re-resumed. This is a good place to cache target data
too. For example, the "finish" command saves the just-finished too. For example, the "finish" command saves the just-finished
function's return value here. */ 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 /* If this FSM saved a function's return value, you can use this
method to retrieve it. Otherwise, this returns NULL. */ method to retrieve it. Otherwise, this returns NULL. */
@ -72,17 +80,20 @@ struct thread_fsm_ops
int (*should_notify_stop) (struct thread_fsm *self); int (*should_notify_stop) (struct thread_fsm *self);
}; };
/* Initialize FSM. */ /* Initialize FSM. */
extern void thread_fsm_ctor (struct thread_fsm *fsm, extern void thread_fsm_ctor (struct thread_fsm *self,
struct thread_fsm_ops *ops); struct thread_fsm_ops *ops,
struct interp *cmd_interp);
/* Calls the FSM's dtor method, and then frees FSM. */ /* Calls the FSM's dtor method, and then frees FSM. */
extern void thread_fsm_delete (struct thread_fsm *fsm); extern void thread_fsm_delete (struct thread_fsm *fsm);
/* Calls the FSM's clean_up method. */ /* 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. */ /* 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. */ /* Calls the FSM's return_value method. */
extern struct return_value_info * extern struct return_value_info *

View File

@ -166,7 +166,7 @@ thread_cancel_execution_command (struct thread_info *thr)
{ {
if (thr->thread_fsm != NULL) 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); thread_fsm_delete (thr->thread_fsm);
thr->thread_fsm = NULL; thr->thread_fsm = NULL;
} }