/* Multi-process/thread control defs for GDB, the GNU debugger.
Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1997, 1998, 1999,
- 2000, 2007 Free Software Foundation, Inc.
+ 2000, 2007, 2008 Free Software Foundation, Inc.
Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
#ifndef GDBTHREAD_H
#define GDBTHREAD_H
-struct breakpoint;
-struct frame_id;
struct symtab;
-/* For bpstat */
#include "breakpoint.h"
-
-/* For struct frame_id. */
#include "frame.h"
+#include "ui-out.h"
+#include "inferior.h"
struct thread_info
{
In fact, this may be overloaded with
kernel thread id, etc. */
int num; /* Convenient handle (GDB thread id) */
- /* State from wait_for_inferior */
- CORE_ADDR prev_pc;
+
+ /* Non-zero means the thread is executing. Note: this is different
+ from saying that there is an active target and we are stopped at
+ a breakpoint, for instance. This is a real indicator whether the
+ thread is off and running. */
+ /* This field is internal to thread.c. Never access it directly,
+ use is_executing instead. */
+ int executing_;
+
+ /* Frontend view of the thread state. Note that the RUNNING/STOPPED
+ states are different from EXECUTING. When the thread is stopped
+ internally while handling an internal event, like a software
+ single-step breakpoint, EXECUTING will be false, but running will
+ still be true. As a possible future extension, this could turn
+ into enum { stopped, exited, stepping, finishing, until(ling),
+ running ... } */
+ /* This field is internal to thread.c. Never access it directly,
+ use is_running instead. */
+ int state_;
+
+ /* If this is > 0, then it means there's code out there that relies
+ on this thread being listed. Don't delete it from the lists even
+ if we detect it exiting. */
+ int refcount;
+
+ /* User/external stepping state. */
+
+ /* Step-resume or longjmp-resume breakpoint. */
struct breakpoint *step_resume_breakpoint;
- CORE_ADDR step_range_start;
- CORE_ADDR step_range_end;
+
+ /* Range to single step within.
+
+ If this is nonzero, respond to a single-step signal by continuing
+ to step if the pc is in this range.
+
+ If step_range_start and step_range_end are both 1, it means to
+ step for a single instruction (FIXME: it might clean up
+ wait_for_inferior in a minor way if this were changed to the
+ address of the instruction and that address plus one. But maybe
+ not.). */
+ CORE_ADDR step_range_start; /* Inclusive */
+ CORE_ADDR step_range_end; /* Exclusive */
+
+ /* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call, and how
+ to set the frame for the breakpoint used to step out. */
struct frame_id step_frame_id;
int current_line;
struct symtab *current_symtab;
+
+ /* Internal stepping state. */
+
+ /* Record the pc of the thread the last time it stopped. This is
+ maintained by proceed and keep_going, and used in
+ adjust_pc_after_break to distinguish a hardware single-step
+ SIGTRAP from a breakpoint SIGTRAP. */
+ CORE_ADDR prev_pc;
+
+ /* Nonzero if we are presently stepping over a breakpoint.
+
+ If we hit a breakpoint or watchpoint, and then continue, we need
+ to single step the current thread with breakpoints disabled, to
+ avoid hitting the same breakpoint or watchpoint again. And we
+ should step just a single thread and keep other threads stopped,
+ so that other threads don't miss breakpoints while they are
+ removed.
+
+ So, this variable simultaneously means that we need to single
+ step the current thread, keep other threads stopped, and that
+ breakpoints should be removed while we step.
+
+ This variable is set either:
+ - in proceed, when we resume inferior on user's explicit request
+ - in keep_going, if handle_inferior_event decides we need to
+ step over breakpoint.
+
+ The variable is cleared in normal_stop. The proceed calls
+ wait_for_inferior, which calls handle_inferior_event in a loop,
+ and until wait_for_inferior exits, this variable is changed only
+ by keep_going. */
int trap_expected;
- int handling_longjmp;
- int another_trap;
+
+ /* Should we step over breakpoint next time keep_going is called? */
+ int stepping_over_breakpoint;
+
+ /* Set to TRUE if we should finish single-stepping over a breakpoint
+ after hitting the current step-resume breakpoint. */
+ int step_after_step_resume_breakpoint;
/* This is set TRUE when a catchpoint of a shared library event
triggers. Since we don't wish to leave the inferior in the
when we finally do stop stepping. */
bpstat stepping_through_solib_catchpoints;
+ /* Per-thread command support. */
+
+ /* Pointer to what is left to do for an execution command after the
+ target stops. Used only in asynchronous mode, by targets that
+ support async execution. Several execution commands use it. */
+ struct continuation *continuations;
+
+ /* Similar to the above, but used when a single execution command
+ requires several resume/stop iterations. Used by the step
+ command. */
+ struct continuation *intermediate_continuations;
+
+ /* Nonzero if the thread is being proceeded for a "finish" command
+ or a similar situation when stop_registers should be saved. */
+ int proceed_to_finish;
+
+ enum step_over_calls_kind step_over_calls;
+
+ /* Nonzero if stopped due to a step command. */
+ int stop_step;
+
+ /* If stepping, nonzero means step count is > 1 so don't print frame
+ next time inferior stops if it stops due to stepping. */
+ int step_multi;
+
+ /* Last signal that the inferior received (why it stopped). */
+ enum target_signal stop_signal;
+
+ /* Chain containing status of breakpoint(s) the thread stopped
+ at. */
+ bpstat stop_bpstat;
+
+ /* True if this thread has been explicitly requested to stop. */
+ int stop_requested;
+
/* Private data used by the target vector implementation. */
struct private_thread_info *private;
};
/* Create an empty thread list, or empty the existing one. */
extern void init_thread_list (void);
-/* Add a thread to the thread list.
- Note that add_thread now returns the handle of the new thread,
- so that the caller may initialize the private thread data. */
+/* Add a thread to the thread list, print a message
+ that a new thread is found, and return the pointer to
+ the new thread. Caller my use this pointer to
+ initialize the private thread data. */
extern struct thread_info *add_thread (ptid_t ptid);
+/* Same as add_thread, but does not print a message
+ about new thread. */
+extern struct thread_info *add_thread_silent (ptid_t ptid);
+
+/* Same as add_thread, and sets the private info. */
+extern struct thread_info *add_thread_with_info (ptid_t ptid,
+ struct private_thread_info *);
+
/* Delete an existing thread list entry. */
extern void delete_thread (ptid_t);
+/* Delete an existing thread list entry, and be quiet about it. Used
+ after the process this thread having belonged to having already
+ exited, for example. */
+extern void delete_thread_silent (ptid_t);
+
/* Delete a step_resume_breakpoint from the thread database. */
-extern void delete_step_resume_breakpoint (void *);
+extern void delete_step_resume_breakpoint (struct thread_info *);
/* Translate the integer thread id (GDB's homegrown id, not the system's)
into a "pid" (which may be overloaded with extra thread information). */
/* Search function to lookup a thread by 'pid'. */
extern struct thread_info *find_thread_pid (ptid_t ptid);
+/* Find thread by GDB user-visible thread number. */
+struct thread_info *find_thread_id (int num);
+
+/* Change the ptid of thread OLD_PTID to NEW_PTID. */
+void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
+
/* Iterator function to call a user-provided callback function
once for each known thread. */
typedef int (*thread_callback_func) (struct thread_info *, void *);
extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
-/* infrun context switch: save the debugger state for the given thread. */
-extern void save_infrun_state (ptid_t ptid,
- CORE_ADDR prev_pc,
- int trap_expected,
- struct breakpoint *step_resume_breakpoint,
- CORE_ADDR step_range_start,
- CORE_ADDR step_range_end,
- const struct frame_id *step_frame_id,
- int handling_longjmp,
- int another_trap,
- int stepping_through_solib_after_catch,
- bpstat stepping_through_solib_catchpoints,
- int current_line,
- struct symtab *current_symtab);
-
-/* infrun context switch: load the debugger state previously saved
- for the given thread. */
-extern void load_infrun_state (ptid_t ptid,
- CORE_ADDR *prev_pc,
- int *trap_expected,
- struct breakpoint **step_resume_breakpoint,
- CORE_ADDR *step_range_start,
- CORE_ADDR *step_range_end,
- struct frame_id *step_frame_id,
- int *handling_longjmp,
- int *another_trap,
- int *stepping_through_solib_affter_catch,
- bpstat *stepping_through_solib_catchpoints,
- int *current_line,
- struct symtab **current_symtab);
+extern int thread_count (void);
/* Switch from one thread to another. */
extern void switch_to_thread (ptid_t ptid);
+/* Marks thread PTID is running, or stopped.
+ If PIDGET (PTID) is -1, marks all threads. */
+extern void set_running (ptid_t ptid, int running);
+
+/* Marks or clears thread(s) PTID as having been requested to stop.
+ If PTID is MINUS_ONE_PTID, applies to all threads. If
+ ptid_is_pid(PTID) is true, applies to all threads of the process
+ pointed at by PTID. If STOP, then the THREAD_STOP_REQUESTED
+ observer is called with PTID as argument. */
+extern void set_stop_requested (ptid_t ptid, int stop);
+
+/* NOTE: Since the thread state is not a boolean, most times, you do
+ not want to check it with negation. If you really want to check if
+ the thread is stopped,
+
+ use (good):
+
+ if (is_stopped (ptid))
+
+ instead of (bad):
+
+ if (!is_running (ptid))
+
+ The latter also returns true on exited threads, most likelly not
+ what you want. */
+
+/* Reports if in the frontend's perpective, thread PTID is running. */
+extern int is_running (ptid_t ptid);
+
+/* Is this thread listed, but known to have exited? We keep it listed
+ (but not visible) until it's safe to delete. */
+extern int is_exited (ptid_t ptid);
+
+/* In the frontend's perpective, is this thread stopped? */
+extern int is_stopped (ptid_t ptid);
+
+/* In the frontend's perpective is there any thread running? */
+extern int any_running (void);
+
+/* Marks thread PTID as executing, or not. If PIDGET (PTID) is -1,
+ marks all threads.
+
+ Note that this is different from the running state. See the
+ description of state_ and executing_ fields of struct
+ thread_info. */
+extern void set_executing (ptid_t ptid, int executing);
+
+/* Reports if thread PTID is executing. */
+extern int is_executing (ptid_t ptid);
+
/* Commands with a prefix of `thread'. */
extern struct cmd_list_element *thread_cmd_list;
+/* Print notices on thread events (attach, detach, etc.), set with
+ `set print thread-events'. */
+extern int print_thread_events;
+
+extern void print_thread_info (struct ui_out *uiout, int thread);
+
+extern struct cleanup *make_cleanup_restore_current_thread (void);
+
+/* Returns a pointer into the thread_info corresponding to
+ INFERIOR_PTID. INFERIOR_PTID *must* be in the thread list. */
+extern struct thread_info* inferior_thread (void);
+
#endif /* GDBTHREAD_H */