Implement "info proc mappings" for NetBSD
authorKamil Rytarowski <n54@gmx.com>
Sun, 12 Apr 2020 00:00:14 +0000 (02:00 +0200)
committerKamil Rytarowski <n54@gmx.com>
Sun, 12 Apr 2020 11:06:08 +0000 (13:06 +0200)
Define nbsd_nat_target::find_memory_regions and
nbsd_nat_target::info_proc. info_proc handles as of now only
the "mappings" command.

Define a local static function kinfo_get_vmmap() that reads
the process memory layout of a specified process.
kinfo_get_vmmap() wraps the sysctl(3) call.

nbsd-tdep.c defines now utility functions for printing the
process memory layout:
 * nbsd_info_proc_mappings_header()
 * nbsd_vm_map_entry_flags()
 * nbsd_info_proc_mappings_entry()

gdb/ChangeLog:

* nbsd-nat.c; Include "nbsd-tdep.h" and "gdbarch.h".
* nbsd-nat.c (nbsd_nat_target::find_memory_regions)
(nbsd_nat_target::info_proc): New functions.
* nbsd-nat.c (kinfo_get_vmmap): New function.
* nbsd-nat.c (nbsd_nat_target::info_proc) Use
nbsd_info_proc_mappings_header and nbsd_info_proc_mappings_entry.
* nbsd-tdep.c (nbsd_info_proc_mappings_header)
(nbsd_info_proc_mappings_entry, nbsd_vm_map_entry_flags): New
functions.
* nbsd-tdep.c (KINFO_VME_PROT_READ, KINFO_VME_PROT_WRITE)
(KINFO_VME_PROT_EXEC, KINFO_VME_FLAG_COW)
(KINFO_VME_FLAG_NEEDS_COPY, KINFO_VME_FLAG_NOCOREDUMP)
(KINFO_VME_FLAG_PAGEABLE, KINFO_VME_FLAG_GROWS_UP)
(KINFO_VME_FLAG_GROWS_DOWN): New.

gdb/ChangeLog
gdb/nbsd-nat.c
gdb/nbsd-nat.h
gdb/nbsd-tdep.c
gdb/nbsd-tdep.h

index 81102ee569bcb841d38688b5ac0eb905ba043261..336bd497413046513227eb55c47d817e9a6d3a55 100644 (file)
@@ -1,3 +1,20 @@
+2020-04-11  Kamil Rytarowski  <n54@gmx.com>
+
+       * nbsd-nat.c; Include "nbsd-tdep.h" and "gdbarch.h".
+       * nbsd-nat.c (nbsd_nat_target::find_memory_regions)
+       (nbsd_nat_target::info_proc): New functions.
+       * nbsd-nat.c (kinfo_get_vmmap): New function.
+       * nbsd-nat.c (nbsd_nat_target::info_proc) Use
+       nbsd_info_proc_mappings_header and nbsd_info_proc_mappings_entry.
+       * nbsd-tdep.c (nbsd_info_proc_mappings_header)
+       (nbsd_info_proc_mappings_entry, nbsd_vm_map_entry_flags): New
+       functions.
+       * nbsd-tdep.c (KINFO_VME_PROT_READ, KINFO_VME_PROT_WRITE)
+       (KINFO_VME_PROT_EXEC, KINFO_VME_FLAG_COW)
+       (KINFO_VME_FLAG_NEEDS_COPY, KINFO_VME_FLAG_NOCOREDUMP)
+       (KINFO_VME_FLAG_PAGEABLE, KINFO_VME_FLAG_GROWS_UP)
+       (KINFO_VME_FLAG_GROWS_DOWN): New.
+
 2020-04-10  Artur Shepilko  <nomadbyte@gmail.com>
 
        * utils.c (copy_bitwise): Use unsigned 0 constant as operand of
index 4423e19428d3405e5f3c8ed537f1cde7e6c843d6..2420153c7bc5cfd8fbf9830d57c475ed13284ba2 100644 (file)
@@ -21,7 +21,9 @@
 
 #include "nbsd-nat.h"
 #include "gdbthread.h"
+#include "nbsd-tdep.h"
 #include "inferior.h"
+#include "gdbarch.h"
 
 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -199,3 +201,150 @@ nbsd_nat_target::pid_to_str (ptid_t ptid)
 
   return normal_pid_to_str (ptid);
 }
+
+/* Retrieve all the memory regions in the specified process.  */
+
+static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
+nbsd_kinfo_get_vmmap (pid_t pid, size_t *size)
+{
+  int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid,
+               sizeof (struct kinfo_vmentry)};
+
+  size_t length = 0;
+  if (sysctl (mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0))
+    {
+      *size = 0;
+      return NULL;
+    }
+
+  /* Prereserve more space.  The length argument is volatile and can change
+     between the sysctl(3) calls as this function can be called against a
+     running process.  */
+  length = length * 5 / 3;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
+    (XNEWVAR (kinfo_vmentry, length));
+
+  if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
+    {
+      *size = 0;
+      return NULL;
+    }
+
+  *size = length / sizeof (struct kinfo_vmentry);
+  return kiv;
+}
+
+/* Iterate over all the memory regions in the current inferior,
+   calling FUNC for each memory region.  OBFD is passed as the last
+   argument to FUNC.  */
+
+int
+nbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
+                                     void *data)
+{
+  pid_t pid = inferior_ptid.pid ();
+
+  size_t nitems;
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
+    = nbsd_kinfo_get_vmmap (pid, &nitems);
+  if (vmentl == NULL)
+    perror_with_name (_("Couldn't fetch VM map entries."));
+
+  for (size_t i = 0; i < nitems; i++)
+    {
+      struct kinfo_vmentry *kve = &vmentl[i];
+
+      /* Skip unreadable segments and those where MAP_NOCORE has been set.  */
+      if (!(kve->kve_protection & KVME_PROT_READ)
+         || kve->kve_flags & KVME_FLAG_NOCOREDUMP)
+       continue;
+
+      /* Skip segments with an invalid type.  */
+      switch (kve->kve_type)
+       {
+       case KVME_TYPE_VNODE:
+       case KVME_TYPE_ANON:
+       case KVME_TYPE_SUBMAP:
+       case KVME_TYPE_OBJECT:
+         break;
+       default:
+         continue;
+       }
+
+      size_t size = kve->kve_end - kve->kve_start;
+      if (info_verbose)
+       {
+         fprintf_filtered (gdb_stdout,
+                           "Save segment, %ld bytes at %s (%c%c%c)\n",
+                           (long) size,
+                           paddress (target_gdbarch (), kve->kve_start),
+                           kve->kve_protection & KVME_PROT_READ ? 'r' : '-',
+                           kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-',
+                           kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-');
+       }
+
+      /* Invoke the callback function to create the corefile segment.
+        Pass MODIFIED as true, we do not know the real modification state.  */
+      func (kve->kve_start, size, kve->kve_protection & KVME_PROT_READ,
+           kve->kve_protection & KVME_PROT_WRITE,
+           kve->kve_protection & KVME_PROT_EXEC, 1, data);
+    }
+  return 0;
+}
+
+/* Implement the "info_proc" target_ops method.  */
+
+bool
+nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
+{
+  pid_t pid;
+  bool do_mappings = false;
+
+  switch (what)
+    {
+    case IP_MAPPINGS:
+      do_mappings = true;
+      break;
+    default:
+      error (_("Not supported on this target."));
+    }
+
+  gdb_argv built_argv (args);
+  if (built_argv.count () == 0)
+    {
+      pid = inferior_ptid.pid ();
+      if (pid == 0)
+        error (_("No current process: you must name one."));
+    }
+  else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
+    pid = strtol (built_argv[0], NULL, 10);
+  else
+    error (_("Invalid arguments."));
+
+  printf_filtered (_("process %d\n"), pid);
+
+  if (do_mappings)
+    {
+      size_t nvment;
+      gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
+       = nbsd_kinfo_get_vmmap (pid, &nvment);
+
+      if (vmentl != nullptr)
+       {
+         int addr_bit = TARGET_CHAR_BIT * sizeof (void *);
+         nbsd_info_proc_mappings_header (addr_bit);
+
+         struct kinfo_vmentry *kve = vmentl.get ();
+         for (int i = 0; i < nvment; i++, kve++)
+           nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start,
+                                          kve->kve_end, kve->kve_offset,
+                                          kve->kve_flags, kve->kve_protection,
+                                          kve->kve_path);
+       }
+      else
+       warning (_("unable to fetch virtual memory map"));
+    }
+
+  return true;
+}
index 3606048cd07041d635e874ac36b055cdcd3398e1..256db4b9017fb78d2265bcfc61969e72cafb4a33 100644 (file)
@@ -35,6 +35,9 @@ struct nbsd_nat_target : public inf_ptrace_target
   void post_attach (int pid) override;
   void update_thread_list () override;
   std::string pid_to_str (ptid_t ptid) override;
+
+  int find_memory_regions (find_memory_region_ftype func, void *data) override;
+  bool info_proc (const char *, enum info_proc_what) override;
 };
 
 #endif /* nbsd-nat.h */
index 158a43bebaa1e2ccc48bc7e4313ee81551500e2a..52e0640e35cad506e1eb31d075d97206b8bbc3eb 100644 (file)
 #include "gdbarch.h"
 #include "objfiles.h"
 
+/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
+   match the KVME_PROT_* constants in <sys/sysctl.h>.  */
+
+#define        KINFO_VME_PROT_READ     0x00000001
+#define        KINFO_VME_PROT_WRITE    0x00000002
+#define        KINFO_VME_PROT_EXEC     0x00000004
+
+/* Flags in the 'kve_flags' field in struct kinfo_vmentry.  These
+   match the KVME_FLAG_* constants in <sys/sysctl.h>.  */
+
+#define        KINFO_VME_FLAG_COW              0x00000001
+#define        KINFO_VME_FLAG_NEEDS_COPY       0x00000002
+#define        KINFO_VME_FLAG_NOCOREDUMP       0x00000004
+#define        KINFO_VME_FLAG_PAGEABLE         0x00000008
+#define        KINFO_VME_FLAG_GROWS_UP         0x00000010
+#define        KINFO_VME_FLAG_GROWS_DOWN       0x00000020
+
 /* FIXME: kettenis/20060115: We should really eliminate the next two
    functions completely.  */
 
@@ -357,6 +374,78 @@ nbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
 
 /* See nbsd-tdep.h.  */
 
+void
+nbsd_info_proc_mappings_header (int addr_bit)
+{
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (addr_bit == 64)
+    {
+      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
+                      "Start Addr",
+                      "  End Addr",
+                      "      Size", "    Offset", "Flags  ", "File");
+    }
+  else
+    {
+      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
+                      "Start Addr",
+                      "  End Addr",
+                      "      Size", "    Offset", "Flags  ", "File");
+    }
+}
+
+/* Helper function to generate mappings flags for a single VM map
+   entry in 'info proc mappings'.  */
+
+static const char *
+nbsd_vm_map_entry_flags (int kve_flags, int kve_protection)
+{
+  static char vm_flags[9];
+
+  vm_flags[0] = (kve_protection & KINFO_VME_PROT_READ) ? 'r' : '-';
+  vm_flags[1] = (kve_protection & KINFO_VME_PROT_WRITE) ? 'w' : '-';
+  vm_flags[2] = (kve_protection & KINFO_VME_PROT_EXEC) ? 'x' : '-';
+  vm_flags[3] = ' ';
+  vm_flags[4] = (kve_flags & KINFO_VME_FLAG_COW) ? 'C' : '-';
+  vm_flags[5] = (kve_flags & KINFO_VME_FLAG_NEEDS_COPY) ? 'N' : '-';
+  vm_flags[6] = (kve_flags & KINFO_VME_FLAG_PAGEABLE) ? 'P' : '-';
+  vm_flags[7] = (kve_flags & KINFO_VME_FLAG_GROWS_UP) ? 'U'
+    : (kve_flags & KINFO_VME_FLAG_GROWS_DOWN) ? 'D' : '-';
+  vm_flags[8] = '\0';
+
+  return vm_flags;
+}
+
+void
+nbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start,
+                              ULONGEST kve_end, ULONGEST kve_offset,
+                              int kve_flags, int kve_protection,
+                              const char *kve_path)
+{
+  if (addr_bit == 64)
+    {
+      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
+                      hex_string (kve_start),
+                      hex_string (kve_end),
+                      hex_string (kve_end - kve_start),
+                      hex_string (kve_offset),
+                      nbsd_vm_map_entry_flags (kve_flags, kve_protection),
+                      kve_path);
+    }
+  else
+    {
+      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
+                      hex_string (kve_start),
+                      hex_string (kve_end),
+                      hex_string (kve_end - kve_start),
+                      hex_string (kve_offset),
+                      nbsd_vm_map_entry_flags (kve_flags, kve_protection),
+                      kve_path);
+    }
+}
+
+/* See nbsd-tdep.h.  */
+
 void
 nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
index 4b06c13f87bb18b72bcead3add6b63d761673acd..a6e3a8f0f3f182d78829f0e56fc3556f384d19ce 100644 (file)
@@ -29,4 +29,22 @@ int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
 
 void nbsd_init_abi (struct gdbarch_info, struct gdbarch *);
 
+/* Output the header for "info proc mappings".  ADDR_BIT is the size
+   of a virtual address in bits.  */
+
+extern void nbsd_info_proc_mappings_header (int addr_bit);
+
+/* Output description of a single memory range for "info proc
+   mappings".  ADDR_BIT is the size of a virtual address in bits.  The
+   KVE_START, KVE_END, KVE_OFFSET, KVE_FLAGS, and KVE_PROTECTION
+   parameters should contain the value of the corresponding fields in
+   a 'struct kinfo_vmentry'.  The KVE_PATH parameter should contain a
+   pointer to the 'kve_path' field in a 'struct kinfo_vmentry'. */
+
+extern void nbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start,
+                                          ULONGEST kve_end,
+                                          ULONGEST kve_offset,
+                                          int kve_flags, int kve_protection,
+                                          const char *kve_path);
+
 #endif /* NBSD_TDEP_H */