]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gdbserver/linux-low.c
gdbserver: Add linux_get_hwcap
[thirdparty/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index dfa7fbaa494d84d7548acb6f6dc3a2a24581e999..7158a6798c91f42670a232343b252d5f835da999 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to ptrace, for the remote server for GDB.
-   Copyright (C) 1995-2018 Free Software Foundation, Inc.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "server.h"
 #include "linux-low.h"
 #include "nat/linux-osdata.h"
-#include "agent.h"
+#include "common/agent.h"
 #include "tdesc.h"
-#include "rsp-low.h"
-#include "signals-state-save-restore.h"
+#include "common/rsp-low.h"
+#include "common/signals-state-save-restore.h"
 #include "nat/linux-nat.h"
 #include "nat/linux-waitpid.h"
-#include "gdb_wait.h"
+#include "common/gdb_wait.h"
 #include "nat/gdb_ptrace.h"
 #include "nat/linux-ptrace.h"
 #include "nat/linux-procfs.h"
 #include <sys/stat.h>
 #include <sys/vfs.h>
 #include <sys/uio.h>
-#include "filestuff.h"
+#include "common/filestuff.h"
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
-#include "common-inferior.h"
+#include "common/common-inferior.h"
 #include "nat/fork-inferior.h"
-#include "environ.h"
+#include "common/environ.h"
 #include "common/scoped_restore.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
 
 #ifdef HAVE_LINUX_BTRACE
 # include "nat/linux-btrace.h"
-# include "btrace-common.h"
+# include "common/btrace-common.h"
 #endif
 
 #ifndef HAVE_ELF32_AUXV_T
@@ -951,11 +951,11 @@ add_lwp (ptid_t ptid)
 
   lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
 
+  lwp->thread = add_thread (ptid, lwp);
+
   if (the_low_target.new_thread != NULL)
     the_low_target.new_thread (lwp);
 
-  lwp->thread = add_thread (ptid, lwp);
-
   return lwp;
 }
 
@@ -1188,18 +1188,19 @@ linux_attach (unsigned long pid)
   ptid_t ptid = ptid_t (pid, pid, 0);
   int err;
 
+  proc = linux_add_process (pid, 1);
+
   /* Attach to PID.  We will check for other threads
      soon.  */
   err = linux_attach_lwp (ptid);
   if (err != 0)
     {
-      std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err);
+      remove_process (proc);
 
+      std::string reason = linux_ptrace_attach_fail_reason_string (ptid, err);
       error ("Cannot attach to process %ld: %s", pid, reason.c_str ());
     }
 
-  proc = linux_add_process (pid, 1);
-
   /* Don't ignore the initial SIGSTOP if we just attached to this
      process.  It will be collected by wait shortly.  */
   initial_thread = find_thread_ptid (ptid_t (pid, pid, 0));
@@ -1255,7 +1256,7 @@ last_thread_of_process_p (int pid)
 {
   bool seen_one = false;
 
-  thread_info *thread = find_thread (pid, [&] (thread_info *thread)
+  thread_info *thread = find_thread (pid, [&] (thread_info *thr_arg)
     {
       if (!seen_one)
        {
@@ -1385,14 +1386,9 @@ kill_one_lwp_callback (thread_info *thread, int pid)
 }
 
 static int
-linux_kill (int pid)
+linux_kill (process_info *process)
 {
-  struct process_info *process;
-  struct lwp_info *lwp;
-
-  process = find_process_pid (pid);
-  if (process == NULL)
-    return -1;
+  int pid = process->pid;
 
   /* If we're killing a running inferior, make sure it is stopped
      first, as PTRACE_KILL will not work otherwise.  */
@@ -1405,7 +1401,7 @@ linux_kill (int pid)
 
   /* See the comment in linux_kill_one_lwp.  We did not kill the first
      thread in the list, so do so now.  */
-  lwp = find_lwp_pid (ptid_t (pid));
+  lwp_info *lwp = find_lwp_pid (ptid_t (pid));
 
   if (lwp == NULL)
     {
@@ -1675,12 +1671,12 @@ linux_mourn (struct process_info *process)
 }
 
 static void
-linux_join (process_info *proc)
+linux_join (int pid)
 {
   int status, ret;
 
   do {
-    ret = my_waitpid (proc->pid, &status, 0);
+    ret = my_waitpid (pid, &status, 0);
     if (WIFEXITED (status) || WIFSIGNALED (status))
       break;
   } while (ret != -1 || errno != ECHILD);
@@ -1816,10 +1812,10 @@ status_pending_p_callback (thread_info *thread, ptid_t ptid)
 struct lwp_info *
 find_lwp_pid (ptid_t ptid)
 {
-  thread_info *thread = find_thread ([&] (thread_info *thread)
+  thread_info *thread = find_thread ([&] (thread_info *thr_arg)
     {
       int lwp = ptid.lwp () != 0 ? ptid.lwp () : ptid.pid ();
-      return thread->id.lwp () == lwp;
+      return thr_arg->id.lwp () == lwp;
     });
 
   if (thread == NULL)
@@ -1847,14 +1843,13 @@ num_lwps (int pid)
 
 struct lwp_info *
 iterate_over_lwps (ptid_t filter,
-                  iterate_over_lwps_ftype callback,
-                  void *data)
+                  gdb::function_view<iterate_over_lwps_ftype> callback)
 {
-  thread_info *thread = find_thread (filter, [&] (thread_info *thread)
+  thread_info *thread = find_thread (filter, [&] (thread_info *thr_arg)
     {
-      lwp_info *lwp = get_thread_lwp (thread);
+      lwp_info *lwp = get_thread_lwp (thr_arg);
 
-      return callback (lwp, data);
+      return callback (lwp);
     });
 
   if (thread == NULL)
@@ -5363,10 +5358,11 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
 #endif
       if (res < 0)
        {
-         if (errno == EIO)
+         if (errno == EIO
+             || (errno == EINVAL && regset->type == OPTIONAL_REGS))
            {
-             /* If we get EIO on a regset, do not try it again for
-                this process mode.  */
+             /* If we get EIO on a regset, or an EINVAL and the regset is
+                optional, do not try it again for this process mode.  */
              disable_regset (regsets_info, regset);
            }
          else if (errno == ENODATA)
@@ -5461,10 +5457,11 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
 
       if (res < 0)
        {
-         if (errno == EIO)
+         if (errno == EIO
+             || (errno == EINVAL && regset->type == OPTIONAL_REGS))
            {
-             /* If we get EIO on a regset, do not try it again for
-                this process mode.  */
+             /* If we get EIO on a regset, or an EINVAL and the regset is
+                optional, do not try it again for this process mode.  */
              disable_regset (regsets_info, regset);
            }
          else if (errno == ESRCH)
@@ -7037,16 +7034,16 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
     {
       const char *sep;
       CORE_ADDR *addrp;
-      int len;
+      int name_len;
 
       sep = strchr (annex, '=');
       if (sep == NULL)
        break;
 
-      len = sep - annex;
-      if (len == 5 && startswith (annex, "start"))
+      name_len = sep - annex;
+      if (name_len == 5 && startswith (annex, "start"))
        addrp = &lm_addr;
-      else if (len == 4 && startswith (annex, "prev"))
+      else if (name_len == 4 && startswith (annex, "prev"))
        addrp = &lm_prev;
       else
        {
@@ -7426,6 +7423,53 @@ linux_get_pc_64bit (struct regcache *regcache)
   return pc;
 }
 
+/* Fetch the entry MATCH from the auxv vector, where entries are length
+   WORDSIZE.  If no entry was found, return zero.  */
+
+static CORE_ADDR
+linux_get_auxv (int wordsize, CORE_ADDR match)
+{
+  gdb_byte *data = (gdb_byte *) alloca (2 * wordsize);
+  int offset = 0;
+
+  gdb_assert (wordsize == 4 || wordsize == 8);
+
+  while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
+    {
+      if (wordsize == 4)
+       {
+         uint32_t *data_p = (uint32_t *)data;
+         if (data_p[0] == match)
+           return data_p[1];
+       }
+      else
+       {
+         uint64_t *data_p = (uint64_t *)data;
+         if (data_p[0] == match)
+           return data_p[1];
+       }
+
+      offset += 2 * wordsize;
+    }
+
+  return 0;
+}
+
+/* See linux-low.h.  */
+
+CORE_ADDR
+linux_get_hwcap (int wordsize)
+{
+  return linux_get_auxv (wordsize, AT_HWCAP);
+}
+
+/* See linux-low.h.  */
+
+CORE_ADDR
+linux_get_hwcap2 (int wordsize)
+{
+  return linux_get_auxv (wordsize, AT_HWCAP2);
+}
 
 static struct target_ops linux_target_ops = {
   linux_create_inferior,