12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037 |
- /* Multi-process/thread control defs for GDB, the GNU debugger.
- Copyright (C) 1987-2022 Free Software Foundation, Inc.
- Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
-
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #ifndef GDBTHREAD_H
- #define GDBTHREAD_H
- struct symtab;
- #include "breakpoint.h"
- #include "frame.h"
- #include "ui-out.h"
- #include "btrace.h"
- #include "target/waitstatus.h"
- #include "cli/cli-utils.h"
- #include "gdbsupport/refcounted-object.h"
- #include "gdbsupport/common-gdbthread.h"
- #include "gdbsupport/forward-scope-exit.h"
- #include "displaced-stepping.h"
- #include "gdbsupport/intrusive_list.h"
- #include "thread-fsm.h"
- struct inferior;
- struct process_stratum_target;
- /* When true, print debug messages related to GDB thread creation and
- deletion. */
- extern bool debug_threads;
- /* Print a "threads" debug statement. */
- #define threads_debug_printf(fmt, ...) \
- debug_prefixed_printf_cond (debug_threads, "threads", fmt, ##__VA_ARGS__)
- /* Frontend view of the thread state. Possible extensions: stepping,
- finishing, until(ling),...
- 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 (tp->state == THREAD_STOPPED)
- instead of (bad):
- if (tp->state != THREAD_RUNNING)
- The latter is also true for exited threads, most likely not what
- you want. */
- enum thread_state
- {
- /* In the frontend's perpective, the thread is stopped. */
- THREAD_STOPPED,
- /* In the frontend's perpective, the thread is running. */
- THREAD_RUNNING,
- /* The thread is listed, but known to have exited. We keep it
- listed (but not visible) until it's safe to delete it. */
- THREAD_EXITED,
- };
- /* STEP_OVER_ALL means step over all subroutine calls.
- STEP_OVER_UNDEBUGGABLE means step over calls to undebuggable functions.
- STEP_OVER_NONE means don't step over any subroutine calls. */
- enum step_over_calls_kind
- {
- STEP_OVER_NONE,
- STEP_OVER_ALL,
- STEP_OVER_UNDEBUGGABLE
- };
- /* Inferior thread specific part of `struct infcall_control_state'.
- Inferior process counterpart is `struct inferior_control_state'. */
- struct thread_control_state
- {
- /* User/external stepping state. */
- /* Step-resume or longjmp-resume breakpoint. */
- struct breakpoint *step_resume_breakpoint = nullptr;
- /* 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 = nullptr;
- /* 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 = 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 = nullptr;
- /* If GDB issues a target step request, and this is nonzero, the
- target should single-step this thread once, and then continue
- single-stepping it without GDB core involvement as long as the
- 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 = 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 {};
- /* Similarly, the frame ID of the underlying stack frame (skipping
- any inlined frames). */
- struct frame_id step_stack_frame_id {};
- /* True if the the thread is presently stepping over a breakpoint or
- a watchpoint, either with an inline step over or a displaced (out
- of line) step, and we're now expecting it to report a trap for
- the finished single step. */
- 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 = 0;
- /* Nonzero if the thread is being proceeded for an inferior function
- call. */
- int in_infcall = 0;
- enum step_over_calls_kind step_over_calls = STEP_OVER_NONE;
- /* Nonzero if stopped due to a step command. */
- int stop_step = 0;
- /* Chain containing status of breakpoint(s) the thread stopped
- at. */
- 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 = 0;
- };
- /* Inferior thread specific part of `struct infcall_suspend_state'. */
- struct thread_suspend_state
- {
- /* Last signal that the inferior received (why it stopped). When
- the thread is resumed, this signal is delivered. Note: the
- target should not check whether the signal is in pass state,
- because the signal may have been explicitly passed with the
- "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 = GDB_SIGNAL_0;
- /* The reason the thread last stopped, if we need to track it
- (breakpoint, watchpoint, etc.) */
- enum target_stop_reason stop_reason = TARGET_STOPPED_BY_NO_REASON;
- /* The waitstatus for this thread's last event. */
- struct target_waitstatus waitstatus;
- /* If true WAITSTATUS hasn't been handled yet. */
- 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").
- - 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, then this field has its value removed by
- calling stop_pc.reset() (see thread_info::set_executing()).
- Attempting to read a gdb::optional with no value is undefined
- behaviour and will trigger an assertion error when _GLIBCXX_DEBUG is
- defined, which should make error easier to track down. */
- gdb::optional<CORE_ADDR> stop_pc;
- };
- /* Base class for target-specific thread data. */
- struct private_thread_info
- {
- virtual ~private_thread_info () = 0;
- };
- /* 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 scoped_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.
- The intrusive_list_node base links threads in a per-inferior list. */
- class thread_info : public refcounted_object,
- public intrusive_list_node<thread_info>
- {
- public:
- explicit thread_info (inferior *inf, ptid_t ptid);
- ~thread_info ();
- bool deletable () const;
- /* Mark this thread as running and notify observers. */
- void set_running (bool running);
- ptid_t ptid; /* "Actual process id";
- In fact, this may be overloaded with
- kernel thread id, etc. */
- /* Each thread has two GDB IDs.
- a) The thread ID (Id). This consists of the pair of:
- - the number of the thread's inferior and,
- - the thread's thread number in its inferior, aka, the
- per-inferior thread number. This number is unique in the
- inferior but not unique between inferiors.
- b) The global ID (GId). This is a a single integer unique
- between all inferiors.
- E.g.:
- (gdb) info threads -gid
- Id GId Target Id Frame
- * 1.1 1 Thread A 0x16a09237 in foo () at foo.c:10
- 1.2 3 Thread B 0x15ebc6ed in bar () at foo.c:20
- 1.3 5 Thread C 0x15ebc6ed in bar () at foo.c:20
- 2.1 2 Thread A 0x16a09237 in foo () at foo.c:10
- 2.2 4 Thread B 0x15ebc6ed in bar () at foo.c:20
- 2.3 6 Thread C 0x15ebc6ed in bar () at foo.c:20
- Above, both inferiors 1 and 2 have threads numbered 1-3, but each
- thread has its own unique global ID. */
- /* The thread's global GDB thread number. This is exposed to MI,
- Python/Scheme, visible with "info threads -gid", and is also what
- the $_gthread convenience variable is bound to. */
- int global_num;
- /* The per-inferior thread number. This is unique in the inferior
- the thread belongs to, but not unique between inferiors. This is
- what the $_thread convenience variable is bound to. */
- int per_inf_num;
- /* The inferior this thread belongs to. */
- struct inferior *inf;
- /* The user-given name of the thread.
- Returns nullptr if the thread does not have a user-given name. */
- const char *name () const
- {
- return m_name.get ();
- }
- /* Set the user-given name of the thread.
- Pass nullptr to clear the name. */
- void set_name (gdb::unique_xmalloc_ptr<char> name)
- {
- m_name = std::move (name);
- }
- bool executing () const
- { return m_executing; }
- /* Set the thread's 'm_executing' field from EXECUTING, and if EXECUTING
- is true also clears the thread's stop_pc. */
- void set_executing (bool executing);
- bool resumed () const
- { return m_resumed; }
- /* Set the thread's 'm_resumed' field from RESUMED. The thread may also
- be added to (when RESUMED is true), or removed from (when RESUMED is
- false), the list of threads with a pending wait status. */
- void set_resumed (bool resumed);
- /* Frontend view of the thread state. Note that the THREAD_RUNNING/
- THREAD_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 STATE will still be THREAD_RUNNING. */
- enum thread_state state = THREAD_STOPPED;
- /* State of GDB control of inferior thread execution.
- See `struct thread_control_state'. */
- thread_control_state control;
- /* Save M_SUSPEND to SUSPEND. */
- void save_suspend_to (thread_suspend_state &suspend) const
- {
- suspend = m_suspend;
- }
- /* Restore M_SUSPEND from SUSPEND. */
- void restore_suspend_from (const thread_suspend_state &suspend)
- {
- m_suspend = suspend;
- }
- /* Return this thread's stop PC. This should only be called when it is
- known that stop_pc has a value. If this function is being used in a
- situation where a thread may not have had a stop_pc assigned, then
- stop_pc_p() can be used to check if the stop_pc is defined. */
- CORE_ADDR stop_pc () const
- {
- gdb_assert (m_suspend.stop_pc.has_value ());
- return *m_suspend.stop_pc;
- }
- /* Set this thread's stop PC. */
- void set_stop_pc (CORE_ADDR stop_pc)
- {
- m_suspend.stop_pc = stop_pc;
- }
- /* Remove the stop_pc stored on this thread. */
- void clear_stop_pc ()
- {
- m_suspend.stop_pc.reset ();
- }
- /* Return true if this thread has a cached stop pc value, otherwise
- return false. */
- bool stop_pc_p () const
- {
- return m_suspend.stop_pc.has_value ();
- }
- /* Return true if this thread has a pending wait status. */
- bool has_pending_waitstatus () const
- {
- return m_suspend.waitstatus_pending_p;
- }
- /* Get this thread's pending wait status.
- May only be called if has_pending_waitstatus returns true. */
- const target_waitstatus &pending_waitstatus () const
- {
- gdb_assert (this->has_pending_waitstatus ());
- return m_suspend.waitstatus;
- }
- /* Set this thread's pending wait status.
- May only be called if has_pending_waitstatus returns false. */
- void set_pending_waitstatus (const target_waitstatus &ws);
- /* Clear this thread's pending wait status.
- May only be called if has_pending_waitstatus returns true. */
- void clear_pending_waitstatus ();
- /* Return this thread's stop signal. */
- gdb_signal stop_signal () const
- {
- return m_suspend.stop_signal;
- }
- /* Set this thread's stop signal. */
- void set_stop_signal (gdb_signal sig)
- {
- m_suspend.stop_signal = sig;
- }
- /* Return this thread's stop reason. */
- target_stop_reason stop_reason () const
- {
- return m_suspend.stop_reason;
- }
- /* Set this thread's stop reason. */
- void set_stop_reason (target_stop_reason reason)
- {
- m_suspend.stop_reason = reason;
- }
- /* Get the FSM associated with the thread. */
- struct thread_fsm *thread_fsm () const
- {
- return m_thread_fsm.get ();
- }
- /* Get the owning reference to the FSM associated with the thread.
- After a call to this method, "thread_fsm () == nullptr". */
- std::unique_ptr<struct thread_fsm> release_thread_fsm ()
- {
- return std::move (m_thread_fsm);
- }
- /* Set the FSM associated with the current thread.
- It is invalid to set the FSM if another FSM is already installed. */
- void set_thread_fsm (std::unique_ptr<struct thread_fsm> fsm)
- {
- gdb_assert (m_thread_fsm == nullptr);
- m_thread_fsm = std::move (fsm);
- }
- int current_line = 0;
- struct symtab *current_symtab = NULL;
- /* Internal stepping state. */
- /* Record the pc of the thread the last time it was resumed. (It
- can't be done on stop as the PC may change since the last stop,
- e.g., "return" command, or "p $pc = 0xf000"). This is maintained
- by proceed and keep_going, and among other things, it's used in
- adjust_pc_after_break to distinguish a hardware single-step
- SIGTRAP from a breakpoint SIGTRAP. */
- CORE_ADDR prev_pc = 0;
- /* Did we set the thread stepping a breakpoint instruction? This is
- used in conjunction with PREV_PC to decide whether to adjust the
- PC. */
- int stepped_breakpoint = 0;
- /* Should we step over breakpoint next time keep_going is called? */
- int stepping_over_breakpoint = 0;
- /* Should we step over a watchpoint next time keep_going is called?
- This is needed on targets with non-continuable, non-steppable
- watchpoints. */
- int stepping_over_watchpoint = 0;
- /* Set to TRUE if we should finish single-stepping over a breakpoint
- after hitting the current step-resume breakpoint. The context here
- is that GDB is to do `next' or `step' while signal arrives.
- When stepping over a breakpoint and signal arrives, GDB will attempt
- to skip signal handler, so it inserts a step_resume_breakpoint at the
- signal return address, and resume inferior.
- step_after_step_resume_breakpoint is set to TRUE at this moment in
- order to keep GDB in mind that there is still a breakpoint to step over
- when GDB gets back SIGTRAP from step_resume_breakpoint. */
- int step_after_step_resume_breakpoint = 0;
- /* This is used to remember when a fork or vfork event was caught by
- a catchpoint, and thus the event is to be followed at the next
- resume of the thread, and not immediately. */
- struct target_waitstatus pending_follow;
- /* True if this thread has been explicitly requested to stop. */
- int stop_requested = 0;
- /* The initiating frame of a nexting operation, used for deciding
- which exceptions to intercept. If it is null_frame_id no
- bp_longjmp or bp_exception but longjmp has been caught just for
- bp_longjmp_call_dummy. */
- struct frame_id initiating_frame = null_frame_id;
- /* Private data used by the target vector implementation. */
- std::unique_ptr<private_thread_info> 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. */
- bool stack_temporaries_enabled = false;
- /* Values that are stored as temporaries on stack while evaluating
- expressions. */
- std::vector<struct value *> stack_temporaries;
- /* Step-over chain. A thread is in the step-over queue if this node is
- linked. */
- intrusive_list_node<thread_info> step_over_list_node;
- /* Node for list of threads that are resumed and have a pending wait status.
- The list head for this is in process_stratum_target, hence all threads in
- this list belong to that process target. */
- intrusive_list_node<thread_info> resumed_with_pending_wait_status_node;
- /* Displaced-step state for this thread. */
- displaced_step_thread_state displaced_step_state;
- private:
- /* True if this thread is resumed from infrun's perspective.
- Note that a thread can be marked both as not-executing and
- resumed at the same time. This happens if we try to resume a
- thread that has a wait status pending. We shouldn't let the
- thread really run until that wait status has been processed, but
- we should not process that wait status if we didn't try to let
- the thread run. */
- bool m_resumed = false;
- /* True 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. */
- bool m_executing = false;
- /* State of inferior thread to restore after GDB is done with an inferior
- call. See `struct thread_suspend_state'. */
- thread_suspend_state m_suspend;
- /* The user-given name of the thread.
- Nullptr if the thread does not have a user-given name. */
- gdb::unique_xmalloc_ptr<char> m_name;
- /* Pointer to the state machine manager object that handles what is
- left to do for the thread's execution command after the target
- stops. Several execution commands use it. */
- std::unique_ptr<struct thread_fsm> m_thread_fsm;
- };
- using thread_info_resumed_with_pending_wait_status_node
- = intrusive_member_node<thread_info,
- &thread_info::resumed_with_pending_wait_status_node>;
- using thread_info_resumed_with_pending_wait_status_list
- = intrusive_list<thread_info,
- thread_info_resumed_with_pending_wait_status_node>;
- /* A gdb::ref_ptr pointer to a thread_info. */
- using thread_info_ref
- = gdb::ref_ptr<struct thread_info, refcounted_object_ref_policy>;
- /* A gdb::ref_ptr pointer to an inferior. This would ideally be in
- inferior.h, but it can't due to header dependencies (inferior.h
- includes gdbthread.h). */
- using inferior_ref
- = gdb::ref_ptr<struct inferior, refcounted_object_ref_policy>;
- /* Create an empty thread list, or empty the existing one. */
- extern void init_thread_list (void);
- /* 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 (process_stratum_target *targ,
- ptid_t ptid);
- /* Same as add_thread, but does not print a message about new
- thread. */
- extern struct thread_info *add_thread_silent (process_stratum_target *targ,
- ptid_t ptid);
- /* Same as add_thread, and sets the private info. */
- extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
- ptid_t ptid,
- private_thread_info *);
- /* Delete thread THREAD and notify of thread exit. If the thread is
- currently not deletable, don't actually delete it but still tag it
- as exited and do the notification. */
- extern void delete_thread (struct thread_info *thread);
- /* Like delete_thread, but be quiet about it. Used when the process
- this thread belonged to has already exited, for example. */
- extern void delete_thread_silent (struct thread_info *thread);
- /* Mark the thread exited, but don't delete it or remove it from the
- inferior thread list. */
- extern void set_thread_exited (thread_info *tp, bool silent);
- /* Delete a step_resume_breakpoint from the thread database. */
- extern void delete_step_resume_breakpoint (struct thread_info *);
- /* Delete an exception_resume_breakpoint from the thread database. */
- extern void delete_exception_resume_breakpoint (struct thread_info *);
- /* Delete the single-step breakpoints of thread TP, if any. */
- extern void delete_single_step_breakpoints (struct thread_info *tp);
- /* Check if the thread has software single stepping breakpoints
- set. */
- 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,
- const address_space *aspace,
- CORE_ADDR addr);
- /* 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. */
- extern int show_inferior_qualified_tids (void);
- /* Return a string version of THR's thread ID. If there are multiple
- inferiors, then this prints the inferior-qualifier form, otherwise
- it only prints the thread number. The result is stored in a
- circular static buffer, NUMCELLS deep. */
- const char *print_thread_id (struct thread_info *thr);
- /* Boolean test for an already-known ptid. */
- extern bool in_thread_list (process_stratum_target *targ, ptid_t ptid);
- /* Boolean test for an already-known global thread id (GDB's homegrown
- global id, not the system's). */
- extern int valid_global_thread_id (int global_id);
- /* Find (non-exited) thread PTID of inferior INF. */
- extern thread_info *find_thread_ptid (inferior *inf, ptid_t ptid);
- /* Search function to lookup a (non-exited) thread by 'ptid'. */
- extern struct thread_info *find_thread_ptid (process_stratum_target *targ,
- ptid_t ptid);
- /* Find thread by GDB global thread ID. */
- struct thread_info *find_thread_global_id (int global_id);
- /* Find thread by thread library specific handle in inferior INF. */
- struct thread_info *find_thread_by_handle
- (gdb::array_view<const gdb_byte> handle, struct inferior *inf);
- /* Finds the first thread of the specified inferior. */
- extern struct thread_info *first_thread_of_inferior (inferior *inf);
- /* 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_inferior (inferior *inf);
- /* Change the ptid of thread OLD_PTID to NEW_PTID. */
- void thread_change_ptid (process_stratum_target *targ,
- 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 *);
- /* Pull in the internals of the inferiors/threads ranges and
- iterators. Must be done after struct thread_info is defined. */
- #include "thread-iter.h"
- /* Return a range that can be used to walk over threads, with
- range-for.
- Used like this, it walks over all threads of all inferiors of all
- targets:
- for (thread_info *thr : all_threads ())
- { .... }
- FILTER_PTID can be used to filter out threads that don't match.
- FILTER_PTID can be:
- - minus_one_ptid, meaning walk all threads of all inferiors of
- PROC_TARGET. If PROC_TARGET is NULL, then of all targets.
- - A process ptid, in which case walk all threads of the specified
- process. PROC_TARGET must be non-NULL in this case.
- - A thread ptid, in which case walk that thread only. PROC_TARGET
- must be non-NULL in this case.
- */
- inline all_matching_threads_range
- all_threads (process_stratum_target *proc_target = nullptr,
- ptid_t filter_ptid = minus_one_ptid)
- {
- return all_matching_threads_range (proc_target, filter_ptid);
- }
- /* Return a range that can be used to walk over all non-exited threads
- of all inferiors, with range-for. Arguments are like all_threads
- above. */
- inline all_non_exited_threads_range
- all_non_exited_threads (process_stratum_target *proc_target = nullptr,
- ptid_t filter_ptid = minus_one_ptid)
- {
- return all_non_exited_threads_range (proc_target, filter_ptid);
- }
- /* Return a range that can be used to walk over all threads of all
- inferiors, with range-for, safely. I.e., it is safe to delete the
- currently-iterated thread. When combined with range-for, this
- allow convenient patterns like this:
- for (thread_info *t : all_threads_safe ())
- if (some_condition ())
- delete f;
- */
- inline all_threads_safe_range
- all_threads_safe ()
- {
- return all_threads_safe_range (all_threads_iterator::begin_t {});
- }
- extern int thread_count (process_stratum_target *proc_target);
- /* Return true if we have any thread in any inferior. */
- extern bool any_thread_p ();
- /* 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. */
- extern void switch_to_thread_no_regs (struct thread_info *thread);
- /* Marks or clears thread(s) PTID of TARG as resumed. If PTID is
- MINUS_ONE_PTID, applies to all threads of TARG. If
- ptid_is_pid(PTID) is true, applies to all threads of the process
- pointed at by {TARG,PTID}. */
- extern void set_resumed (process_stratum_target *targ,
- ptid_t ptid, bool resumed);
- /* Marks thread PTID of TARG as running, or as stopped. If PTID is
- minus_one_ptid, marks all threads of TARG. */
- extern void set_running (process_stratum_target *targ,
- ptid_t ptid, bool running);
- /* Marks or clears thread(s) PTID of TARG as having been requested to
- stop. If PTID is MINUS_ONE_PTID, applies to all threads of TARG.
- If ptid_is_pid(PTID) is true, applies to all threads of the process
- pointed at by {TARG, PTID}. If STOP, then the
- THREAD_STOP_REQUESTED observer is called with PTID as argument. */
- extern void set_stop_requested (process_stratum_target *targ,
- ptid_t ptid, bool stop);
- /* Marks thread PTID of TARG as executing, or not. If PTID is
- minus_one_ptid, marks all threads of TARG.
- 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 (process_stratum_target *targ,
- ptid_t ptid, bool executing);
- /* True if any (known or unknown) thread of TARG is or may be
- executing. */
- extern bool threads_are_executing (process_stratum_target *targ);
- /* Merge the executing property of thread PTID of TARG over to its
- thread state property (frontend running/stopped view).
- "not executing" -> "stopped"
- "executing" -> "running"
- "exited" -> "exited"
- If PTID is minus_one_ptid, go over all threads of TARG.
- Notifications are only emitted if the thread state did change. */
- extern void finish_thread_state (process_stratum_target *targ, ptid_t ptid);
- /* Calls finish_thread_state on scope exit, unless release() is called
- to disengage. */
- using scoped_finish_thread_state
- = FORWARD_SCOPE_EXIT (finish_thread_state);
- /* Commands with a prefix of `thread'. */
- extern struct cmd_list_element *thread_cmd_list;
- extern void thread_command (const char *tidstr, int from_tty);
- /* Print notices on thread events (attach, detach, etc.), set with
- `set print thread-events'. */
- extern bool print_thread_events;
- /* Prints the list of threads and their details on UIOUT. If
- REQUESTED_THREADS, a list of GDB ids/ranges, is not NULL, only
- print threads whose ID is included in the list. If PID is not -1,
- only print threads from the process PID. Otherwise, threads from
- all attached PIDs are printed. If both REQUESTED_THREADS is not
- NULL and PID is not -1, then the thread is printed if it belongs to
- the specified process. Otherwise, an error is raised. */
- extern void print_thread_info (struct ui_out *uiout,
- const char *requested_threads,
- int pid);
- /* 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);
- /* Cancel restoring on scope exit. */
- void dont_restore () { m_dont_restore = true; }
- private:
- void restore ();
- bool m_dont_restore = false;
- thread_info_ref m_thread;
- inferior_ref m_inf;
- frame_id m_selected_frame_id;
- int m_selected_frame_level;
- bool m_was_stopped;
- /* Save/restore the language as well, because selecting a frame
- changes the current language to the frame's language if "set
- language auto". */
- enum language m_lang;
- };
- /* 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);
- extern void update_thread_list (void);
- /* Delete any thread the target says is no longer alive. */
- extern void prune_threads (void);
- /* Delete threads marked THREAD_EXITED. Unlike prune_threads, this
- does not consult the target about whether the thread is alive right
- now. */
- extern void delete_exited_threads (void);
- /* Return true if PC is in the stepping range of THREAD. */
- int pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread);
- /* 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 (thread_info_ref::new_reference (thr))
- {
- 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 ();
- }
- DISABLE_COPY_AND_ASSIGN (enable_thread_stack_temporaries);
- private:
- thread_info_ref m_thr;
- };
- extern bool thread_stack_temporaries_enabled_p (struct thread_info *tp);
- 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);
- /* Thread step-over list type. */
- using thread_step_over_list_node
- = intrusive_member_node<thread_info, &thread_info::step_over_list_node>;
- using thread_step_over_list
- = intrusive_list<thread_info, thread_step_over_list_node>;
- using thread_step_over_list_iterator
- = reference_to_pointer_iterator<thread_step_over_list::iterator>;
- using thread_step_over_list_safe_iterator
- = basic_safe_iterator<thread_step_over_list_iterator>;
- using thread_step_over_list_safe_range
- = iterator_range<thread_step_over_list_safe_iterator>;
- static inline thread_step_over_list_safe_range
- make_thread_step_over_list_safe_range (thread_step_over_list &list)
- {
- return thread_step_over_list_safe_range
- (thread_step_over_list_safe_iterator (list.begin (),
- list.end ()),
- thread_step_over_list_safe_iterator (list.end (),
- list.end ()));
- }
- /* Add TP to the end of the global pending step-over chain. */
- extern void global_thread_step_over_chain_enqueue (thread_info *tp);
- /* Append the thread step over list LIST to the global thread step over
- chain. */
- extern void global_thread_step_over_chain_enqueue_chain
- (thread_step_over_list &&list);
- /* Remove TP from the global pending step-over chain. */
- extern void global_thread_step_over_chain_remove (thread_info *tp);
- /* Return true if TP is in any step-over chain. */
- extern int thread_is_in_step_over_chain (struct thread_info *tp);
- /* Return the length of the the step over chain TP is in.
- If TP is non-nullptr, the thread must be in a step over chain.
- TP may be nullptr, in which case it denotes an empty list, so a length of
- 0. */
- extern int thread_step_over_chain_length (const thread_step_over_list &l);
- /* Cancel any ongoing execution command. */
- extern void thread_cancel_execution_command (struct thread_info *thr);
- /* Check whether it makes sense to access a register of the current
- thread at this point. If not, throw an error (e.g., the thread is
- executing). */
- extern void validate_registers_access (void);
- /* 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_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
- true iff we ever detected multiple threads. */
- extern int show_thread_that_caused_stop (void);
- /* Print the message for a thread or/and frame selected. */
- 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);
- /* Return THREAD's name.
- If THREAD has a user-given name, return it. Otherwise, query the thread's
- target to get the name. May return nullptr. */
- extern const char *thread_name (thread_info *thread);
- /* Switch to thread TP if it is alive. Returns true if successfully
- switched, false otherwise. */
- extern bool switch_to_thread_if_alive (thread_info *thr);
- /* Assuming that THR is the current thread, execute CMD.
- If ADA_TASK is not empty, it is the Ada task ID, and will
- be printed instead of the thread information.
- FLAGS.QUIET controls the printing of the thread information.
- FLAGS.CONT and FLAGS.SILENT control how to handle errors. Can throw an
- exception if !FLAGS.SILENT and !FLAGS.CONT and CMD fails. */
- extern void thread_try_catch_cmd (thread_info *thr,
- gdb::optional<int> ada_task,
- const char *cmd, int from_tty,
- const qcs_flags &flags);
- /* Return a string representation of STATE. */
- extern const char *thread_state_string (enum thread_state state);
- #endif /* GDBTHREAD_H */
|