|  | /* Native debugging support for GNU/Linux (LWP layer). | 
|  |  | 
|  | Copyright (C) 2000-2022 Free Software Foundation, Inc. | 
|  |  | 
|  | 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 LINUX_NAT_H | 
|  | #define LINUX_NAT_H | 
|  |  | 
|  | #include "nat/linux-nat.h" | 
|  | #include "inf-ptrace.h" | 
|  | #include "target.h" | 
|  | #include <signal.h> | 
|  |  | 
|  | /* A prototype generic GNU/Linux target.  A concrete instance should | 
|  | override it with local methods.  */ | 
|  |  | 
|  | class linux_nat_target : public inf_ptrace_target | 
|  | { | 
|  | public: | 
|  | linux_nat_target (); | 
|  | ~linux_nat_target () override = 0; | 
|  |  | 
|  | thread_control_capabilities get_thread_control_capabilities () override | 
|  | { return tc_schedlock; } | 
|  |  | 
|  | void create_inferior (const char *, const std::string &, | 
|  | char **, int) override; | 
|  |  | 
|  | void attach (const char *, int) override; | 
|  |  | 
|  | void detach (inferior *, int) override; | 
|  |  | 
|  | void resume (ptid_t, int, enum gdb_signal) override; | 
|  |  | 
|  | ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override; | 
|  |  | 
|  | void pass_signals (gdb::array_view<const unsigned char>) override; | 
|  |  | 
|  | enum target_xfer_status xfer_partial (enum target_object object, | 
|  | const char *annex, | 
|  | gdb_byte *readbuf, | 
|  | const gdb_byte *writebuf, | 
|  | ULONGEST offset, ULONGEST len, | 
|  | ULONGEST *xfered_len) override; | 
|  |  | 
|  | void kill () override; | 
|  |  | 
|  | void mourn_inferior () override; | 
|  | bool thread_alive (ptid_t ptid) override; | 
|  |  | 
|  | void update_thread_list () override; | 
|  |  | 
|  | std::string pid_to_str (ptid_t) override; | 
|  |  | 
|  | const char *thread_name (struct thread_info *) override; | 
|  |  | 
|  | struct address_space *thread_address_space (ptid_t) override; | 
|  |  | 
|  | bool stopped_by_watchpoint () override; | 
|  |  | 
|  | bool stopped_data_address (CORE_ADDR *) override; | 
|  |  | 
|  | bool stopped_by_sw_breakpoint () override; | 
|  | bool supports_stopped_by_sw_breakpoint () override; | 
|  |  | 
|  | bool stopped_by_hw_breakpoint () override; | 
|  | bool supports_stopped_by_hw_breakpoint () override; | 
|  |  | 
|  | void thread_events (int) override; | 
|  |  | 
|  | bool can_async_p () override; | 
|  |  | 
|  | bool supports_non_stop () override; | 
|  | bool always_non_stop_p () override; | 
|  |  | 
|  | void async (bool) override; | 
|  |  | 
|  | void stop (ptid_t) override; | 
|  |  | 
|  | bool supports_multi_process () override; | 
|  |  | 
|  | bool supports_disable_randomization () override; | 
|  |  | 
|  | int core_of_thread (ptid_t ptid) override; | 
|  |  | 
|  | bool filesystem_is_local () override; | 
|  |  | 
|  | int fileio_open (struct inferior *inf, const char *filename, | 
|  | int flags, int mode, int warn_if_slow, | 
|  | fileio_error *target_errno) override; | 
|  |  | 
|  | gdb::optional<std::string> | 
|  | fileio_readlink (struct inferior *inf, | 
|  | const char *filename, | 
|  | fileio_error *target_errno) override; | 
|  |  | 
|  | int fileio_unlink (struct inferior *inf, | 
|  | const char *filename, | 
|  | fileio_error *target_errno) override; | 
|  |  | 
|  | int insert_fork_catchpoint (int) override; | 
|  | int remove_fork_catchpoint (int) override; | 
|  | int insert_vfork_catchpoint (int) override; | 
|  | int remove_vfork_catchpoint (int) override; | 
|  |  | 
|  | int insert_exec_catchpoint (int) override; | 
|  | int remove_exec_catchpoint (int) override; | 
|  |  | 
|  | int set_syscall_catchpoint (int pid, bool needed, int any_count, | 
|  | gdb::array_view<const int> syscall_counts) override; | 
|  |  | 
|  | const char *pid_to_exec_file (int pid) override; | 
|  |  | 
|  | void post_attach (int) override; | 
|  |  | 
|  | void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override; | 
|  |  | 
|  | std::vector<static_tracepoint_marker> | 
|  | static_tracepoint_markers_by_strid (const char *id) override; | 
|  |  | 
|  | /* Methods that are meant to overridden by the concrete | 
|  | arch-specific target instance.  */ | 
|  |  | 
|  | virtual void low_resume (ptid_t ptid, int step, enum gdb_signal sig) | 
|  | { inf_ptrace_target::resume (ptid, step, sig); } | 
|  |  | 
|  | virtual bool low_stopped_by_watchpoint () | 
|  | { return false; } | 
|  |  | 
|  | virtual bool low_stopped_data_address (CORE_ADDR *addr_p) | 
|  | { return false; } | 
|  |  | 
|  | /* The method to call, if any, when a new thread is attached.  */ | 
|  | virtual void low_new_thread (struct lwp_info *) | 
|  | {} | 
|  |  | 
|  | /* The method to call, if any, when a thread is destroyed.  */ | 
|  | virtual void low_delete_thread (struct arch_lwp_info *lp) | 
|  | { | 
|  | gdb_assert (lp == NULL); | 
|  | } | 
|  |  | 
|  | /* The method to call, if any, when a new fork is attached.  */ | 
|  | virtual void low_new_fork (struct lwp_info *parent, pid_t child_pid) | 
|  | {} | 
|  |  | 
|  | /* The method to call, if any, when a new clone event is detected.  */ | 
|  | virtual void low_new_clone (struct lwp_info *parent, pid_t child_lwp) | 
|  | {} | 
|  |  | 
|  | /* The method to call, if any, when a process is no longer | 
|  | attached.  */ | 
|  | virtual void low_forget_process (pid_t pid) | 
|  | {} | 
|  |  | 
|  | /* Hook to call prior to resuming a thread.  */ | 
|  | virtual void low_prepare_to_resume (struct lwp_info *) | 
|  | {} | 
|  |  | 
|  | /* Convert a ptrace/host siginfo object, into/from the siginfo in | 
|  | the layout of the inferiors' architecture.  Returns true if any | 
|  | conversion was done; false otherwise, in which case the caller | 
|  | does a straight memcpy.  If DIRECTION is 1, then copy from INF to | 
|  | PTRACE.  If DIRECTION is 0, copy from PTRACE to INF.  */ | 
|  | virtual bool low_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, | 
|  | int direction) | 
|  | { return false; } | 
|  |  | 
|  | /* SIGTRAP-like breakpoint status events recognizer.  The default | 
|  | recognizes SIGTRAP only.  */ | 
|  | virtual bool low_status_is_event (int status); | 
|  |  | 
|  | protected: | 
|  |  | 
|  | void post_startup_inferior (ptid_t) override; | 
|  | }; | 
|  |  | 
|  | /* The final/concrete instance.  */ | 
|  | extern linux_nat_target *linux_target; | 
|  |  | 
|  | struct arch_lwp_info; | 
|  |  | 
|  | /* Structure describing an LWP.  */ | 
|  |  | 
|  | struct lwp_info : intrusive_list_node<lwp_info> | 
|  | { | 
|  | lwp_info (ptid_t ptid) | 
|  | : ptid (ptid) | 
|  | {} | 
|  |  | 
|  | ~lwp_info (); | 
|  |  | 
|  | DISABLE_COPY_AND_ASSIGN (lwp_info); | 
|  |  | 
|  | /* The process id of the LWP.  This is a combination of the LWP id | 
|  | and overall process id.  */ | 
|  | ptid_t ptid = null_ptid; | 
|  |  | 
|  | /* If this flag is set, we need to set the event request flags the | 
|  | next time we see this LWP stop.  */ | 
|  | int must_set_ptrace_flags = 0; | 
|  |  | 
|  | /* Non-zero if we sent this LWP a SIGSTOP (but the LWP didn't report | 
|  | it back yet).  */ | 
|  | int signalled = 0; | 
|  |  | 
|  | /* Non-zero if this LWP is stopped.  */ | 
|  | int stopped = 0; | 
|  |  | 
|  | /* Non-zero if this LWP will be/has been resumed.  Note that an LWP | 
|  | can be marked both as stopped and resumed at the same time.  This | 
|  | happens if we try to resume an LWP that has a wait status | 
|  | pending.  We shouldn't let the LWP run until that wait status has | 
|  | been processed, but we should not report that wait status if GDB | 
|  | didn't try to let the LWP run.  */ | 
|  | int resumed = 0; | 
|  |  | 
|  | /* The last resume GDB requested on this thread.  */ | 
|  | resume_kind last_resume_kind = resume_continue; | 
|  |  | 
|  | /* If non-zero, a pending wait status.  */ | 
|  | int status = 0; | 
|  |  | 
|  | /* When 'stopped' is set, this is where the lwp last stopped, with | 
|  | decr_pc_after_break already accounted for.  If the LWP is | 
|  | running and stepping, this is the address at which the lwp was | 
|  | resumed (that is, it's the previous stop PC).  If the LWP is | 
|  | running and not stepping, this is 0.  */ | 
|  | CORE_ADDR stop_pc = 0; | 
|  |  | 
|  | /* Non-zero if we were stepping this LWP.  */ | 
|  | int step = 0; | 
|  |  | 
|  | /* The reason the LWP last stopped, if we need to track it | 
|  | (breakpoint, watchpoint, etc.).  */ | 
|  | target_stop_reason stop_reason = TARGET_STOPPED_BY_NO_REASON; | 
|  |  | 
|  | /* On architectures where it is possible to know the data address of | 
|  | a triggered watchpoint, STOPPED_DATA_ADDRESS_P is non-zero, and | 
|  | STOPPED_DATA_ADDRESS contains such data address.  Otherwise, | 
|  | STOPPED_DATA_ADDRESS_P is false, and STOPPED_DATA_ADDRESS is | 
|  | undefined.  Only valid if STOPPED_BY_WATCHPOINT is true.  */ | 
|  | int stopped_data_address_p = 0; | 
|  | CORE_ADDR stopped_data_address = 0; | 
|  |  | 
|  | /* Non-zero if we expect a duplicated SIGINT.  */ | 
|  | int ignore_sigint = 0; | 
|  |  | 
|  | /* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus | 
|  | for this LWP's last event.  This may correspond to STATUS above, | 
|  | or to a local variable in lin_lwp_wait.  */ | 
|  | struct target_waitstatus waitstatus; | 
|  |  | 
|  | /* Signal whether we are in a SYSCALL_ENTRY or | 
|  | in a SYSCALL_RETURN event. | 
|  | Values: | 
|  | - TARGET_WAITKIND_SYSCALL_ENTRY | 
|  | - TARGET_WAITKIND_SYSCALL_RETURN */ | 
|  | enum target_waitkind syscall_state; | 
|  |  | 
|  | /* The processor core this LWP was last seen on.  */ | 
|  | int core = -1; | 
|  |  | 
|  | /* Arch-specific additions.  */ | 
|  | struct arch_lwp_info *arch_private = nullptr; | 
|  | }; | 
|  |  | 
|  | /* lwp_info iterator and range types.  */ | 
|  |  | 
|  | using lwp_info_iterator | 
|  | = reference_to_pointer_iterator<intrusive_list<lwp_info>::iterator>; | 
|  | using lwp_info_range = iterator_range<lwp_info_iterator>; | 
|  | using lwp_info_safe_range = basic_safe_range<lwp_info_range>; | 
|  |  | 
|  | /* Get an iterable range over all lwps.  */ | 
|  |  | 
|  | lwp_info_range all_lwps (); | 
|  |  | 
|  | /* Same as the above, but safe against deletion while iterating.  */ | 
|  |  | 
|  | lwp_info_safe_range all_lwps_safe (); | 
|  |  | 
|  | /* Does the current host support PTRACE_GETREGSET?  */ | 
|  | extern enum tribool have_ptrace_getregset; | 
|  |  | 
|  | /* Called from the LWP layer to inform the thread_db layer that PARENT | 
|  | spawned CHILD.  Both LWPs are currently stopped.  This function | 
|  | does whatever is required to have the child LWP under the | 
|  | thread_db's control --- e.g., enabling event reporting.  Returns | 
|  | true on success, false if the process isn't using libpthread.  */ | 
|  | extern int thread_db_notice_clone (ptid_t parent, ptid_t child); | 
|  |  | 
|  | /* Return the number of signals used by the threads library.  */ | 
|  | extern unsigned int lin_thread_get_thread_signal_num (void); | 
|  |  | 
|  | /* Return the i-th signal used by the threads library.  */ | 
|  | extern int lin_thread_get_thread_signal (unsigned int i); | 
|  |  | 
|  | /* Find process PID's pending signal set from /proc/pid/status.  */ | 
|  | void linux_proc_pending_signals (int pid, sigset_t *pending, | 
|  | sigset_t *blocked, sigset_t *ignored); | 
|  |  | 
|  | /* For linux_stop_lwp see nat/linux-nat.h.  */ | 
|  |  | 
|  | /* Stop all LWPs, synchronously.  (Any events that trigger while LWPs | 
|  | are being stopped are left pending.)  */ | 
|  | extern void linux_stop_and_wait_all_lwps (void); | 
|  |  | 
|  | /* Set resumed LWPs running again, as they were before being stopped | 
|  | with linux_stop_and_wait_all_lwps.  (LWPS with pending events are | 
|  | left stopped.)  */ | 
|  | extern void linux_unstop_all_lwps (void); | 
|  |  | 
|  | /* Update linux-nat internal state when changing from one fork | 
|  | to another.  */ | 
|  | void linux_nat_switch_fork (ptid_t new_ptid); | 
|  |  | 
|  | /* Store the saved siginfo associated with PTID in *SIGINFO. | 
|  | Return true if it was retrieved successfully, false otherwise (*SIGINFO is | 
|  | uninitialized in such case).  */ | 
|  | bool linux_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo); | 
|  |  | 
|  | #endif /* LINUX_NAT_H */ |