[non-stop] 07/10 non-stop inferior control

Pedro Alves
2008-06-15T21:05:46Z

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

This patch adds the base inferior control support for non-stop mode.

In non-stop mode, each thread is handled individually.  It should
behave close to having a separate debugger attached to each thread.
To accomplish that, as soon as we have an event, we context switch
to it, and go on handling it.  The cases of hiting a breakpoint
in another thread while we're stepping don't need to be handled
specially, as each thread will have its own stepping state.

Another difference in non-stop mode, is that exec commands
apply only to the selected thread; the target is never told
to resume all threads -- much like with scheduler locking
on.

It is also needed to have support to interrupt/suspend a simple
thread so a new target_stop_ptid method was added to request
the target to interrupt a single thread.

Several checks have been added so GDB doesn't try to do
things with running threads, which don't make sense,
like asking for the current PC of an executing thread.

"info threads" now shows "(running)" instead of info on the
selected frame, on running threads.  MI support will be
added on top.

--
Pedro Alves

[-- Attachment #2: 007-non_stop_core.diff --]
[-- Type: text/x-diff, Size: 22929 bytes --]

2008-06-15 Pedro Alves <pedro@codesourcery.com>

* infrun.c (resume): In non-stop mode, always resume just one
thread.
(proceed): Don't call prepare_to_proceed in non-stop mode.
(fetch_inferior_event): In non-stop mode, switch context before
handling the event.
(error_is_running, ensure_not_running): New.
(handle_inferior_event): In non-stop mode: Mark only the event
thread as stopped. Require that the target module manages adding
threads to the thread list. Don't switch to
infwait_thread_hop_state.
(normal_stop): Only mark not-running if inferior hasn't exited.
In non-stop mode, only mark the event thread.

* thread.c:Include "cli/cli-decode.h".
(print_thread_info): Don't read from a running thread.
Output "(running)" if thread is running.
(switch_to_thread): Don't read stop_pc if thread is executing.
(do_restore_current_thread_cleanup): Don't write to a running
thread.
(thread_apply_all_command): Don't read from a running thread. In
non-stop mode, do a full context-switch instead of just switching
threads.
(thread_apply_command): In non-stop mode, do a full context-switch
instead of just switching threads.
(do_captured_thread_select): Likewise. Inform user if selected
thread is running.
(_initialize_thread): Mark "info threads" and "thread" and
async_ok.

* inf-loop.c (inferior_event_handler): In non-stop mode, don't
unregister the target from the event loop.

* infcmd.c (continue_command, step_1, jump_command)
(signal_command): Ensure the selected thread isn't running.
(interrupt_target_command): In non-stop mode, interrupt only the
selected thread.

* inferior.h (error_is_running, ensure_not_running): Declare.

* target.h (struct target_ops): Add to_stop_ptid member.
(target_stop_ptid): Define.
* target.c (update_current_target): Inherit to_stop_ptid. Default
to_stop_ptid to target_ignore.
(debug_to_stop_ptid): New.
(debug_to_rcmd): Set to_stop_ptid.

* Makefile.in (thread.o): Update.

---
gdb/Makefile.in | 2
gdb/inf-loop.c | 14 ++++--
gdb/infcmd.c | 10 ++++
gdb/inferior.h | 6 ++
gdb/infrun.c | 126 ++++++++++++++++++++++++++++++++++++++++++--------------
gdb/target.c | 13 +++++
gdb/target.h | 7 +++
gdb/thread.c | 97 +++++++++++++++++++++++++++++++------------
8 files changed, 212 insertions(+), 63 deletions(-)

Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2008-06-15 20:06:41.000000000 +0100
+++ src/gdb/infrun.c 2008-06-15 20:26:51.000000000 +0100
@@ -1052,9 +1052,15 @@ a command like `return' or `jump' to con
resume_ptid = inferior_ptid;
}

- if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
+ if (non_stop)
+ {
+ /* With non-stop mode on, threads are always handled
+ individually. */
+ resume_ptid = inferior_ptid;
+ }
+ else if ((scheduler_mode == schedlock_on)
+ || (scheduler_mode == schedlock_step
+ && (step || singlestep_breakpoints_inserted_p)))
{
/* User-settable 'scheduler' mode requires solo thread resume. */
resume_ptid = inferior_ptid;
@@ -1215,19 +1221,27 @@ proceed (CORE_ADDR addr, enum target_sig
"infrun: proceed (addr=0x%s, signal=%d, step=%d)\n",
paddr_nz (addr), siggnal, step);

- /* In a multi-threaded task we may select another thread
- and then continue or step.
+ if (non_stop)
+ /* In non-stop, each thread is handled individually. The context
+ must already be set to the right thread here. */
+ ;
+ else
+ {
+ /* In a multi-threaded task we may select another thread and
+ then continue or step.

- But if the old thread was stopped at a breakpoint, it
- will immediately cause another breakpoint stop without
- any execution (i.e. it will report a breakpoint hit
- incorrectly). So we must step over it first.
-
- prepare_to_proceed checks the current thread against the thread
- that reported the most recent event. If a step-over is required
- it returns TRUE and sets the current thread to the old thread. */
- if (prepare_to_proceed (step))
- oneproc = 1;
+ But if the old thread was stopped at a breakpoint, it will
+ immediately cause another breakpoint stop without any
+ execution (i.e. it will report a breakpoint hit incorrectly).
+ So we must step over it first.
+
+ prepare_to_proceed checks the current thread against the
+ thread that reported the most recent event. If a step-over
+ is required it returns TRUE and sets the current thread to
+ the old thread. */
+ if (prepare_to_proceed (step))
+ oneproc = 1;
+ }

if (oneproc)
{
@@ -1529,6 +1543,15 @@ fetch_inferior_event (void *client_data)
else
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);

+ if (non_stop
+ && ecs->ws.kind != TARGET_WAITKIND_IGNORE
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+ /* In non-stop mode, each thread is handled individually. Switch
+ early, so the global state is set correctly for this
+ thread. */
+ context_switch (ecs->ptid);
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);

@@ -1739,6 +1762,20 @@ init_infwait_state (void)
infwait_state = infwait_normal_state;
}

+void
+error_is_running (void)
+{
+ error (_("\
+Cannot execute this command while the selected thread is running."));
+}
+
+void
+ensure_not_running (void)
+{
+ if (is_running (inferior_ptid))
+ error_is_running ();
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -1810,11 +1847,16 @@ handle_inferior_event (struct execution_
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);

- /* Mark all threads as not-executing. In non-stop, this should be
- adjusted to only mark ecs->ptid. */
- if (ecs->ws.kind != TARGET_WAITKIND_IGNORE
- && stop_soon != STOP_QUIETLY)
- set_executing (pid_to_ptid (-1), 0);
+ if (ecs->ws.kind != TARGET_WAITKIND_IGNORE)
+ {
+ /* Mark the stopped threads accordingly. */
+ if (!non_stop
+ || ecs->ws.kind == TARGET_WAITKIND_EXITED
+ || ecs->ws.kind == TARGET_WAITKIND_SIGNALLED)
+ set_executing (pid_to_ptid (-1), 0);
+ else
+ set_executing (ecs->ptid, 0);
+ }

switch (ecs->ws.kind)
{
@@ -2052,15 +2094,22 @@ handle_inferior_event (struct execution_
return;
}

- /* We may want to consider not doing a resume here in order to give
- the user a chance to play with the new thread. It might be good
- to make that a user-settable option. */
-
- /* At this point, all threads are stopped (happens automatically in
- either the OS or the native code). Therefore we need to continue
- all threads in order to make progress. */
if (ecs->new_thread_event)
{
+ if (non_stop)
+ /* Non-stop assumes that the target handles adding new threads
+ to the thread list. */
+ internal_error (__FILE__, __LINE__, "\
+targets should add new threads to the thread list themselves in non-stop mode.");
+
+ /* We may want to consider not doing a resume here in order to
+ give the user a chance to play with the new thread. It might
+ be good to make that a user-settable option. */
+
+ /* At this point, all threads are stopped (happens automatically
+ in either the OS or the native code). Therefore we need to
+ continue all threads in order to make progress. */
+
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
@@ -2127,6 +2176,9 @@ handle_inferior_event (struct execution_

if (!ptid_equal (deferred_step_ptid, null_ptid))
{
+ /* In non-stop mode, there's never a deferred_step_ptid set. */
+ gdb_assert (!non_stop);
+
/* If we stopped for some other reason than single-stepping, ignore
the fact that we were supposed to switch back. */
if (stop_signal == TARGET_SIGNAL_TRAP)
@@ -2275,8 +2327,13 @@ handle_inferior_event (struct execution_
if (!ptid_equal (inferior_ptid, ecs->ptid))
context_switch (ecs->ptid);

- waiton_ptid = ecs->ptid;
- infwait_state = infwait_thread_hop_state;
+ if (!non_stop)
+ {
+ /* Only need to require the next event from this
+ thread in all-stop mode. */
+ waiton_ptid = ecs->ptid;
+ infwait_state = infwait_thread_hop_state;
+ }

tss->stepping_over_breakpoint = 1;
keep_going (ecs);
@@ -3831,7 +3888,16 @@ done:
/* Delete the breakpoint we stopped at, if it wants to be deleted.
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (stop_bpstat);
- set_running (pid_to_ptid (-1), 0);
+
+ if (target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
+ {
+ if (!non_stop)
+ set_running (pid_to_ptid (-1), 0);
+ else
+ set_running (inferior_ptid, 0);
+ }
}

static int
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c 2008-06-15 19:40:21.000000000 +0100
+++ src/gdb/thread.c 2008-06-15 20:25:39.000000000 +0100
@@ -42,6 +42,8 @@
#include "observer.h"
#include "annotate.h"

+#include "cli/cli-decode.h"
+
/* Definition of struct thread_info exported to gdbthread.h */

/* Prototypes for exported functions. */
@@ -613,9 +615,12 @@ print_thread_info (struct ui_out *uiout,
int current_thread = -1;

/* Backup current thread and selected frame. */
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;

+ old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
make_cleanup_ui_out_list_begin_end (uiout, "threads");

prune_threads ();
@@ -650,12 +655,18 @@ print_thread_info (struct ui_out *uiout,
ui_out_text (uiout, ")");
}
ui_out_text (uiout, " ");
- /* That switch put us at the top of the stack (leaf frame). */
- switch_to_thread (tp->ptid);
- print_stack_frame (get_selected_frame (NULL),
- /* For MI output, print frame level. */
- ui_out_is_mi_like_p (uiout),
- LOCATION);
+ if (tp->running_)
+ ui_out_text (uiout, "(running)\n");
+ else
+ {
+ /* The switch below puts us at the top of the stack (leaf
+ frame). */
+ switch_to_thread (tp->ptid);
+ print_stack_frame (get_selected_frame (NULL),
+ /* For MI output, print frame level. */
+ ui_out_is_mi_like_p (uiout),
+ LOCATION);
+ }

do_cleanups (chain2);
}
@@ -671,6 +682,9 @@ print_thread_info (struct ui_out *uiout,
ui_out_field_int (uiout, "current-thread-id", current_thread);
}

+ if (is_running (inferior_ptid))
+ return;
+
/* If case we were not able to find the original frame, print the
new selected frame. */
if (frame_find_by_id (saved_frame_id) == NULL)
@@ -709,7 +723,11 @@ switch_to_thread (ptid_t ptid)
inferior_ptid = ptid;
reinit_frame_cache ();
registers_changed ();
- stop_pc = read_pc ();
+
+ if (!is_executing (ptid))
+ stop_pc = read_pc ();
+ else
+ stop_pc = ~(CORE_ADDR) 0;
}

static void
@@ -746,7 +764,12 @@ do_restore_current_thread_cleanup (void
{
struct current_thread_cleanup *old = arg;
restore_current_thread (old->inferior_ptid);
- restore_selected_frame (old->selected_frame_id);
+
+ /* A command like 'thread apply all $exec_command&' may change the
+ running state of the originally selected thread, so we have to
+ recheck it here. */
+ if (!is_running (old->inferior_ptid))
+ restore_selected_frame (old->selected_frame_id);
xfree (old);
}

@@ -774,8 +797,7 @@ static void
thread_apply_all_command (char *cmd, int from_tty)
{
struct thread_info *tp;
- struct cleanup *old_chain;
- struct cleanup *saved_cmd_cleanup_chain;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
char *saved_cmd;
struct frame_id saved_frame_id;
ptid_t current_ptid;
@@ -785,8 +807,12 @@ thread_apply_all_command (char *cmd, int
error (_("Please specify a command following the thread ID list"));

current_ptid = inferior_ptid;
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;
+ make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);

/* It is safe to update the thread list now, before
traversing it for "thread apply all". MVS */
@@ -795,11 +821,15 @@ thread_apply_all_command (char *cmd, int
/* Save a copy of the command in case it is clobbered by
execute_command */
saved_cmd = xstrdup (cmd);
- saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
+ make_cleanup (xfree, saved_cmd);
for (tp = thread_list; tp; tp = tp->next)
if (thread_alive (tp))
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
+
printf_filtered (_("\nThread %d (%s):\n"),
tp->num, target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -809,12 +839,10 @@ thread_apply_all_command (char *cmd, int
if (!ptid_equal (current_ptid, inferior_ptid))
thread_has_changed = 1;

- do_cleanups (saved_cmd_cleanup_chain);
do_cleanups (old_chain);
/* Print stack frame only if we changed thread. */
- if (thread_has_changed)
+ if (thread_has_changed && !is_running (inferior_ptid))
print_stack_frame (get_current_frame (), 1, SRC_LINE);
-
}

static void
@@ -838,7 +866,11 @@ thread_apply_command (char *tidlist, int
error (_("Please specify a command following the thread ID list"));

current_ptid = inferior_ptid;
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
+
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);

/* Save a copy of the command in case it is clobbered by
@@ -882,7 +914,10 @@ thread_apply_command (char *tidlist, int
warning (_("Thread %d has terminated."), start);
else
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
printf_filtered (_("\nThread %d (%s):\n"), tp->num,
target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -950,7 +985,10 @@ do_captured_thread_select (struct ui_out
if (!thread_alive (tp))
error (_("Thread ID %d has terminated."), num);

- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);

ui_out_text (uiout, "[Switching to thread ");
ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
@@ -958,7 +996,11 @@ do_captured_thread_select (struct ui_out
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
ui_out_text (uiout, ")]");

- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ if (!tp->running_)
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ else
+ ui_out_text (uiout, "(running)\n");
+
return GDB_RC_OK;
}

@@ -978,14 +1020,17 @@ void
_initialize_thread (void)
{
static struct cmd_list_element *thread_apply_list = NULL;
+ struct cmd_list_element *c;

- add_info ("threads", info_threads_command,
- _("IDs of currently known threads."));
+ c = add_info ("threads", info_threads_command,
+ _("IDs of currently known threads."));
+ set_cmd_async_ok (c);

- add_prefix_cmd ("thread", class_run, thread_command, _("\
+ c = add_prefix_cmd ("thread", class_run, thread_command, _("\
Use this command to switch between threads.\n\
The new thread ID must be currently known."),
&thread_cmd_list, "thread ", 1, &cmdlist);
+ set_cmd_async_ok (c);

add_prefix_cmd ("apply", class_run, thread_apply_command,
_("Apply a command to a list of threads."),
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c 2008-06-15 17:57:52.000000000 +0100
+++ src/gdb/inf-loop.c 2008-06-15 20:06:52.000000000 +0100
@@ -73,11 +73,15 @@ inferior_event_handler (enum inferior_ev
break;

case INF_EXEC_COMPLETE:
- /* Unregister the inferior from the event loop. This is done so that
- when the inferior is not running we don't get distracted by
- spurious inferior output. */
- if (target_has_execution)
- target_async (NULL, 0);
+
+ if (!non_stop)
+ {
+ /* Unregister the inferior from the event loop. This is done
+ so that when the inferior is not running we don't get
+ distracted by spurious inferior output. */
+ if (target_has_execution)
+ target_async (NULL, 0);
+ }

/* The call to async_enable_stdin below resets 'sync_execution'.
However, if sync_execution is 1 now, we also need to show the
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c 2008-06-15 17:57:46.000000000 +0100
+++ src/gdb/infcmd.c 2008-06-15 20:25:41.000000000 +0100
@@ -613,6 +613,7 @@ continue_command (char *proc_count_exp,
{
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_running ();

/* Find out whether we must run in the background. */
if (proc_count_exp != NULL)
@@ -714,6 +715,7 @@ step_1 (int skip_subroutines, int single
int thread = -1;

ERROR_NO_INFERIOR;
+ ensure_not_running ();

if (count_string)
async_exec = strip_bg_char (&count_string);
@@ -936,6 +938,7 @@ jump_command (char *arg, int from_tty)
int async_exec = 0;

ERROR_NO_INFERIOR;
+ ensure_not_running ();

/* Find out whether we must run in the background. */
if (arg != NULL)
@@ -1036,6 +1039,7 @@ signal_command (char *signum_exp, int fr

dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
+ ensure_not_running ();

/* Find out whether we must run in the background. */
if (signum_exp != NULL)
@@ -2100,7 +2104,11 @@ interrupt_target_command (char *args, in
if (target_can_async_p ())
{
dont_repeat (); /* Not for the faint of heart */
- target_stop ();
+
+ if (non_stop)
+ target_stop_ptid (inferior_ptid);
+ else
+ target_stop ();
}
}

Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h 2008-06-15 20:01:30.000000000 +0100
+++ src/gdb/inferior.h 2008-06-15 20:25:40.000000000 +0100
@@ -245,6 +245,12 @@ extern void get_last_target_status(ptid_

extern void follow_inferior_reset_breakpoints (void);

+/* Throw an error indicating the current thread is running. */
+extern void error_is_running (void);
+
+/* Calls error_is_running if the current thread is running. */
+extern void ensure_not_running (void);
+
/* From infcmd.c */

extern void tty_command (char *, int);
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2008-06-15 19:40:17.000000000 +0100
+++ src/gdb/target.h 2008-06-15 20:06:52.000000000 +0100
@@ -397,6 +397,7 @@ struct target_ops
char *(*to_pid_to_str) (ptid_t);
char *(*to_extra_thread_info) (struct thread_info *);
void (*to_stop) (void);
+ void (*to_stop_ptid) (ptid_t ptid);
void (*to_rcmd) (char *command, struct ui_file *output);
char *(*to_pid_to_exec_file) (int pid);
void (*to_log_command) (const char *);
@@ -895,6 +896,12 @@ int target_follow_fork (int follow_child

#define target_stop current_target.to_stop

+/* Same as target_stop, but apply to PTID. Used in non-stop mode to
+ stop a single thread without affecting the running state of the
+ others. */
+#define target_stop_ptid(ptid) \
+ (*current_target.to_stop_ptid) (ptid)
+
/* Send the specified COMMAND to the target's monitor
(shell,interpreter) for execution. The result of the query is
placed in OUTBUF. */
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2008-06-15 17:57:52.000000000 +0100
+++ src/gdb/target.c 2008-06-15 20:25:40.000000000 +0100
@@ -456,6 +456,7 @@ update_current_target (void)
INHERIT (to_pid_to_str, t);
INHERIT (to_extra_thread_info, t);
INHERIT (to_stop, t);
+ INHERIT (to_stop_ptid, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
INHERIT (to_pid_to_exec_file, t);
@@ -632,6 +633,9 @@ update_current_target (void)
de_fault (to_stop,
(void (*) (void))
target_ignore);
+ de_fault (to_stop_ptid,
+ (void (*) (ptid_t))
+ target_ignore);
current_target.to_xfer_partial = current_xfer_partial;
de_fault (to_rcmd,
(void (*) (char *, struct ui_file *))
@@ -2939,6 +2943,14 @@ debug_to_stop (void)
}

static void
+debug_to_stop_ptid (ptid_t ptid)
+{
+ debug_target.to_stop_ptid (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_stop_pid\n");
+}
+
+static void
debug_to_rcmd (char *command,
struct ui_file *outbuf)
{
@@ -3012,6 +3024,7 @@ setup_target_debug (void)
current_target.to_thread_alive = debug_to_thread_alive;
current_target.to_find_new_threads = debug_to_find_new_threads;
current_target.to_stop = debug_to_stop;
+ current_target.to_stop_ptid = debug_to_stop_ptid;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
}
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2008-06-15 19:40:21.000000000 +0100
+++ src/gdb/Makefile.in 2008-06-15 20:06:52.000000000 +0100
@@ -2934,7 +2934,7 @@ target-memory.o: target-memory.c $(defs_
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
- $(ui_out_h) $(observer_h) $(annotate_h)
+ $(ui_out_h) $(observer_h) $(annotate_h) $(cli_decode_h)
top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \
$(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \
$(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \