[PATCH] Implement IP_STAT on NetBSD

Kamil Rytarowski n54@gmx.com
Mon Apr 13 18:19:11 GMT 2020


NetBSD ships with a compatibility layer in a /proc virtual file system
and delivers optionally /proc/<pid>/stat. In case of missing
/proc/<pid>/stat fallback to emulating it with sysctl(3) APIs.

gdb/ChangeLog:

        * nbsd-nat.c: Include "sys/resource.h" and "machine/vmparam.h".
        (nbsd_pid_to_kinfo_proc2, nbsd_pid_to_rlimit_cur)
        (nbsd_pid_to_statstr): New.
        (nbsd_nat_target::info_proc): Add do_stat.
---
 gdb/ChangeLog  |   7 ++
 gdb/nbsd-nat.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 285 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7d91abf6334..5ff76e85cb3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2020-04-13  Kamil Rytarowski  <n54@gmx.com>
+
+	* nbsd-nat.c: Include "sys/resource.h" and "machine/vmparam.h".
+	(nbsd_pid_to_kinfo_proc2, nbsd_pid_to_rlimit_cur)
+	(nbsd_pid_to_statstr): New.
+	(nbsd_nat_target::info_proc): Add do_stat.
+
 2020-04-12  Kamil Rytarowski  <n54@gmx.com>

 	* nbsd-nat.c (nbsd_nat_target::info_proc): Add IP_MINIMAL and
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 5eaf9dec8af..b2a05d63122 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -28,6 +28,8 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <machine/vmparam.h>

 /* Return the name of a file that can be opened to get the symbols for
    the child process identified by PID.  */
@@ -58,6 +60,134 @@ nbsd_pid_to_cwd (int pid)
   return buf;
 }

+/* Return the kinfo_proc2 structure for the process identified by PID.  */
+
+static bool
+nbsd_pid_to_kinfo_proc2(pid_t pid, struct kinfo_proc2 *ki)
+{
+  gdb_assert (ki != nullptr);
+
+  size_t size = sizeof (*ki);
+  int mib[6] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid,
+		static_cast<int> (size), 1};
+  return sysctl (mib, ARRAY_SIZE (mib), ki, &size, NULL, 0);
+}
+
+/* Return the RLIMIT value for the process identified by PID.  */
+
+static bool
+nbsd_pid_to_rlimit_cur(pid_t pid, rlim_t *rlim, int type)
+{
+  gdb_assert (rlim != nullptr);
+
+  size_t size = sizeof (*rlim);
+  int mib[5] = {CTL_PROC, pid, PROC_PID_LIMIT, type, PROC_PID_LIMIT_TYPE_SOFT};
+  return sysctl (mib, ARRAY_SIZE (mib), rlim, &size, NULL, 0);
+}
+
+/* Return the emulated /proc/#/stat string for the process identified by PID.
+   NetBSD keeps the /proc filesystem that is optional and not recommended for
+   new software, thus this call emulates it with sysctl(3).  */
+
+static gdb::unique_xmalloc_ptr<char>
+nbsd_pid_to_statstr (int pid)
+{
+  struct kinfo_proc2 ki;
+  if (nbsd_pid_to_kinfo_proc2 (pid, &ki))
+    return nullptr;
+
+  struct rusage cru = {};
+  /* We can check only the current process.  */
+  if (getpid() == pid)
+    getrusage (RUSAGE_SELF, &cru);
+
+  rlim_t rsslim_cur;
+  if (nbsd_pid_to_rlimit_cur (pid, &rsslim_cur, PROC_PID_LIMIT_RSS))
+    return nullptr;
+
+  auto print_p_stat
+    = [] (int8_t state)
+      {
+	return "0RRSTZXR8"[(state > 8) ? 0 : state];
+      };
+
+  auto print_p_tdev
+    = [] (uint32_t dev)
+      {
+	return (dev != static_cast<uint32_t> (NODEV)) ? dev : 0;
+      };
+
+  auto print_utime2ticks
+    = [] (uint32_t sec, uint32_t usec)
+      {
+	return (static_cast<uint64_t> (sec) * 1000000 + (usec)) / 10000;
+      };
+
+  auto print_pgtokb
+    = [] (int32_t rsssize)
+      {
+	return static_cast<unsigned long int> (rsssize) << (PAGE_SHIFT - 10);
+      };
+
+  std::string statstr
+    = string_printf("%d (%s) %c %d %d %d %u %d "
+		    "%u "
+		    "%" PRIu64 " %lu %" PRIu64 " %lu %" PRIu64 " %" PRIu64 " "
+		    "%" PRIu64 " %" PRIu64 " "
+		    "%d %d %" PRIu64 " "
+		    "%lld %" PRIu64 " %" PRId64 " %lu %" PRIu64 " "
+		    "%lu %lu %lu "
+		    "%u %u "
+		    "%u %u %u %u "
+		    "%" PRIu64 " %" PRIu64 " %" PRIu64 " %d %" PRIu64 "\n",
+		    ki.p_pid,                               /* 1 pid */
+		    ki.p_comm,                              /* 2 tcomm */
+		    print_p_stat(ki.p_stat),                /* 3 state */
+		    ki.p_ppid,                              /* 4 ppid */
+		    ki.p__pgid,                             /* 5 pgrp */
+		    ki.p_sid,                               /* 6 sid */
+		    print_p_tdev(ki.p_tdev),                /* 7 tty_nr */
+		    ki.p_tpgid,                             /* 8 tty_pgrp */
+		    ki.p_flag,                              /* 9 flags */
+		    ki.p_uru_minflt,                        /* 10 min_flt */
+		    cru.ru_minflt,
+		    ki.p_uru_majflt,                        /* 12 maj_flt */
+		    cru.ru_majflt,
+		    print_utime2ticks(ki.p_uutime_sec,
+				      ki.p_uutime_usec),    /* 14 utime */
+		    print_utime2ticks(ki.p_ustime_sec,
+				      ki.p_ustime_usec),    /* 15 stime */
+		    print_utime2ticks(cru.ru_utime.tv_sec,
+				      cru.ru_utime.tv_usec),/* 16 cutime */
+		    print_utime2ticks(cru.ru_stime.tv_sec,
+				      cru.ru_stime.tv_usec),/* 17 cstime */
+		    ki.p_priority,                          /* 18 priority */
+		    ki.p_nice - NZERO,                      /* 19 nice */
+		    ki.p_nlwps,                             /* 20 num_threads */
+		    static_cast<long long int> (ki.p_rtime_sec),
+		    print_utime2ticks(ki.p_ustart_sec,
+				      ki.p_ustart_usec),    /* 22 start_time */
+		    ki.p_vm_msize,                          /* 23 vsize */
+		    print_pgtokb(ki.p_vm_rssize),           /* 24 rss */
+		    rsslim_cur,                             /* 25 rsslim */
+		    0L,                                     /* 26 start_code */
+		    0L,                                     /* 27 end_code */
+		    0L,                                     /* 28 start_stack */
+		    0,                                      /* 29 esp */
+		    0,                                      /* 30 eip */
+		    ki.p_siglist.__bits[0],                 /* 31 pending */
+		    0,                                      /* 32 blocked */
+		    ki.p_sigignore.__bits[0],               /* 33 sigign */
+		    ki.p_sigcatch.__bits[0],                /* 34 sigcatch */
+		    ki.p_wchan,                             /* 35 wchan */
+		    ki.p_uru_nvcsw,
+		    ki.p_uru_nivcsw,
+		    ki.p_exitsig,                           /* 38 exit_signal */
+		    ki.p_cpuid);                            /* 39 task_cpu */
+
+  return gdb::unique_xmalloc_ptr<char> (xstrprintf ("%s", statstr.c_str ()));
+}
+
 /* Return the command line for the process identified by PID.  */

 static gdb::unique_xmalloc_ptr<char[]>
@@ -344,6 +474,7 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
   bool do_cwd = false;
   bool do_exe = false;
   bool do_mappings = false;
+  bool do_stat = false;

   switch (what)
     {
@@ -352,6 +483,9 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
       do_cwd = true;
       do_exe = true;
       break;
+    case IP_STAT:
+      do_stat = true;
+      break;
     case IP_MAPPINGS:
       do_mappings = true;
       break;
@@ -369,6 +503,7 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
       do_cwd = true;
       do_exe = true;
       do_mappings = true;
+      do_stat = true;
       break;
     default:
       error (_("Not supported on this target."));
@@ -433,6 +568,149 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
       else
 	warning (_("unable to fetch virtual memory map"));
     }
+  if (do_stat)
+    {
+      /* First, try with Linux-compat /proc/<pid>/stat. */
+      char filename[100];
+      xsnprintf (filename, sizeof filename, "/proc/%d/stat", pid);
+      gdb::unique_xmalloc_ptr<char> statstr
+	= target_fileio_read_stralloc (NULL, filename);
+
+      /* Then fallback to emulating /proc/<pid>/stat with sysctl(3).  */
+      if (statstr == nullptr)
+	statstr = nbsd_pid_to_statstr (pid);
+
+      if (statstr)
+	{
+	  const char *p = statstr.get ();
+
+	  printf_filtered (_("Process: %s\n"),
+			   pulongest (strtoulst (p, &p, 10)));
+
+	  p = skip_spaces (p);
+	  if (*p == '(')
+	    {
+	      /* ps command also relies on no trailing fields
+		 ever contain ')'.  */
+	      const char *ep = strrchr (p, ')');
+	      if (ep != NULL)
+		{
+		  printf_filtered ("Exec file: %.*s\n",
+				   (int) (ep - p - 1), p + 1);
+		  p = ep + 1;
+		}
+	    }
+
+	  p = skip_spaces (p);
+	  if (*p)
+	    printf_filtered (_("State: %c\n"), *p++);
+
+	  if (*p)
+	    printf_filtered (_("Parent process: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Process group: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Session id: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("TTY: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("TTY owner process group: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+
+	  if (*p)
+	    printf_filtered (_("Flags: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Minor faults (no memory page): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Minor faults, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Major faults (memory page faults): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Major faults, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("utime: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("stime: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("utime, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("stime, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies remaining in current "
+			       "time slice: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("'nice' value: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies until next timeout: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies until next SIGALRM: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("start time (jiffies since "
+			       "system boot): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Virtual memory size: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Resident set size: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("rlim: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Start of text: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("End of text: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Start of stack: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+#if 0	/* Don't know how architecture-dependent the rest is...
+	   Anyway the signal bitmap info is available from "status".  */
+	  if (*p)
+	    printf_filtered (_("Kernel stack pointer: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Kernel instr pointer: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Pending signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Blocked signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Ignored signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Catched signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("wchan (system call): %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+#endif
+	}
+      else
+	warning (_("unable to open /proc file '%s'"), filename);
+    }

   return true;
 }
--
2.25.0



More information about the Gdb-patches mailing list