[PATCH] Implement "info proc mappings" for NetBSD

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PATCH] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
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()

This code is based on the FreeBSD implementation.

gdb/ChangeLog:

        * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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   |  17 ++++++
 gdb/nbsd-nat.c  | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 277 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a0d97584189..b690222068a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-03-16  Kamil Rytarowski  <[hidden email]>
+
+ * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-14  Tom Tromey  <[hidden email]>

  * c-typeprint.c (cp_type_print_method_args): Print "__restrict__"
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index e7f91bebb0d..3cafd24b1dc 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 /* Return the name of a file that can be opened to get the symbols for
    the child process identified by PID.  */
@@ -41,3 +44,149 @@ nbsd_nat_target::pid_to_exec_file (int pid)

   return NULL;
 }
+
+/* Retrieve all the memory regions in the specified process.  */
+
+static struct kinfo_vmentry *
+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. */
+  length = length * 5 / 3;
+
+  struct kinfo_vmentry *kiv = (struct kinfo_vmentry *) calloc(length, 1);
+  if (kiv == NULL) {
+    *size = 0;
+    return NULL;
+  }
+
+  if (sysctl(mib, ARRAY_SIZE (mib), kiv, &length, NULL, 0)) {
+    *size = 0;
+    free(kiv);
+    return NULL;
+  }
+
+  *size = length / sizeof(*kiv);
+  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 *obfd)
+{
+  pid_t pid = inferior_ptid.pid ();
+  struct kinfo_vmentry *kve;
+  uint64_t size;
+  int i;
+  size_t nitems;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
+    vmentl (kinfo_get_vmmap (pid, &nitems));
+  if (vmentl == NULL)
+    perror_with_name (_("Couldn't fetch VM map entries."));
+
+  for (i = 0, kve = vmentl.get (); i < nitems; i++, kve++)
+    {
+      /* 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 = 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, obfd);
+    }
+  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 (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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 49bb2b706bd..23732854172 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@
 #include "solib-svr4.h"
 #include "nbsd-tdep.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.  */

@@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
   && startswith (func_name, "__sigtramp"));
 }
+
+/* See fbsd-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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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 void *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),
+       reinterpret_cast<const char *> (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),
+       reinterpret_cast<const char *> (kve_path));
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..81bdb2510f5 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 void *kve_path);
+
 #endif /* NBSD_TDEP_H */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
Ping?

I depend on this patch with more feature in "info proc" and

This one is mostly resuing prior art from the FreeBSD code.

On 16.03.2020 18:34, Kamil Rytarowski wrote:

> 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()
>
> This code is based on the FreeBSD implementation.
>
> gdb/ChangeLog:
>
> * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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   |  17 ++++++
>  gdb/nbsd-nat.c  | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/nbsd-nat.h  |   2 +
>  gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
>  gdb/nbsd-tdep.h |  18 ++++++
>  5 files changed, 277 insertions(+)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index a0d97584189..b690222068a 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,20 @@
> +2020-03-16  Kamil Rytarowski  <[hidden email]>
> +
> + * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-14  Tom Tromey  <[hidden email]>
>
>   * c-typeprint.c (cp_type_print_method_args): Print "__restrict__"
> diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
> index e7f91bebb0d..3cafd24b1dc 100644
> --- a/gdb/nbsd-nat.c
> +++ b/gdb/nbsd-nat.c
> @@ -20,6 +20,9 @@
>  #include "defs.h"
>
>  #include "nbsd-nat.h"
> +#include "nbsd-tdep.h"
> +#include "inferior.h"
> +#include "gdbarch.h"
>
>  /* Return the name of a file that can be opened to get the symbols for
>     the child process identified by PID.  */
> @@ -41,3 +44,149 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>
>    return NULL;
>  }
> +
> +/* Retrieve all the memory regions in the specified process.  */
> +
> +static struct kinfo_vmentry *
> +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. */
> +  length = length * 5 / 3;
> +
> +  struct kinfo_vmentry *kiv = (struct kinfo_vmentry *) calloc(length, 1);
> +  if (kiv == NULL) {
> +    *size = 0;
> +    return NULL;
> +  }
> +
> +  if (sysctl(mib, ARRAY_SIZE (mib), kiv, &length, NULL, 0)) {
> +    *size = 0;
> +    free(kiv);
> +    return NULL;
> +  }
> +
> +  *size = length / sizeof(*kiv);
> +  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 *obfd)
> +{
> +  pid_t pid = inferior_ptid.pid ();
> +  struct kinfo_vmentry *kve;
> +  uint64_t size;
> +  int i;
> +  size_t nitems;
> +
> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
> +    vmentl (kinfo_get_vmmap (pid, &nitems));
> +  if (vmentl == NULL)
> +    perror_with_name (_("Couldn't fetch VM map entries."));
> +
> +  for (i = 0, kve = vmentl.get (); i < nitems; i++, kve++)
> +    {
> +      /* 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 = 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, obfd);
> +    }
> +  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 (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;
> +}
> diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
> index a752fbe572d..98af21d0bda 100644
> --- a/gdb/nbsd-nat.h
> +++ b/gdb/nbsd-nat.h
> @@ -27,6 +27,8 @@
>  struct nbsd_nat_target : public inf_ptrace_target
>  {
>    char *pid_to_exec_file (int pid) 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 */
> diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
> index 49bb2b706bd..23732854172 100644
> --- a/gdb/nbsd-tdep.c
> +++ b/gdb/nbsd-tdep.c
> @@ -23,6 +23,23 @@
>  #include "solib-svr4.h"
>  #include "nbsd-tdep.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.  */
>
> @@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
>    return (func_name != NULL
>    && startswith (func_name, "__sigtramp"));
>  }
> +
> +/* See fbsd-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;
> +}
> +
> +/* See nbsd-tdep.h.  */
> +
> +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 void *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),
> +       reinterpret_cast<const char *> (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),
> +       reinterpret_cast<const char *> (kve_path));
> +    }
> +}
> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
> index c99a8b537b6..81bdb2510f5 100644
> --- a/gdb/nbsd-tdep.h
> +++ b/gdb/nbsd-tdep.h
> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
>
>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
>
> +/* 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 void *kve_path);
> +
>  #endif /* NBSD_TDEP_H */
> --
> 2.25.0
>


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Tom Tromey-2
In reply to this post by Kamil Rytarowski
>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:

Kamil> Define nbsd_nat_target::find_memory_regions and
Kamil> nbsd_nat_target::info_proc. info_proc handles as of now only
Kamil> the "mappings" command.

Thank you for the patch.

Kamil> +/* Retrieve all the memory regions in the specified process.  */
Kamil> +
Kamil> +static struct kinfo_vmentry *
Kamil> +kinfo_get_vmmap(pid_t pid, size_t *size)

Space before paren.
There are multiple instances of this in the patch.

Kamil> +{
Kamil> +  int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid, sizeof(struct kinfo_vmentry)};
Kamil> +
Kamil> +  size_t length = 0;
Kamil> +  if (sysctl(mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0)) {

GNU style is to put the open brace on its own line.
There are several cases of this as well.

Kamil> +  if (sysctl(mib, ARRAY_SIZE (mib), kiv, &length, NULL, 0)) {
Kamil> +    *size = 0;
Kamil> +    free(kiv);

xfree, though these days in gdb it's better to create and return a
self-managing object, like gdb::unique_xmalloc_ptr<>.

Kamil> +
Kamil> +int
Kamil> +nbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
Kamil> +      void *obfd)

I wouldn't name that parameter "obfd" but rather "data" or "user_data"
or something like that.  The name "obfd" in gdb normally implies that it
is a "BFD *", but this is just opaque data that's shared by the caller
and the callback.

Kamil> diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
[...]
Kamil> +/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
Kamil> +   match the KVME_PROT_* constants in <sys/sysctl.h>.  */

What if they stop matching?

I wonder if this code really ought to be in the tdep file.  I suppose
so, if it will be used somehow when cross debugging... but will that
happen?

If not then maybe putting it in the -nat file is better; and then the
appropriate NetBSD headers could be used.

Kamil> +  printf_filtered (_("Mapped address spaces:\n\n"));
Kamil> +  if (addr_bit == 64)
Kamil> +    {
Kamil> +      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
Kamil> +       "Start Addr",
Kamil> +       "  End Addr",
Kamil> +       "      Size", "    Offset", "Flags  ", "File");
Kamil> +    }
Kamil> +  else
Kamil> +    {
Kamil> +      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
Kamil> +       "Start Addr",
Kamil> +       "  End Addr",
Kamil> +       "      Size", "    Offset", "Flags  ", "File");

Personally I like using ui-out tables instead of this kind of thing.

Tom
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
On 20.03.2020 16:36, Tom Tromey wrote:

>>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:
>
> Kamil> Define nbsd_nat_target::find_memory_regions and
> Kamil> nbsd_nat_target::info_proc. info_proc handles as of now only
> Kamil> the "mappings" command.
>
> Thank you for the patch.
>
> Kamil> +/* Retrieve all the memory regions in the specified process.  */
> Kamil> +
> Kamil> +static struct kinfo_vmentry *
> Kamil> +kinfo_get_vmmap(pid_t pid, size_t *size)
>
> Space before paren.
> There are multiple instances of this in the patch.
>
Done.

> Kamil> +{
> Kamil> +  int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid, sizeof(struct kinfo_vmentry)};
> Kamil> +
> Kamil> +  size_t length = 0;
> Kamil> +  if (sysctl(mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0)) {
>
> GNU style is to put the open brace on its own line.
> There are several cases of this as well.
>

Done.

> Kamil> +  if (sysctl(mib, ARRAY_SIZE (mib), kiv, &length, NULL, 0)) {
> Kamil> +    *size = 0;
> Kamil> +    free(kiv);
>
> xfree, though these days in gdb it's better to create and return a
> self-managing object, like gdb::unique_xmalloc_ptr<>.
>

Done.

> Kamil> +
> Kamil> +int
> Kamil> +nbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
> Kamil> +      void *obfd)
>
> I wouldn't name that parameter "obfd" but rather "data" or "user_data"
> or something like that.  The name "obfd" in gdb normally implies that it
> is a "BFD *", but this is just opaque data that's shared by the caller
> and the callback.
>
I see. I prefer to keep this called obfd, as it matches the FreeBSD code
more closely. If we want to rename it, we shall do it also in FreeBSD.

> Kamil> diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
> [...]
> Kamil> +/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
> Kamil> +   match the KVME_PROT_* constants in <sys/sysctl.h>.  */
>
> What if they stop matching?
>

Not a concern.

If that will ever change, it will be patched, same as the other existing
NetBSD support.

> I wonder if this code really ought to be in the tdep file.  I suppose
> so, if it will be used somehow when cross debugging... but will that
> happen?
>

This code follows the structure of FreeBSD.

> If not then maybe putting it in the -nat file is better; and then the
> appropriate NetBSD headers could be used.
>

I prefer to keep similarity with FreeBSD. If we want to change it,
FreeBSD shall be changed too.

> Kamil> +  printf_filtered (_("Mapped address spaces:\n\n"));
> Kamil> +  if (addr_bit == 64)
> Kamil> +    {
> Kamil> +      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
> Kamil> +       "Start Addr",
> Kamil> +       "  End Addr",
> Kamil> +       "      Size", "    Offset", "Flags  ", "File");
> Kamil> +    }
> Kamil> +  else
> Kamil> +    {
> Kamil> +      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
> Kamil> +       "Start Addr",
> Kamil> +       "  End Addr",
> Kamil> +       "      Size", "    Offset", "Flags  ", "File");
>
> Personally I like using ui-out tables instead of this kind of thing.
>
I will keep this as is. If we want to change it, we shall change FreeBSD
in one go.

I don't have chance to work or test on FreeBSD myself so I defer
refactoring it into future.

Please see v2.

> Tom
>



signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

[PATCH v2] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Kamil Rytarowski
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()

This code is based on the FreeBSD implementation.

gdb/ChangeLog:

        * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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   |  17 ++++++
 gdb/nbsd-nat.c  | 153 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 ++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 281 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 650b74bae4a..b12965e41bb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-03-20  Kamil Rytarowski  <[hidden email]>
+
+ * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>

  * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 326bbe3aec3..26115948aa9 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -39,3 +42,153 @@ nbsd_nat_target::pid_to_exec_file (int pid)
     return NULL;
   return buf;
 }
+
+/* Retrieve all the memory regions in the specified process.  */
+
+static gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
+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. */
+  length = length * 5 / 3;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry> kiv
+    ((struct kinfo_vmentry *) xcalloc (length, 1));
+  if (kiv == NULL)
+    {
+      *size = 0;
+      return NULL;
+    }
+
+  if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
+    {
+      *size = 0;
+      return NULL;
+    }
+
+  *size = length / sizeof (*kiv);
+  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 *obfd)
+{
+  pid_t pid = inferior_ptid.pid ();
+  struct kinfo_vmentry *kve;
+  uint64_t size;
+  int i;
+  size_t nitems;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
+    vmentl (kinfo_get_vmmap (pid, &nitems));
+  if (vmentl == NULL)
+    perror_with_name (_("Couldn't fetch VM map entries."));
+
+  for (i = 0, kve = vmentl.get (); i < nitems; i++, kve++)
+    {
+      /* 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 = 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, obfd);
+    }
+  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 (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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 49bb2b706bd..23732854172 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@
 #include "solib-svr4.h"
 #include "nbsd-tdep.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.  */

@@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
   && startswith (func_name, "__sigtramp"));
 }
+
+/* See fbsd-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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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 void *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),
+       reinterpret_cast<const char *> (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),
+       reinterpret_cast<const char *> (kve_path));
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..81bdb2510f5 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 void *kve_path);
+
 #endif /* NBSD_TDEP_H */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Tom Tromey-2
In reply to this post by Kamil Rytarowski
>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:

Kamil> I see. I prefer to keep this called obfd, as it matches the FreeBSD code
Kamil> more closely. If we want to rename it, we shall do it also in FreeBSD.

Well, that FreeBSD code is wrong too...

>> What if they stop matching?

Kamil> Not a concern.

Kamil> If that will ever change, it will be patched, same as the other
Kamil> existing NetBSD support.

How will cross debugging to different versions work in this situation?

Kamil> I prefer to keep similarity with FreeBSD. If we want to change it,
Kamil> FreeBSD shall be changed too.

...
Kamil> I don't have chance to work or test on FreeBSD myself so I defer
Kamil> refactoring it into future.

It sounds like maybe FreeBSD isn't as maintained?  Unless the two need
to share a lot of code, it seems like it would be better to do things as
well as possible in the maintained code; and let the other code alone.

Tom

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
On 20.03.2020 19:50, Tom Tromey wrote:

>>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:
>
> Kamil> I see. I prefer to keep this called obfd, as it matches the FreeBSD code
> Kamil> more closely. If we want to rename it, we shall do it also in FreeBSD.
>
> Well, that FreeBSD code is wrong too...
>
>>> What if they stop matching?
>
> Kamil> Not a concern.
>
> Kamil> If that will ever change, it will be patched, same as the other
> Kamil> existing NetBSD support.
>
> How will cross debugging to different versions work in this situation?
>
Do you mean non-NetBSD cross debugging connected to NetBSD gdbserver?

In any other case there is no concern and APIs are stable. If there will
be ABI changes, we will version sysctl() for new vs old calls, keeping
compat and old prebuilt things will continue to work.

> Kamil> I prefer to keep similarity with FreeBSD. If we want to change it,
> Kamil> FreeBSD shall be changed too.
>
> ...
> Kamil> I don't have chance to work or test on FreeBSD myself so I defer
> Kamil> refactoring it into future.
>
> It sounds like maybe FreeBSD isn't as maintained?  Unless the two need
> to share a lot of code, it seems like it would be better to do things as
> well as possible in the maintained code; and let the other code alone.
>
If that can make the code merged, I will apply some changes on the cost
of diverging from the FreeBSD model.

> Tom
>



signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

John Baldwin
In reply to this post by Tom Tromey-2
On 3/20/20 11:50 AM, Tom Tromey wrote:
>>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:
>
> Kamil> I see. I prefer to keep this called obfd, as it matches the FreeBSD code
> Kamil> more closely. If we want to rename it, we shall do it also in FreeBSD.
>
> Well, that FreeBSD code is wrong too...

I looked, and I think that name was just inherited.  The callback argument commonly
passed to this function is in fact the bfd for a core file being generated (e.g.
from gcore_memory_sections) and other functions like objfile_find_memory_regions()
still use 'obfd' here.  I think it's perfectly reasonable to rename the
variable.  The exec target uses 'data' which it gained when it became a C++ class
instead of setting to_find_memory_regions to objfile_find_memory_regions directly.

>>> What if they stop matching?
>
> Kamil> Not a concern.
>
> Kamil> If that will ever change, it will be patched, same as the other
> Kamil> existing NetBSD support.
>
> How will cross debugging to different versions work in this situation?

From FreeBSD's perspective, we probably won't ever change these bitfields as our
struct kinfo_vmentry is a public structure that we make ABI promises about that
is supposed to be the "public" version of internal kernel structures.  I suspect
NetBSD is following a similar model.

FWIW, I did the code in the tdep file to support core file debugging and cross
debugging (which works).  I think the Linux tdep code also does info proc
in the tdep file for similar reasons.  In the case of Linux, linux-tdep.c
handles core dumps, while procfs.c appears to handle native processes.

The formatting of using manual tables, etc. for info proc is also something the
Linux and procfs backends do.  It might indeed be much cleaner to use ui-out
(and probably more friendly to mi if we did so?)

--
John Baldwin
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
On 25.03.2020 17:36, John Baldwin wrote:

> On 3/20/20 11:50 AM, Tom Tromey wrote:
>>>>>>> "Kamil" == Kamil Rytarowski <[hidden email]> writes:
>>
>> Kamil> I see. I prefer to keep this called obfd, as it matches the FreeBSD code
>> Kamil> more closely. If we want to rename it, we shall do it also in FreeBSD.
>>
>> Well, that FreeBSD code is wrong too...
>
> I looked, and I think that name was just inherited.  The callback argument commonly
> passed to this function is in fact the bfd for a core file being generated (e.g.
> from gcore_memory_sections) and other functions like objfile_find_memory_regions()
> still use 'obfd' here.  I think it's perfectly reasonable to rename the
> variable.  The exec target uses 'data' which it gained when it became a C++ class
> instead of setting to_find_memory_regions to objfile_find_memory_regions directly.
>

OK, I can rename obfd to data.

>>>> What if they stop matching?
>>
>> Kamil> Not a concern.
>>
>> Kamil> If that will ever change, it will be patched, same as the other
>> Kamil> existing NetBSD support.
>>
>> How will cross debugging to different versions work in this situation?
>
> From FreeBSD's perspective, we probably won't ever change these bitfields as our
> struct kinfo_vmentry is a public structure that we make ABI promises about that
> is supposed to be the "public" version of internal kernel structures.  I suspect
> NetBSD is following a similar model.
>

Yes.

> FWIW, I did the code in the tdep file to support core file debugging and cross
> debugging (which works).  I think the Linux tdep code also does info proc
> in the tdep file for similar reasons.  In the case of Linux, linux-tdep.c
> handles core dumps, while procfs.c appears to handle native processes.
>
> The formatting of using manual tables, etc. for info proc is also something the
> Linux and procfs backends do.  It might indeed be much cleaner to use ui-out
> (and probably more friendly to mi if we did so?)
>

My code is not different to prior art.

So, is this patch fine for merging after the obfd->data rename?
Reply | Threaded
Open this post in threaded view
|

[PATCH v2] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Kamil Rytarowski
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", "inferior.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   |  17 ++++++
 gdb/nbsd-nat.c  | 134 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 ++++++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 +++++++
 5 files changed, 262 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 650b74bae4a..b12965e41bb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-03-20  Kamil Rytarowski  <[hidden email]>
+
+ * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>

  * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 326bbe3aec3..aa36bf56364 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -39,3 +42,134 @@ nbsd_nat_target::pid_to_exec_file (int pid)
     return NULL;
   return buf;
 }
+
+/* Retrieve all the memory regions in the specified process.  */
+
+static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
+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))
+    perror_with_name (("sysctl"));
+
+  /* Prereserve more space. */
+  length = length * 5 / 3;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
+    ((struct kinfo_vmentry *) xcalloc (length, 1));
+
+  if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
+    perror_with_name (("sysctl"));
+
+  *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
+    = kinfo_get_vmmap (pid, &nitems);
+
+  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
+ = kinfo_get_vmmap (pid, &nvment);
+
+      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);
+    }
+
+  return true;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 49bb2b706bd..23732854172 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@
 #include "solib-svr4.h"
 #include "nbsd-tdep.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.  */

@@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
   && startswith (func_name, "__sigtramp"));
 }
+
+/* See fbsd-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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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 void *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),
+       reinterpret_cast<const char *> (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),
+       reinterpret_cast<const char *> (kve_path));
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..81bdb2510f5 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 void *kve_path);
+
 #endif /* NBSD_TDEP_H */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
I will fix one thing and sumit v3.

On 02.04.2020 22:09, Kamil Rytarowski wrote:

> 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", "inferior.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   |  17 ++++++
>  gdb/nbsd-nat.c  | 134 ++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/nbsd-nat.h  |   2 +
>  gdb/nbsd-tdep.c |  91 ++++++++++++++++++++++++++++++++
>  gdb/nbsd-tdep.h |  18 +++++++
>  5 files changed, 262 insertions(+)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 650b74bae4a..b12965e41bb 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,20 @@
> +2020-03-20  Kamil Rytarowski  <[hidden email]>
> +
> + * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>
>
>   * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
> diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
> index 326bbe3aec3..aa36bf56364 100644
> --- a/gdb/nbsd-nat.c
> +++ b/gdb/nbsd-nat.c
> @@ -20,6 +20,9 @@
>  #include "defs.h"
>
>  #include "nbsd-nat.h"
> +#include "nbsd-tdep.h"
> +#include "inferior.h"
> +#include "gdbarch.h"
>
>  #include <sys/types.h>
>  #include <sys/ptrace.h>
> @@ -39,3 +42,134 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>      return NULL;
>    return buf;
>  }
> +
> +/* Retrieve all the memory regions in the specified process.  */
> +
> +static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
> +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))
> +    perror_with_name (("sysctl"));
> +
> +  /* Prereserve more space. */
> +  length = length * 5 / 3;
> +
> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
> +    ((struct kinfo_vmentry *) xcalloc (length, 1));
> +
> +  if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
> +    perror_with_name (("sysctl"));
> +
> +  *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
> +    = kinfo_get_vmmap (pid, &nitems);
> +
> +  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
> + = kinfo_get_vmmap (pid, &nvment);
> +
> +      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);
> +    }
> +
> +  return true;
> +}
> diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
> index a752fbe572d..98af21d0bda 100644
> --- a/gdb/nbsd-nat.h
> +++ b/gdb/nbsd-nat.h
> @@ -27,6 +27,8 @@
>  struct nbsd_nat_target : public inf_ptrace_target
>  {
>    char *pid_to_exec_file (int pid) 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 */
> diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
> index 49bb2b706bd..23732854172 100644
> --- a/gdb/nbsd-tdep.c
> +++ b/gdb/nbsd-tdep.c
> @@ -23,6 +23,23 @@
>  #include "solib-svr4.h"
>  #include "nbsd-tdep.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.  */
>
> @@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
>    return (func_name != NULL
>    && startswith (func_name, "__sigtramp"));
>  }
> +
> +/* See fbsd-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;
> +}
> +
> +/* See nbsd-tdep.h.  */
> +
> +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 void *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),
> +       reinterpret_cast<const char *> (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),
> +       reinterpret_cast<const char *> (kve_path));
> +    }
> +}
> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
> index c99a8b537b6..81bdb2510f5 100644
> --- a/gdb/nbsd-tdep.h
> +++ b/gdb/nbsd-tdep.h
> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
>
>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
>
> +/* 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 void *kve_path);
> +
>  #endif /* NBSD_TDEP_H */
> --
> 2.25.0
>

Reply | Threaded
Open this post in threaded view
|

[PATCH v3] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Kamil Rytarowski
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", "inferior.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   |  17 ++++++
 gdb/nbsd-nat.c  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 276 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 650b74bae4a..b12965e41bb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-03-20  Kamil Rytarowski  <[hidden email]>
+
+ * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>

  * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 326bbe3aec3..82f9837b775 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)
     return NULL;
   return buf;
 }
+
+/* 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. */
+  length = length * 5 / 3;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
+    ((struct kinfo_vmentry *) xcalloc (length, 1));
+
+  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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 49bb2b706bd..29dc9172306 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@
 #include "solib-svr4.h"
 #include "nbsd-tdep.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.  */

@@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
   && startswith (func_name, "__sigtramp"));
 }
+
+/* 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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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 void *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),
+       reinterpret_cast<const char *> (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),
+       reinterpret_cast<const char *> (kve_path));
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..81bdb2510f5 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 void *kve_path);
+
 #endif /* NBSD_TDEP_H */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
Ping?

On 06.04.2020 11:37, Kamil Rytarowski wrote:

> 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", "inferior.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   |  17 ++++++
>  gdb/nbsd-nat.c  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/nbsd-nat.h  |   2 +
>  gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
>  gdb/nbsd-tdep.h |  18 ++++++
>  5 files changed, 276 insertions(+)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 650b74bae4a..b12965e41bb 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,20 @@
> +2020-03-20  Kamil Rytarowski  <[hidden email]>
> +
> + * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>
>
>   * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
> diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
> index 326bbe3aec3..82f9837b775 100644
> --- a/gdb/nbsd-nat.c
> +++ b/gdb/nbsd-nat.c
> @@ -20,6 +20,9 @@
>  #include "defs.h"
>
>  #include "nbsd-nat.h"
> +#include "nbsd-tdep.h"
> +#include "inferior.h"
> +#include "gdbarch.h"
>
>  #include <sys/types.h>
>  #include <sys/ptrace.h>
> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>      return NULL;
>    return buf;
>  }
> +
> +/* 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. */
> +  length = length * 5 / 3;
> +
> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
> +    ((struct kinfo_vmentry *) xcalloc (length, 1));
> +
> +  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;
> +}
> diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
> index a752fbe572d..98af21d0bda 100644
> --- a/gdb/nbsd-nat.h
> +++ b/gdb/nbsd-nat.h
> @@ -27,6 +27,8 @@
>  struct nbsd_nat_target : public inf_ptrace_target
>  {
>    char *pid_to_exec_file (int pid) 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 */
> diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
> index 49bb2b706bd..29dc9172306 100644
> --- a/gdb/nbsd-tdep.c
> +++ b/gdb/nbsd-tdep.c
> @@ -23,6 +23,23 @@
>  #include "solib-svr4.h"
>  #include "nbsd-tdep.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.  */
>
> @@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
>    return (func_name != NULL
>    && startswith (func_name, "__sigtramp"));
>  }
> +
> +/* 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;
> +}
> +
> +/* See nbsd-tdep.h.  */
> +
> +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 void *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),
> +       reinterpret_cast<const char *> (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),
> +       reinterpret_cast<const char *> (kve_path));
> +    }
> +}
> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
> index c99a8b537b6..81bdb2510f5 100644
> --- a/gdb/nbsd-tdep.h
> +++ b/gdb/nbsd-tdep.h
> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
>
>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
>
> +/* 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 void *kve_path);
> +
>  #endif /* NBSD_TDEP_H */
> --
> 2.25.0
>

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3] Implement "info proc mappings" for NetBSD

Simon Marchi-4
In reply to this post by Kamil Rytarowski
On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:

> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>      return NULL;
>    return buf;
>  }
> +
> +/* 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. */
> +  length = length * 5 / 3;

Why is this needed?

> +
> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
> +    ((struct kinfo_vmentry *) xcalloc (length, 1));

Let's use XCNEWVAR here.  It doesn't matter in this case, but for consistency.  It does
check that we are not trying to allocate space for a non-POD type.  You can use like:

  XCNEWVAR (kinfo_vmentry, length)

You can also use XNEWVAR if you don't care about the buffer being initialized to zeros.

> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
> index c99a8b537b6..81bdb2510f5 100644
> --- a/gdb/nbsd-tdep.h
> +++ b/gdb/nbsd-tdep.h
> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
>
>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
>
> +/* 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 void *kve_path);

I'd make the last parameter a `const char *` directly, since this is what the function
expects to receive.  And remove the reinterpret_casts.

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
On 11.04.2020 23:05, Simon Marchi wrote:

> On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:
>> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>>      return NULL;
>>    return buf;
>>  }
>> +
>> +/* 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. */
>> +  length = length * 5 / 3;
>
> Why is this needed?
>

This length is volatile and can be larger on the 2nd sysctl(3) call. We
can call this function against a running process that can enlarge its
usage of address space in this time window.

>> +
>> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
>> +    ((struct kinfo_vmentry *) xcalloc (length, 1));
>
> Let's use XCNEWVAR here.  It doesn't matter in this case, but for consistency.  It does
> check that we are not trying to allocate space for a non-POD type.  You can use like:
>
>   XCNEWVAR (kinfo_vmentry, length)
>
> You can also use XNEWVAR if you don't care about the buffer being initialized to zeros.
>

OK.

>> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
>> index c99a8b537b6..81bdb2510f5 100644
>> --- a/gdb/nbsd-tdep.h
>> +++ b/gdb/nbsd-tdep.h
>> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);
>>
>>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);
>>
>> +/* 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 void *kve_path);
>
> I'd make the last parameter a `const char *` directly, since this is what the function
> expects to receive.  And remove the reinterpret_casts.
>

OK.

> Simon
>

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3] Implement "info proc mappings" for NetBSD

Simon Marchi-4
On 2020-04-11 5:28 p.m., Kamil Rytarowski wrote:

> On 11.04.2020 23:05, Simon Marchi wrote:
>> On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:
>>> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)
>>>      return NULL;
>>>    return buf;
>>>  }
>>> +
>>> +/* 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. */
>>> +  length = length * 5 / 3;
>>
>> Why is this needed?
>>
>
> This length is volatile and can be larger on the 2nd sysctl(3) call. We
> can call this function against a running process that can enlarge its
> usage of address space in this time window.

Ok, then please make the comment explain that.  We can see that the expression
increases length, but as a reader I have no idea why.

Simon
Reply | Threaded
Open this post in threaded view
|

[PATCH v4] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Kamil Rytarowski
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", "inferior.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   |  17 ++++++
 gdb/nbsd-nat.c  | 150 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 278 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 650b74bae4a..b12965e41bb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-03-20  Kamil Rytarowski  <[hidden email]>
+
+ * nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <[hidden email]>

  * amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 326bbe3aec3..1651f2033e3 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -39,3 +42,150 @@ nbsd_nat_target::pid_to_exec_file (int pid)
     return NULL;
   return buf;
 }
+
+/* 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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 49bb2b706bd..4f24b62a8a7 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@
 #include "solib-svr4.h"
 #include "nbsd-tdep.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.  */

@@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
   && startswith (func_name, "__sigtramp"));
 }
+
+/* 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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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);
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..581ffb4455a 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v4] Implement "info proc mappings" for NetBSD

Simon Marchi-4
On 2020-04-11 7:45 p.m., Kamil Rytarowski wrote:

> 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()

When sending a new version, can you please rebase it on the current master?

The patch does not apply cleanly on master today, so it doesn't really reflect what's
going to be merged.

Simon
Reply | Threaded
Open this post in threaded view
|

[PATCH v5] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Kamil Rytarowski
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   |  17 ++++++
 gdb/nbsd-nat.c  | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   3 +
 gdb/nbsd-tdep.c |  89 +++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 276 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 81102ee569b..336bd497413 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2020-04-11  Kamil Rytarowski  <[hidden email]>
+
+ * 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  <[hidden email]>

  * utils.c (copy_bitwise): Use unsigned 0 constant as operand of
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 4423e19428d..2420153c7bc 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index 3606048cd07..256db4b9017 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -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 */
diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c
index 158a43bebaa..52e0640e35c 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -26,6 +26,23 @@
 #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)
 {
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index 4b06c13f87b..a6e3a8f0f3f 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -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 */
--
2.25.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v4] Implement "info proc mappings" for NetBSD

Kamil Rytarowski
In reply to this post by Simon Marchi-4
On 12.04.2020 01:49, Simon Marchi wrote:

> On 2020-04-11 7:45 p.m., Kamil Rytarowski wrote:
>> 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()
>
> When sending a new version, can you please rebase it on the current master?
>
> The patch does not apply cleanly on master today, so it doesn't really reflect what's
> going to be merged.
>
> Simon
>

Rebased in v5.
12