+/* Private arch info associated with each thread lwp_info object, used
+ for debug register handling. */
+
+struct arch_lwp_info
+{
+ /* When true, indicates that the debug registers installed in the
+ thread no longer correspond to the watchpoints and breakpoints
+ requested by GDB. */
+ bool debug_regs_stale;
+
+ /* We need a back-reference to the PTID of the thread so that we can
+ cleanup the debug register state of the thread in
+ low_delete_thread. */
+ ptid_t lwp_ptid;
+};
+
+/* Class used to detect which set of ptrace requests that
+ ppc_linux_nat_target will use to install and remove hardware
+ breakpoints and watchpoints.
+
+ The interface is only detected once, testing the ptrace calls. The
+ result can indicate that no interface is available.
+
+ The Linux kernel provides two different sets of ptrace requests to
+ handle hardware watchpoints and breakpoints for Power:
+
+ - PPC_PTRACE_GETHWDBGINFO, PPC_PTRACE_SETHWDEBUG, and
+ PPC_PTRACE_DELHWDEBUG.
+
+ Or
+
+ - PTRACE_SET_DEBUGREG and PTRACE_GET_DEBUGREG
+
+ The first set is the more flexible one and allows setting watchpoints
+ with a variable watched region length and, for BookE processors,
+ multiple types of debug registers (e.g. hardware breakpoints and
+ hardware-assisted conditions for watchpoints). The second one only
+ allows setting one debug register, a watchpoint, so we only use it if
+ the first one is not available. */
+
+class ppc_linux_dreg_interface
+{
+public:
+
+ ppc_linux_dreg_interface ()
+ : m_interface (), m_hwdebug_info ()
+ {
+ };
+
+ DISABLE_COPY_AND_ASSIGN (ppc_linux_dreg_interface);
+
+ /* One and only one of these three functions returns true, indicating
+ whether the corresponding interface is the one we detected. The
+ interface must already have been detected as a precontidion. */
+
+ bool hwdebug_p ()
+ {
+ gdb_assert (detected_p ());
+ return *m_interface == HWDEBUG;
+ }
+
+ bool debugreg_p ()
+ {
+ gdb_assert (detected_p ());
+ return *m_interface == DEBUGREG;
+ }
+
+ bool unavailable_p ()
+ {
+ gdb_assert (detected_p ());
+ return *m_interface == UNAVAILABLE;
+ }
+
+ /* Returns the debug register capabilities of the target. Should only
+ be called if the interface is HWDEBUG. */
+ const struct ppc_debug_info &hwdebug_info ()
+ {
+ gdb_assert (hwdebug_p ());
+
+ return m_hwdebug_info;
+ }
+
+ /* Returns true if the interface has already been detected. This is
+ useful for cases when we know there is no work to be done if the
+ interface hasn't been detected yet. */
+ bool detected_p ()
+ {
+ return m_interface.has_value ();
+ }
+
+ /* Detect the available interface, if any, if it hasn't been detected
+ before, using PTID for the necessary ptrace calls. */
+
+ void detect (const ptid_t &ptid)
+ {
+ if (m_interface.has_value ())
+ return;
+
+ gdb_assert (ptid.lwp_p ());
+
+ bool no_features = false;
+
+ if (ptrace (PPC_PTRACE_GETHWDBGINFO, ptid.lwp (), 0, &m_hwdebug_info)
+ != -1)
+ {
+ /* If there are no advertised features, we don't use the
+ HWDEBUG interface and try the DEBUGREG interface instead.
+ It shouldn't be necessary to do this, however, when the
+ kernel is configured without CONFIG_HW_BREAKPOINTS (selected
+ by CONFIG_PERF_EVENTS), there is a bug that causes
+ watchpoints installed with the HWDEBUG interface not to
+ trigger. When this is the case, features will be zero,
+ which we use as an indicator to fall back to the DEBUGREG
+ interface. */
+ if (m_hwdebug_info.features != 0)
+ {
+ m_interface.emplace (HWDEBUG);
+ return;
+ }
+ else
+ no_features = true;
+ }
+
+ /* EIO indicates that the request is invalid, so we try DEBUGREG
+ next. Technically, it can also indicate other failures, but we
+ can't differentiate those.
+
+ Other errors could happen for various reasons. We could get an
+ ESRCH if the traced thread was killed by a signal. Trying to
+ detect the interface with another thread in the future would be
+ complicated, as callers would have to handle an "unknown
+ interface" case. It's also unclear if raising an exception
+ here would be safe.
+
+ Other errors, such as ENODEV, could be more permanent and cause
+ a failure for any thread.
+
+ For simplicity, with all errors other than EIO, we set the
+ interface to UNAVAILABLE and don't try DEBUGREG. If DEBUGREG
+ fails too, we'll also set the interface to UNAVAILABLE. It's
+ unlikely that trying the DEBUGREG interface with this same thread
+ would work, for errors other than EIO. This means that these
+ errors will cause hardware watchpoints and breakpoints to become
+ unavailable throughout a GDB session. */
+
+ if (no_features || errno == EIO)
+ {
+ unsigned long wp;
+
+ if (ptrace (PTRACE_GET_DEBUGREG, ptid.lwp (), 0, &wp) != -1)
+ {
+ m_interface.emplace (DEBUGREG);
+ return;
+ }
+ }
+
+ if (errno != EIO)
+ warning (_("Error when detecting the debug register interface. "
+ "Debug registers will be unavailable."));
+
+ m_interface.emplace (UNAVAILABLE);
+ return;
+ }
+
+private:
+
+ /* HWDEBUG represents the set of calls PPC_PTRACE_GETHWDBGINFO,
+ PPC_PTRACE_SETHWDEBUG and PPC_PTRACE_DELHWDEBUG.
+
+ DEBUGREG represents the set of calls PTRACE_SET_DEBUGREG and
+ PTRACE_GET_DEBUGREG.
+
+ UNAVAILABLE can indicate that the kernel doesn't support any of the
+ two sets of requests or that there was an error when we tried to
+ detect wich interface is available. */
+
+ enum debug_reg_interface
+ {
+ UNAVAILABLE,
+ HWDEBUG,
+ DEBUGREG
+ };
+
+ /* The interface option. Initialized if has_value () returns true. */
+ gdb::optional<enum debug_reg_interface> m_interface;
+
+ /* The info returned by the kernel with PPC_PTRACE_GETHWDBGINFO. Only
+ valid if we determined that the interface is HWDEBUG. */
+ struct ppc_debug_info m_hwdebug_info;
+};
+
+/* Per-process information. This includes the hardware watchpoints and
+ breakpoints that GDB requested to this target. */
+
+struct ppc_linux_process_info
+{
+ /* The list of hardware watchpoints and breakpoints that GDB requested
+ for this process.
+
+ Only used when the interface is HWDEBUG. */
+ std::list<struct ppc_hw_breakpoint> requested_hw_bps;
+
+ /* The watchpoint value that GDB requested for this process.
+
+ Only used when the interface is DEBUGREG. */
+ gdb::optional<long> requested_wp_val;
+};
+