/* Internal interfaces for the GNU/Linux specific target code for gdbserver.
- Copyright (C) 2002-2020 Free Software Foundation, Inc.
+ Copyright (C) 2002-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "target/waitstatus.h" /* For enum target_stop_reason. */
#include "tracepoint.h"
+#include <list>
+
#define PTRACE_XFER_TYPE long
#ifdef HAVE_LINUX_REGSETS
struct lwp_info;
-struct linux_target_ops
-{
- /* Fill ADDRP with the thread area address of LWPID. Returns 0 on
- success, -1 on failure. */
- int (*get_thread_area) (int lwpid, CORE_ADDR *addrp);
-
- /* Install a fast tracepoint jump pad. See target.h for
- comments. */
- int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr,
- CORE_ADDR collector,
- CORE_ADDR lockaddr,
- ULONGEST orig_size,
- CORE_ADDR *jump_entry,
- CORE_ADDR *trampoline,
- ULONGEST *trampoline_size,
- unsigned char *jjump_pad_insn,
- ULONGEST *jjump_pad_insn_size,
- CORE_ADDR *adjusted_insn_addr,
- CORE_ADDR *adjusted_insn_addr_end,
- char *err);
-
- /* Return the bytecode operations vector for the current inferior.
- Returns NULL if bytecode compilation is not supported. */
- struct emit_ops *(*emit_ops) (void);
-
- /* Return the minimum length of an instruction that can be safely overwritten
- for use as a fast tracepoint. */
- int (*get_min_fast_tracepoint_insn_len) (void);
-
- /* Returns true if the low target supports range stepping. */
- int (*supports_range_stepping) (void);
-
- /* See target.h. */
- int (*supports_hardware_single_step) (void);
-
- /* Fill *SYSNO with the syscall nr trapped. Only to be called when
- inferior is stopped due to SYSCALL_SIGTRAP. */
- void (*get_syscall_trapinfo) (struct regcache *regcache, int *sysno);
-
- /* See target.h. */
- int (*get_ipa_tdesc_idx) (void);
-};
-
-extern struct linux_target_ops the_low_target;
-
/* Target ops definitions for a Linux target. */
class linux_process_target : public process_stratum_target
void resume (thread_resume *resume_info, size_t n) override;
ptid_t wait (ptid_t ptid, target_waitstatus *status,
- int options) override;
+ target_wait_flags options) override;
void fetch_registers (regcache *regcache, int regno) override;
void stabilize_threads () override;
- bool supports_fast_tracepoints () override;
-
- int install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
- CORE_ADDR tpaddr,
- CORE_ADDR collector,
- CORE_ADDR lockaddr,
- ULONGEST orig_size,
- CORE_ADDR *jump_entry,
- CORE_ADDR *trampoline,
- ULONGEST *trampoline_size,
- unsigned char *jjump_pad_insn,
- ULONGEST *jjump_pad_insn_size,
- CORE_ADDR *adjusted_insn_addr,
- CORE_ADDR *adjusted_insn_addr_end,
- char *err) override;
-
- int get_min_fast_tracepoint_insn_len () override;
-
- struct emit_ops *emit_ops () override;
-
bool supports_disable_randomization () override;
bool supports_qxfer_libraries_svr4 () override;
bool supports_pid_to_exec_file () override;
- char *pid_to_exec_file (int pid) override;
+ const char *pid_to_exec_file (int pid) override;
bool supports_multifs () override;
bool supports_catch_syscall () override;
- int get_ipa_tdesc_idx () override;
-
/* Return the information to access registers. This has public
visibility because proc-service uses it. */
virtual const regs_info *get_regs_info () = 0;
to a new LWP representing the new program. */
int handle_extended_wait (lwp_info **orig_event_lwp, int wstat);
- /* Do low-level handling of the event, and check if we should go on
- and pass it to caller code. Return the affected lwp if we are, or
- NULL otherwise. */
- lwp_info *filter_event (int lwpid, int wstat);
+ /* Do low-level handling of the event, and check if this is an event we want
+ to report. Is so, store it as a pending status in the lwp_info structure
+ corresponding to LWPID. */
+ void filter_event (int lwpid, int wstat);
/* Wait for an event from child(ren) WAIT_PTID, and return any that
match FILTER_PTID (leaving others pending). The PTIDs can be:
/* Wait for process, returns status. */
ptid_t wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
- int target_options);
+ target_wait_flags target_options);
/* Stop all lwps that aren't stopped yet, except EXCEPT, if not NULL.
If SUSPEND, then also increase the suspend count of every LWP,
events. */
void complete_ongoing_step_over ();
+ /* Finish a step-over. Reinsert the breakpoint we had uninserted in
+ start_step_over, if still there, and delete any single-step
+ breakpoints we've set, on non hardware single-step targets.
+ Return true if step over finished. */
+ bool finish_step_over (lwp_info *lwp);
+
/* When we finish a step-over, set threads running again. If there's
another thread that may need a step-over, now's the time to start
it. Eventually, we'll move all threads past their breakpoints. */
or can't single step. */
int single_step (lwp_info* lwp);
+ /* Return true if THREAD is doing hardware single step. */
+ bool maybe_hw_step (thread_info *thread);
+
/* Install breakpoints for software single stepping. */
void install_software_single_step_breakpoints (lwp_info *lwp);
ptid_t filter_exit_event (lwp_info *event_child,
target_waitstatus *ourstatus);
+ /* Returns true if THREAD is stopped in a jump pad, and we can't
+ move it out, because we need to report the stop event to GDB. For
+ example, if the user puts a breakpoint in the jump pad, it's
+ because she wants to debug it. */
+ bool stuck_in_jump_pad (thread_info *thread);
+
+ /* Convenience wrapper. Returns information about LWP's fast tracepoint
+ collection status. */
+ fast_tpoint_collect_result linux_fast_tracepoint_collecting
+ (lwp_info *lwp, fast_tpoint_collect_status *status);
+
+ /* This function should only be called if LWP got a SYSCALL_SIGTRAP.
+ Fill *SYSNO with the syscall nr trapped. */
+ void get_syscall_trapinfo (lwp_info *lwp, int *sysno);
+
+ /* Returns true if GDB is interested in the event_child syscall.
+ Only to be called when stopped reason is SYSCALL_SIGTRAP. */
+ bool gdb_catch_this_syscall (lwp_info *event_child);
+
protected:
/* The architecture-specific "low" methods are listed below. */
/* Hook to call prior to resuming a thread. */
virtual void low_prepare_to_resume (lwp_info *lwp);
+ /* Fill ADDRP with the thread area address of LWPID. Returns 0 on
+ success, -1 on failure. */
+ virtual int low_get_thread_area (int lwpid, CORE_ADDR *addrp);
+
+ /* Returns true if the low target supports range stepping. */
+ virtual bool low_supports_range_stepping ();
+
+ /* Return true if the target supports catch syscall. Such targets
+ override the low_get_syscall_trapinfo method below. */
+ virtual bool low_supports_catch_syscall ();
+
+ /* Fill *SYSNO with the syscall nr trapped. Only to be called when
+ inferior is stopped due to SYSCALL_SIGTRAP. */
+ virtual void low_get_syscall_trapinfo (regcache *regcache, int *sysno);
+
/* How many bytes the PC should be decremented after a break. */
virtual int low_decr_pc_after_break ();
};
#define get_thread_lwp(thr) ((struct lwp_info *) (thread_target_data (thr)))
#define get_lwp_thread(lwp) ((lwp)->thread)
+/* Information about a signal that is to be delivered to a thread. */
+
+struct pending_signal
+{
+ pending_signal (int signal)
+ : signal {signal}
+ {};
+
+ int signal;
+ siginfo_t info;
+};
+
/* This struct is recorded in the target_data field of struct thread_info.
On linux ``all_threads'' is keyed by the LWP ID, which we use as the
struct lwp_info
{
/* Backlink to the parent object. */
- struct thread_info *thread;
+ struct thread_info *thread = nullptr;
/* If this flag is set, the next SIGSTOP will be ignored (the
process will be immediately resumed). This means that either we
(so the SIGSTOP is still pending), or that we stopped the
inferior implicitly via PTRACE_ATTACH and have not waited for it
yet. */
- int stop_expected;
+ int stop_expected = 0;
/* When this is true, we shall not try to resume this thread, even
if last_resume_kind isn't resume_stop. */
- int suspended;
+ int suspended = 0;
/* If this flag is set, the lwp is known to be stopped right now (stop
event already received in a wait()). */
- int stopped;
+ int stopped = 0;
/* 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;
+ enum target_waitkind syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY;
/* When stopped is set, the last wait status recorded for this lwp. */
- int last_status;
+ int last_status = 0;
/* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for
this LWP's last event, to pass to GDB without any further
the parent fork event is not reported to higher layers. Used to
avoid wildcard vCont actions resuming a fork child before GDB is
notified about the parent's fork event. */
- struct lwp_info *fork_relative;
+ struct lwp_info *fork_relative = nullptr;
/* When stopped is set, this is where the lwp last stopped, with
decr_pc_after_break already accounted for. If the LWP is
running, this is the address at which the lwp was resumed. */
- CORE_ADDR stop_pc;
+ CORE_ADDR stop_pc = 0;
/* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
been reported. */
- int status_pending_p;
- int status_pending;
+ int status_pending_p = 0;
+ int status_pending = 0;
/* The reason the LWP 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;
/* On architectures where it is possible to know the data address of
a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and
contains such data address. Only valid if STOPPED_BY_WATCHPOINT
is true. */
- CORE_ADDR stopped_data_address;
+ CORE_ADDR stopped_data_address = 0;
/* If this is non-zero, it is a breakpoint to be reinserted at our next
stop (SIGTRAP stops only). */
- CORE_ADDR bp_reinsert;
+ CORE_ADDR bp_reinsert = 0;
/* If this flag is set, the last continue operation at the ptrace
level on this process was a single-step. */
- int stepping;
+ int stepping = 0;
/* Range to single step within. This is a copy of the step range
passed along the last resume request. See 'struct
thread_resume'. */
- 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 */
/* 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;
+ int must_set_ptrace_flags = 0;
- /* If this is non-zero, it points to a chain of signals which need to
- be delivered to this process. */
- struct pending_signals *pending_signals;
+ /* A chain of signals that need to be delivered to this process. */
+ std::list<pending_signal> pending_signals;
/* A link used when resuming. It is initialized from the resume request,
and then processed and cleared in linux_resume_one_lwp. */
- struct thread_resume *resume;
+ struct thread_resume *resume = nullptr;
/* Information bout this lwp's fast tracepoint collection status (is it
currently stopped in the jump pad, and if so, before or at/after the
relocated instruction). Normally, we won't care about this, but we will
if a signal arrives to this lwp while it is collecting. */
- fast_tpoint_collect_result collecting_fast_tracepoint;
+ fast_tpoint_collect_result collecting_fast_tracepoint
+ = fast_tpoint_collect_result::not_collecting;
- /* If this is non-zero, it points to a chain of signals which need
- to be reported to GDB. These were deferred because the thread
- was doing a fast tracepoint collect when they arrived. */
- struct pending_signals *pending_signals_to_report;
+ /* A chain of signals that need to be reported to GDB. These were
+ deferred because the thread was doing a fast tracepoint collect
+ when they arrived. */
+ std::list<pending_signal> pending_signals_to_report;
/* When collecting_fast_tracepoint is first found to be 1, we insert
a exit-jump-pad-quickly breakpoint. This is it. */
- struct breakpoint *exit_jump_pad_bkpt;
+ struct breakpoint *exit_jump_pad_bkpt = nullptr;
#ifdef USE_THREAD_DB
- int thread_known;
+ int thread_known = 0;
/* The thread handle, used for e.g. TLS access. Only valid if
THREAD_KNOWN is set. */
- td_thrhandle_t th;
+ td_thrhandle_t th {};
/* The pthread_t handle. */
- thread_t thread_handle;
+ thread_t thread_handle {};
#endif
/* Arch-specific additions. */
- struct arch_lwp_info *arch_private;
+ struct arch_lwp_info *arch_private = nullptr;
};
int linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine);