X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbthread.h;h=2738e44da9f52bff7d1c7363c2a4c30041ab7e75;hb=e418a61a67a3476826259163383e5deb661042cc;hp=4cd739089b049c9e361ab8436e53d594f2355e4c;hpb=803bdfe43083475c7df3db38dc96f4e20d05457d;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 4cd739089b..2738e44da9 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -1,5 +1,5 @@ /* Multi-process/thread control defs for GDB, the GNU debugger. - Copyright (C) 1987-2017 Free Software Foundation, Inc. + Copyright (C) 1987-2018 Free Software Foundation, Inc. Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. @@ -31,6 +31,8 @@ struct symtab; #include "common/vec.h" #include "target/waitstatus.h" #include "cli/cli-utils.h" +#include "common/refcounted-object.h" +#include "common-gdbthread.h" /* Frontend view of the thread state. Possible extensions: stepping, finishing, until(ling),... */ @@ -50,17 +52,17 @@ struct thread_control_state /* User/external stepping state. */ /* Step-resume or longjmp-resume breakpoint. */ - struct breakpoint *step_resume_breakpoint; + struct breakpoint *step_resume_breakpoint = nullptr; /* Exception-resume breakpoint. */ - struct breakpoint *exception_resume_breakpoint; + struct breakpoint *exception_resume_breakpoint = nullptr; /* Breakpoints used for software single stepping. Plural, because it may have multiple locations. E.g., if stepping over a conditional branch instruction we can't decode the condition for, we'll need to put a breakpoint at the branch destination, and another at the instruction after the branch. */ - struct breakpoint *single_step_breakpoints; + struct breakpoint *single_step_breakpoints = nullptr; /* Range to single step within. @@ -72,11 +74,11 @@ struct thread_control_state 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 */ + CORE_ADDR step_range_start = 0; /* Inclusive */ + CORE_ADDR step_range_end = 0; /* Exclusive */ /* Function the thread was in as of last it started stepping. */ - struct symbol *step_start_function; + struct symbol *step_start_function = nullptr; /* If GDB issues a target step request, and this is nonzero, the target should single-step this thread once, and then continue @@ -84,16 +86,16 @@ struct thread_control_state thread stops in the step range above. If this is zero, the target should ignore the step range, and only issue one single step. */ - int may_range_step; + int may_range_step = 0; /* 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; + struct frame_id step_frame_id {}; /* Similarly, the frame ID of the underlying stack frame (skipping any inlined frames). */ - struct frame_id step_stack_frame_id; + struct frame_id step_stack_frame_id {}; /* Nonzero if we are presently stepping over a breakpoint. @@ -117,29 +119,29 @@ struct thread_control_state 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 trap_expected = 0; /* Nonzero if the thread is being proceeded for a "finish" command or a similar situation when return value should be printed. */ - int proceed_to_finish; + int proceed_to_finish = 0; /* Nonzero if the thread is being proceeded for an inferior function call. */ - int in_infcall; + int in_infcall = 0; - enum step_over_calls_kind step_over_calls; + enum step_over_calls_kind step_over_calls = STEP_OVER_NONE; /* Nonzero if stopped due to a step command. */ - int stop_step; + int stop_step = 0; /* Chain containing status of breakpoint(s) the thread stopped at. */ - bpstat stop_bpstat; + bpstat stop_bpstat = nullptr; /* 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". */ - int stepping_command; + int stepping_command = 0; }; /* Inferior thread specific part of `struct infcall_suspend_state'. */ @@ -153,31 +155,59 @@ struct thread_suspend_state "signal" command, which overrides "handle nopass". If the signal should be suppressed, the core will take care of clearing this before the target is resumed. */ - enum gdb_signal stop_signal; + enum gdb_signal stop_signal = GDB_SIGNAL_0; /* The reason the thread last stopped, if we need to track it (breakpoint, watchpoint, etc.) */ - enum target_stop_reason stop_reason; + enum target_stop_reason stop_reason = TARGET_STOPPED_BY_NO_REASON; /* The waitstatus for this thread's last event. */ - struct target_waitstatus waitstatus; + struct target_waitstatus waitstatus {}; /* If true WAITSTATUS hasn't been handled yet. */ - int waitstatus_pending_p; + int waitstatus_pending_p = 0; /* Record the pc of the thread the last time it stopped. (This is not the current thread's PC as that may have changed since the - last stop, e.g., "return" command, or "p $pc = 0xf000"). This is - used in coordination with stop_reason and waitstatus_pending_p: - if the thread's PC is changed since it last stopped, a pending - breakpoint waitstatus is discarded. */ - CORE_ADDR stop_pc; + last stop, e.g., "return" command, or "p $pc = 0xf000"). + + - If the thread's PC has not changed since the thread last + stopped, then proceed skips a breakpoint at the current PC, + otherwise we let the thread run into the breakpoint. + + - If the thread has an unprocessed event pending, as indicated by + waitstatus_pending_p, this is used in coordination with + stop_reason: if the thread's PC has changed since the thread + last stopped, a pending breakpoint waitstatus is discarded. + + - If the thread is running, this is set to -1, to avoid leaving + it with a stale value, to make it easier to catch bugs. */ + CORE_ADDR stop_pc = 0; }; -typedef struct value *value_ptr; -DEF_VEC_P (value_ptr); -typedef VEC (value_ptr) value_vec; +/* Base class for target-specific thread data. */ +struct private_thread_info +{ + virtual ~private_thread_info () = 0; +}; -struct thread_info +/* Threads are intrusively refcounted objects. Being the + user-selected thread is normally considered an implicit strong + reference and is thus not accounted in the refcount, unlike + inferior objects. This is necessary, because there's no "current + thread" pointer. Instead the current thread is inferred from the + inferior_ptid global. However, when GDB needs to remember the + selected thread to later restore it, GDB bumps the thread object's + refcount, to prevent something deleting the thread object before + reverting back (e.g., due to a "kill" command). If the thread + meanwhile exits before being re-selected, then the thread object is + left listed in the thread list, but marked with state + THREAD_EXITED. (See make_cleanup_restore_current_thread and + delete_thread). All other thread references are considered weak + references. Placing a thread in the thread list is an implicit + strong reference, and is thus not accounted for in the thread's + refcount. */ + +class thread_info : public refcounted_object { public: explicit thread_info (inferior *inf, ptid_t ptid); @@ -186,23 +216,12 @@ public: bool deletable () const { /* If this is the current thread, or there's code out there that - relies on it existing (m_refcount > 0) we can't delete yet. */ - return (m_refcount == 0 && !ptid_equal (ptid, inferior_ptid)); - } - - /* Increase the refcount. */ - void incref () - { - gdb_assert (m_refcount >= 0); - m_refcount++; + relies on it existing (refcount > 0) we can't delete yet. */ + return (refcount () == 0 && ptid != inferior_ptid); } - /* Decrease the refcount. */ - void decref () - { - m_refcount--; - gdb_assert (m_refcount >= 0); - } + /* Mark this thread as running and notify observers. */ + void set_running (bool running); struct thread_info *next = NULL; ptid_t ptid; /* "Actual process id"; @@ -277,11 +296,11 @@ public: /* State of GDB control of inferior thread execution. See `struct thread_control_state'. */ - thread_control_state control {}; + thread_control_state control; /* State of inferior thread to restore after GDB is done with an inferior call. See `struct thread_suspend_state'. */ - thread_suspend_state suspend {}; + thread_suspend_state suspend; int current_line = 0; struct symtab *current_symtab = NULL; @@ -340,36 +359,30 @@ public: struct frame_id initiating_frame = null_frame_id; /* Private data used by the target vector implementation. */ - struct private_thread_info *priv = NULL; - - /* Function that is called to free PRIVATE. If this is NULL, then - xfree will be called on PRIVATE. */ - void (*private_dtor) (struct private_thread_info *) = NULL; + std::unique_ptr priv; /* Branch trace information for this thread. */ struct btrace_thread_info btrace {}; /* Flag which indicates that the stack temporaries should be stored while evaluating expressions. */ - int stack_temporaries_enabled = 0; + bool stack_temporaries_enabled = false; /* Values that are stored as temporaries on stack while evaluating expressions. */ - value_vec *stack_temporaries = NULL; + std::vector stack_temporaries; /* Step-over chain. A thread is in the step-over queue if these are non-NULL. If only a single thread is in the chain, then these fields point to self. */ struct thread_info *step_over_prev = NULL; struct thread_info *step_over_next = NULL; +}; -private: +/* A gdb::ref_ptr pointer to a thread_info. */ - /* 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 m_refcount = 0; -}; +using thread_info_ref + = gdb::ref_ptr; /* Create an empty thread list, or empty the existing one. */ extern void init_thread_list (void); @@ -389,12 +402,12 @@ 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); +extern void delete_thread (struct thread_info *thread); /* 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); +extern void delete_thread_silent (struct thread_info *thread); /* Delete a step_resume_breakpoint from the thread database. */ extern void delete_step_resume_breakpoint (struct thread_info *); @@ -412,19 +425,9 @@ extern int thread_has_single_step_breakpoints_set (struct thread_info *tp); /* Check whether the thread has software single stepping breakpoints set at PC. */ extern int thread_has_single_step_breakpoint_here (struct thread_info *tp, - struct address_space *aspace, + const address_space *aspace, CORE_ADDR addr); -/* Translate the global integer thread id (GDB's homegrown id, not the - system's) into a "pid" (which may be overloaded with extra thread - information). */ -extern ptid_t global_thread_id_to_ptid (int num); - -/* Translate a 'pid' (which may be overloaded with extra thread - information) into the global integer thread id (GDB's homegrown id, - not the system's). */ -extern int ptid_to_global_thread_id (ptid_t ptid); - /* Returns whether to show inferior-qualified thread IDs, or plain thread numbers. Inferior-qualified IDs are shown whenever we have multiple inferiors, or the only inferior left has number > 1. */ @@ -436,8 +439,7 @@ extern int show_inferior_qualified_tids (void); circular static buffer, NUMCELLS deep. */ const char *print_thread_id (struct thread_info *thr); -/* Boolean test for an already-known pid (which may be overloaded with - extra thread information). */ +/* Boolean test for an already-known ptid. */ extern int in_thread_list (ptid_t ptid); /* Boolean test for an already-known global thread id (GDB's homegrown @@ -450,17 +452,20 @@ extern struct thread_info *find_thread_ptid (ptid_t ptid); /* Find thread by GDB global thread ID. */ struct thread_info *find_thread_global_id (int global_id); -/* Finds the first thread of the inferior given by PID. If PID is -1, - returns the first thread in the list. */ -struct thread_info *first_thread_of_process (int pid); +/* Find thread by thread library specific handle in inferior INF. */ +struct thread_info *find_thread_by_handle (struct value *thread_handle, + struct inferior *inf); -/* Returns any thread of process PID, giving preference to the current - thread. */ -extern struct thread_info *any_thread_of_process (int pid); +/* Finds the first thread of the specified inferior. */ +extern struct thread_info *first_thread_of_inferior (inferior *inf); -/* Returns any non-exited thread of process PID, giving preference to +/* Returns any thread of inferior INF, giving preference to the + current thread. */ +extern struct thread_info *any_thread_of_inferior (inferior *inf); + +/* Returns any non-exited thread of inferior INF, giving preference to the current thread, and to not executing threads. */ -extern struct thread_info *any_live_thread_of_process (int pid); +extern struct thread_info *any_live_thread_of_inferior (inferior *inf); /* Change the ptid of thread OLD_PTID to NEW_PTID. */ void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid); @@ -496,12 +501,13 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *); extern int thread_count (void); -/* Switch from one thread to another. Also sets the STOP_PC - global. */ -extern void switch_to_thread (ptid_t ptid); +/* Switch context to thread THR. Also sets the STOP_PC global. */ +extern void switch_to_thread (struct thread_info *thr); + +/* Switch context to no thread selected. */ +extern void switch_to_no_thread (); -/* Switch from one thread to another. Does not read registers and - sets STOP_PC to -1. */ +/* Switch from one thread to another. Does not read registers. */ extern void switch_to_thread_no_regs (struct thread_info *thread); /* Marks or clears thread(s) PTID as resumed. If PTID is @@ -553,9 +559,6 @@ extern int is_stopped (ptid_t ptid); thread_info. */ extern void set_executing (ptid_t ptid, int executing); -/* Reports if thread PTID is executing. */ -extern int is_executing (ptid_t ptid); - /* True if any (known or unknown) thread is or may be executing. */ extern int threads_are_executing (void); @@ -571,15 +574,38 @@ extern int threads_are_executing (void); Notifications are only emitted if the thread state did change. */ extern void finish_thread_state (ptid_t ptid); -/* Same as FINISH_THREAD_STATE, but with an interface suitable to be - registered as a cleanup. PTID_P points to the ptid_t that is - passed to FINISH_THREAD_STATE. */ -extern void finish_thread_state_cleanup (void *ptid_p); +/* Calls finish_thread_state on scope exit, unless release() is called + to disengage. */ +class scoped_finish_thread_state +{ +public: + explicit scoped_finish_thread_state (ptid_t ptid) + : m_ptid (ptid) + {} + + ~scoped_finish_thread_state () + { + if (!m_released) + finish_thread_state (m_ptid); + } + + /* Disengage. */ + void release () + { + m_released = true; + } + + DISABLE_COPY_AND_ASSIGN (scoped_finish_thread_state); + +private: + bool m_released = false; + ptid_t m_ptid; +}; /* Commands with a prefix of `thread'. */ extern struct cmd_list_element *thread_cmd_list; -extern void thread_command (char *tidstr, int from_tty); +extern void thread_command (const char *tidstr, int from_tty); /* Print notices on thread events (attach, detach, etc.), set with `set print thread-events'. */ @@ -595,7 +621,25 @@ extern int print_thread_events; extern void print_thread_info (struct ui_out *uiout, char *requested_threads, int pid); -extern struct cleanup *make_cleanup_restore_current_thread (void); +/* Save/restore current inferior/thread/frame. */ + +class scoped_restore_current_thread +{ +public: + scoped_restore_current_thread (); + ~scoped_restore_current_thread (); + + DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread); + +private: + /* Use the "class" keyword here, because of a clash with a "thread_info" + function in the Darwin API. */ + class thread_info *m_thread; + inferior *m_inf; + frame_id m_selected_frame_id; + int m_selected_frame_level; + bool m_was_stopped; +}; /* Returns a pointer into the thread_info corresponding to INFERIOR_PTID. INFERIOR_PTID *must* be in the thread list. */ @@ -616,15 +660,48 @@ extern void delete_exited_threads (void); int pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread); -extern struct cleanup *enable_thread_stack_temporaries (ptid_t ptid); +/* Enable storing stack temporaries for thread THR and disable and + clear the stack temporaries on destruction. Holds a strong + reference to THR. */ + +class enable_thread_stack_temporaries +{ +public: + + explicit enable_thread_stack_temporaries (struct thread_info *thr) + : m_thr (thr) + { + gdb_assert (m_thr != NULL); + + m_thr->incref (); + + m_thr->stack_temporaries_enabled = true; + m_thr->stack_temporaries.clear (); + } + + ~enable_thread_stack_temporaries () + { + m_thr->stack_temporaries_enabled = false; + m_thr->stack_temporaries.clear (); + + m_thr->decref (); + } + + DISABLE_COPY_AND_ASSIGN (enable_thread_stack_temporaries); -extern int thread_stack_temporaries_enabled_p (ptid_t ptid); +private: -extern void push_thread_stack_temporary (ptid_t ptid, struct value *v); + struct thread_info *m_thr; +}; -extern struct value *get_last_thread_stack_temporary (ptid_t); +extern bool thread_stack_temporaries_enabled_p (struct thread_info *tp); -extern int value_in_thread_stack_temporaries (struct value *, ptid_t); +extern void push_thread_stack_temporary (struct thread_info *tp, struct value *v); + +extern value *get_last_thread_stack_temporary (struct thread_info *tp); + +extern bool value_in_thread_stack_temporaries (struct value *, + struct thread_info *thr); /* Add TP to the end of its inferior's pending step-over chain. */ @@ -652,9 +729,9 @@ extern void thread_cancel_execution_command (struct thread_info *thr); executing). */ extern void validate_registers_access (void); -/* Check whether it makes sense to access a register of PTID at this point. +/* Check whether it makes sense to access a register of THREAD at this point. Returns true if registers may be accessed; false otherwise. */ -extern bool can_access_registers_ptid (ptid_t ptid); +extern bool can_access_registers_thread (struct thread_info *thread); /* Returns whether to show which thread hit the breakpoint, received a signal, etc. and ended up causing a user-visible stop. This is @@ -665,6 +742,12 @@ extern int show_thread_that_caused_stop (void); extern void print_selected_thread_frame (struct ui_out *uiout, user_selected_what selection); +/* Helper for the CLI's "thread" command and for MI's -thread-select. + Selects thread THR. TIDSTR is the original string the thread ID + was parsed from. This is used in the error message if THR is not + alive anymore. */ +extern void thread_select (const char *tidstr, class thread_info *thr); + extern struct thread_info *thread_list; #endif /* GDBTHREAD_H */