[PATCH v2 0/5] Support for 'info proc' on FreeBSD cores and native

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

[PATCH v2 0/5] Support for 'info proc' on FreeBSD cores and native

John Baldwin
Changes since the first version of this patch series include:

- The first patch for binutils recognizing new core notes has been
  pushed.
- The 'stat' and 'status' subcommands have been merged on FreeBSD.
- Additional error checking added to the argument parsing for the
  native FreeBSD target's info proc method.
- One new patch to fix a bug in fbsd_pid_to_exec_file found during
  testing.
- One new patch to remove an extraneous unique_ptr deleter.
- Various cleanups suggested by Simon Marchi.
- Further refinements to the documentation to be less /proc centric
  and to fix some dangling references to the renamed node's old name.

John Baldwin (5):
  Support 'info proc' for FreeBSD process core dumps.
  Don't return stale data from fbsd_pid_to_exec_file for kernel
    processes.
  Use gdb::unique_xmalloc_ptr<> instead of a deleter that invokes
    free().
  Support 'info proc' for native FreeBSD processes.
  Document support for 'info proc' on FreeBSD.

 gdb/ChangeLog       |  42 ++++
 gdb/config.in       |   3 +
 gdb/configure       |  60 +++++
 gdb/configure.ac    |   5 +
 gdb/doc/ChangeLog   |   9 +
 gdb/doc/gdb.texinfo |  76 ++++---
 gdb/fbsd-nat.c      | 384 ++++++++++++++++++++++++++++---
 gdb/fbsd-tdep.c     | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/fbsd-tdep.h     |   7 +
 9 files changed, 1161 insertions(+), 68 deletions(-)

--
2.15.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 1/5] Support 'info proc' for FreeBSD process core dumps.

John Baldwin
- Command line arguments are obtained from the pr_psargs[] array
  saved in the NT_PRPSINFO note.
- The 'cwd' and 'exe' values are obtained from the per-process file
  descriptor table stored in the NT_PROCSTAT_FILES core note.
- 'mappings' is implemented by walking the array of VM map entries
  stored in the NT_PROCSTAT_VMMAP core note.
- 'status' output is generated by outputting fields from
  the first structure stored in the NT_PROCSTAT_PROC core note.
- 'stat' is aliased to 'status'.

gdb/ChangeLog:

        * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
        (KVE_FLAGS, KVE_PROTECTION, KVE_PATH, 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_SUPER, KINFO_VME_FLAG_GROWS_UP)
        (KINFO_VME_FLAG_GROWS_DOWN, KF_STRUCTSIZE, KF_TYPE, KF_FD)
        (KF_PATH, KINFO_FILE_TYPE_VNODE, KINFO_FILE_FD_TYPE_CWD)
        (KINFO_FILE_FD_TYPE_TEXT, SIG_WORDS, struct kinfo_proc_layout)
        (kinfo_proc_layout_32, kinfo_proc_layout_i386)
        (kinfo_proc_layout_64, fbsd_vm_map_entry_flags)
        (fbsd_core_info_proc_mappings, fbsd_core_vnode_path)
        (fbsd_core_fetch_timeval, fbsd_print_sigset)
        (fbsd_core_info_proc_status, fbsd_core_info_proc): New.
        (fbsd_init_abi):  Install gdbarch "core_info_proc" method.
        * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.
---
 gdb/ChangeLog   |  18 ++
 gdb/fbsd-tdep.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/fbsd-tdep.h |   7 +
 3 files changed, 668 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ed9d2b0ce5..29cfbb287b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,21 @@
+2018-01-03  John Baldwin  <[hidden email]>
+
+ * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
+ (KVE_FLAGS, KVE_PROTECTION, KVE_PATH, 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_SUPER, KINFO_VME_FLAG_GROWS_UP)
+ (KINFO_VME_FLAG_GROWS_DOWN, KF_STRUCTSIZE, KF_TYPE, KF_FD)
+ (KF_PATH, KINFO_FILE_TYPE_VNODE, KINFO_FILE_FD_TYPE_CWD)
+ (KINFO_FILE_FD_TYPE_TEXT, SIG_WORDS, struct kinfo_proc_layout)
+ (kinfo_proc_layout_32, kinfo_proc_layout_i386)
+ (kinfo_proc_layout_64, fbsd_vm_map_entry_flags)
+ (fbsd_core_info_proc_mappings, fbsd_core_vnode_path)
+ (fbsd_core_fetch_timeval, fbsd_print_sigset)
+ (fbsd_core_info_proc_status, fbsd_core_info_proc): New.
+ (fbsd_init_abi):  Install gdbarch "core_info_proc" method.
+ * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.
+
 2018-01-03  Xavier Roirand  <[hidden email]>
 
  * ada-lang.h (ada_exception_catchpoint_kind) <ada_catch_handlers>:
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index ce17c672d9..2bed89d019 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -52,6 +52,228 @@
 #define SIZE64_SIGINFO_T 80
 #define SIZE32_SIGINFO_T 64
 
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_VMMAP core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_vmentry.  This data structure should have the same layout on
+   all architectures.  */
+
+#define KVE_STRUCTSIZE 0x0
+#define KVE_START 0x8
+#define KVE_END 0x10
+#define KVE_OFFSET 0x18
+#define KVE_FLAGS 0x2c
+#define KVE_PROTECTION 0x56
+#define KVE_PATH 0x88
+
+/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
+   match the KVME_PROT_* constants in <sys/user.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/user.h>.  */
+
+#define KINFO_VME_FLAG_COW 0x00000001
+#define KINFO_VME_FLAG_NEEDS_COPY 0x00000002
+#define KINFO_VME_FLAG_NOCOREDUMP 0x00000004
+#define KINFO_VME_FLAG_SUPER 0x00000008
+#define KINFO_VME_FLAG_GROWS_UP 0x00000010
+#define KINFO_VME_FLAG_GROWS_DOWN 0x00000020
+
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_FILES core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_file.  This data structure should have the same layout on all
+   architectures.  */
+
+#define KF_STRUCTSIZE 0x0
+#define KF_TYPE 0x4
+#define KF_FD 0x8
+#define KF_PATH 0x170
+
+/* Constants for the 'kf_type' field in struct kinfo_file.  These
+   match the KF_TYPE_* constants in <sys/user.h>.  */
+
+#define KINFO_FILE_TYPE_VNODE 1
+
+/* Special values for the 'kf_fd' field in struct kinfo_file.  These
+   match the KF_FD_TYPE_* constants in <sys/user.h>.  */
+
+#define KINFO_FILE_FD_TYPE_CWD -1
+#define KINFO_FILE_FD_TYPE_TEXT -5
+
+/* Number of 32-bit words in a signal set.  This matches _SIG_WORDS in
+   <sys/_sigset.h> and is the same value on all architectures.  */
+
+#define SIG_WORDS 4
+
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_PROC core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_proc.  This data structure has different layouts on different
+   architectures mostly due to ILP32 vs LP64.  However, FreeBSD/i386
+   uses a 32-bit time_t while all other architectures use a 64-bit
+   time_t.
+
+   The core dump note actually contains one kinfo_proc structure for
+   each thread, but all of the process-wide data can be obtained from
+   the first structure.  One result of this note's format is that some
+   of the process-wide status available in the native target method
+   from the kern.proc.pid.<pid> sysctl such as ki_stat and ki_siglist
+   is not available from a core dump.  Instead, the per-thread data
+   structures contain the value of these fields for individual
+   threads.  */
+
+struct kinfo_proc_layout
+{
+  /* Offsets of struct kinfo_proc members.  */
+  int ki_layout;
+  int ki_pid;
+  int ki_ppid;
+  int ki_pgid;
+  int ki_tpgid;
+  int ki_sid;
+  int ki_tdev_freebsd11;
+  int ki_sigignore;
+  int ki_sigcatch;
+  int ki_uid;
+  int ki_ruid;
+  int ki_svuid;
+  int ki_rgid;
+  int ki_svgid;
+  int ki_ngroups;
+  int ki_groups;
+  int ki_size;
+  int ki_rssize;
+  int ki_tsize;
+  int ki_dsize;
+  int ki_ssize;
+  int ki_start;
+  int ki_nice;
+  int ki_comm;
+  int ki_tdev;
+  int ki_rusage;
+  int ki_rusage_ch;
+
+  /* Offsets of struct rusage members.  */
+  int ru_utime;
+  int ru_stime;
+  int ru_maxrss;
+  int ru_minflt;
+  int ru_majflt;
+};
+
+const struct kinfo_proc_layout kinfo_proc_layout_32 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x28,
+    .ki_ppid = 0x2c,
+    .ki_pgid = 0x30,
+    .ki_tpgid = 0x34,
+    .ki_sid = 0x38,
+    .ki_tdev_freebsd11 = 0x44,
+    .ki_sigignore = 0x68,
+    .ki_sigcatch = 0x78,
+    .ki_uid = 0x88,
+    .ki_ruid = 0x8c,
+    .ki_svuid = 0x90,
+    .ki_rgid = 0x94,
+    .ki_svgid = 0x98,
+    .ki_ngroups = 0x9c,
+    .ki_groups = 0xa0,
+    .ki_size = 0xe0,
+    .ki_rssize = 0xe4,
+    .ki_tsize = 0xec,
+    .ki_dsize = 0xf0,
+    .ki_ssize = 0xf4,
+    .ki_start = 0x118,
+    .ki_nice = 0x145,
+    .ki_comm = 0x17f,
+    .ki_tdev = 0x1f0,
+    .ki_rusage = 0x220,
+    .ki_rusage_ch = 0x278,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x10,
+    .ru_maxrss = 0x20,
+    .ru_minflt = 0x30,
+    .ru_majflt = 0x34,
+  };
+
+const struct kinfo_proc_layout kinfo_proc_layout_i386 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x28,
+    .ki_ppid = 0x2c,
+    .ki_pgid = 0x30,
+    .ki_tpgid = 0x34,
+    .ki_sid = 0x38,
+    .ki_tdev_freebsd11 = 0x44,
+    .ki_sigignore = 0x68,
+    .ki_sigcatch = 0x78,
+    .ki_uid = 0x88,
+    .ki_ruid = 0x8c,
+    .ki_svuid = 0x90,
+    .ki_rgid = 0x94,
+    .ki_svgid = 0x98,
+    .ki_ngroups = 0x9c,
+    .ki_groups = 0xa0,
+    .ki_size = 0xe0,
+    .ki_rssize = 0xe4,
+    .ki_tsize = 0xec,
+    .ki_dsize = 0xf0,
+    .ki_ssize = 0xf4,
+    .ki_start = 0x118,
+    .ki_nice = 0x135,
+    .ki_comm = 0x16f,
+    .ki_tdev = 0x1e0,
+    .ki_rusage = 0x210,
+    .ki_rusage_ch = 0x258,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x8,
+    .ru_maxrss = 0x10,
+    .ru_minflt = 0x20,
+    .ru_majflt = 0x24,
+  };
+
+const struct kinfo_proc_layout kinfo_proc_layout_64 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x48,
+    .ki_ppid = 0x4c,
+    .ki_pgid = 0x50,
+    .ki_tpgid = 0x54,
+    .ki_sid = 0x58,
+    .ki_tdev_freebsd11 = 0x64,
+    .ki_sigignore = 0x88,
+    .ki_sigcatch = 0x98,
+    .ki_uid = 0xa8,
+    .ki_ruid = 0xac,
+    .ki_svuid = 0xb0,
+    .ki_rgid = 0xb4,
+    .ki_svgid = 0xb8,
+    .ki_ngroups = 0xbc,
+    .ki_groups = 0xc0,
+    .ki_size = 0x100,
+    .ki_rssize = 0x108,
+    .ki_tsize = 0x118,
+    .ki_dsize = 0x120,
+    .ki_ssize = 0x128,
+    .ki_start = 0x150,
+    .ki_nice = 0x185,
+    .ki_comm = 0x1bf,
+    .ki_tdev = 0x230,
+    .ki_rusage = 0x260,
+    .ki_rusage_ch = 0x2f0,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x10,
+    .ru_maxrss = 0x20,
+    .ru_minflt = 0x40,
+    .ru_majflt = 0x48,
+  };
+
 static struct gdbarch_data *fbsd_gdbarch_data_handle;
 
 struct fbsd_gdbarch_data
@@ -367,6 +589,426 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   return note_data;
 }
 
+/* Helper function to generate mappings flags for a single VM map
+   entry in 'info proc mappings'.  */
+
+const char *
+fbsd_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_SUPER) ? 'S' : '-';
+  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;
+}
+
+/* Implement "info proc mappings" for a corefile.  */
+
+static void
+fbsd_core_info_proc_mappings (struct gdbarch *gdbarch)
+{
+  asection *section;
+  unsigned char *descdata, *descend;
+  size_t note_size;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.vmmap");
+  if (section == NULL)
+    {
+      warning (_("unable to find mappings in core file"));
+      return;
+    }
+
+  note_size = bfd_get_section_size (section);
+  if (note_size < 4)
+    error (_("malformed core note - too short for header"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+  descend = descdata + note_size;
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (gdbarch_addr_bit (gdbarch) == 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");
+    }
+
+  while (descdata + KVE_PATH < descend)
+    {
+      ULONGEST start, end, offset, flags, prot, structsize;
+
+      structsize = bfd_get_32 (core_bfd, descdata + KVE_STRUCTSIZE);
+      if (structsize < KVE_PATH)
+ error (_("malformed core note - vmmap entry too small"));
+
+      start = bfd_get_64 (core_bfd, descdata + KVE_START);
+      end = bfd_get_64 (core_bfd, descdata + KVE_END);
+      offset = bfd_get_64 (core_bfd, descdata + KVE_OFFSET);
+      flags = bfd_get_32 (core_bfd, descdata + KVE_FLAGS);
+      prot = bfd_get_32 (core_bfd, descdata + KVE_PROTECTION);
+      if (gdbarch_addr_bit (gdbarch) == 64)
+ {
+  printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
+   paddress (gdbarch, start),
+   paddress (gdbarch, end),
+   hex_string (end - start),
+   hex_string (offset),
+   fbsd_vm_map_entry_flags (flags, prot),
+   descdata + KVE_PATH);
+ }
+      else
+ {
+  printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
+   paddress (gdbarch, start),
+   paddress (gdbarch, end),
+   hex_string (end - start),
+   hex_string (offset),
+   fbsd_vm_map_entry_flags (flags, prot),
+   descdata + KVE_PATH);
+ }
+
+      descdata += structsize;
+    }
+}
+
+/* Fetch the pathname of a vnode for a single file descriptor from the
+   file table core note.  */
+
+static gdb::unique_xmalloc_ptr<char>
+fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd)
+{
+  asection *section;
+  unsigned char *descdata, *descend;
+  size_t note_size;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.files");
+  if (section == NULL)
+    return nullptr;
+
+  note_size = bfd_get_section_size (section);
+  if (note_size < 4)
+    error (_("malformed core note - too short for header"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+  descend = descdata + note_size;
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  while (descdata + KVE_PATH < descend)
+    {
+      ULONGEST structsize;
+
+      structsize = bfd_get_32 (core_bfd, descdata + KF_STRUCTSIZE);
+      if (structsize < KVE_PATH)
+ error (_("malformed core note - vmmap entry too small"));
+
+      if (bfd_get_32 (core_bfd, descdata + KF_TYPE) == KINFO_FILE_TYPE_VNODE
+  && bfd_get_signed_32 (core_bfd, descdata + KF_FD) == fd)
+ {
+  char *path = (char *) descdata + KF_PATH;
+  return gdb::unique_xmalloc_ptr<char> (xstrdup (path));
+ }
+
+      descdata += structsize;
+    }
+  return nullptr;
+}
+
+/* Helper function to read a struct timeval.  */
+
+static void
+fbsd_core_fetch_timeval (struct gdbarch *gdbarch, unsigned char *data,
+ LONGEST &sec, ULONGEST &usec)
+{
+  if (gdbarch_addr_bit (gdbarch) == 64)
+    {
+      sec = bfd_get_signed_64 (core_bfd, data);
+      usec = bfd_get_64 (core_bfd, data + 8);
+    }
+  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
+    {
+      sec = bfd_get_signed_32 (core_bfd, data);
+      usec = bfd_get_32 (core_bfd, data + 4);
+    }
+  else
+    {
+      sec = bfd_get_signed_64 (core_bfd, data);
+      usec = bfd_get_32 (core_bfd, data + 8);
+    }
+}
+
+/* Print out the contents of a signal set.  */
+
+static void
+fbsd_print_sigset (const char *descr, unsigned char *sigset)
+{
+  printf_filtered ("%s: ", descr);
+  for (int i = 0; i < SIG_WORDS; i++)
+    printf_filtered ("%08x ",
+     (unsigned int) bfd_get_32 (core_bfd, sigset + i * 4));
+  printf_filtered ("\n");
+}
+
+/* Implement "info proc status" for a corefile.  */
+
+static void
+fbsd_core_info_proc_status (struct gdbarch *gdbarch)
+{
+  const struct kinfo_proc_layout *kp;
+  asection *section;
+  const char *state;
+  unsigned char *descdata, *descend;
+  int addr_bit, long_bit;
+  size_t note_size;
+  ULONGEST value;
+  LONGEST sec;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
+  if (section == NULL)
+    {
+      warning (_("unable to find process info in core file"));
+      return;
+    }
+
+  addr_bit = gdbarch_addr_bit (gdbarch);
+  if (addr_bit == 64)
+    kp = &kinfo_proc_layout_64;
+  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
+    kp = &kinfo_proc_layout_i386;
+  else
+    kp = &kinfo_proc_layout_32;
+
+  note_size = bfd_get_section_size (section);
+  if (note_size < 4 + kp->ki_rusage_ch + kp->ru_majflt + addr_bit)
+    error (_("malformed core note - too short"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+  descend = descdata + note_size;
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  /* Verify 'ki_layout' is 0.  */
+  if (bfd_get_32 (core_bfd, descdata + kp->ki_layout) != 0)
+    {
+      warning (_("unsupported process information in core file"));
+      return;
+    }
+
+  printf_filtered ("Name: %.19s\n", descdata + kp->ki_comm);
+  printf_filtered ("Process ID: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
+  printf_filtered ("Parent process: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ppid)));
+  printf_filtered ("Process group: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pgid)));
+  printf_filtered ("Session id: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_sid)));
+
+  /* FreeBSD 12.0 and later store a 64-bit dev_t at 'ki_tdev'.  Older
+     kernels store a 32-bit dev_t at 'ki_tdev_freebsd11'.  In older
+     kernels the 64-bit 'ki_tdev' field is in a reserved section of
+     the structure that is cleared to zero.  Assume that a zero value
+     in ki_tdev indicates a core dump from an older kernel and use the
+     value in 'ki_tdev_freebsd11' instead.  */
+  value = bfd_get_64 (core_bfd, descdata + kp->ki_tdev);
+  if (value == 0)
+    value = bfd_get_32 (core_bfd, descdata + kp->ki_tdev_freebsd11);
+  printf_filtered ("TTY: %s\n", pulongest (value));
+  printf_filtered ("TTY owner process group: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_tpgid)));
+  printf_filtered ("User IDs (real, effective, saved): %s %s %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ruid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_uid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svuid)));
+  printf_filtered ("Group IDs (real, effective, saved): %s %s %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_rgid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_groups)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svgid)));
+  printf_filtered ("Groups: ");
+  uint16_t ngroups = bfd_get_16 (core_bfd, descdata + kp->ki_ngroups);
+  for (int i = 0; i < ngroups; i++)
+    printf_filtered ("%s ",
+     pulongest (bfd_get_32 (core_bfd,
+    descdata + kp->ki_groups + i * 4)));
+  printf_filtered ("\n");
+  value = bfd_get (addr_bit, core_bfd,
+   descdata + kp->ki_rusage + kp->ru_minflt);
+  printf_filtered ("Minor faults (no memory page): %s\n", pulongest (value));
+  value = bfd_get (addr_bit, core_bfd,
+   descdata + kp->ki_rusage_ch + kp->ru_minflt);
+  printf_filtered ("Minor faults, children: %s\n", pulongest (value));
+  value = bfd_get (addr_bit, core_bfd,
+   descdata + kp->ki_rusage + kp->ru_majflt);
+  printf_filtered ("Major faults (memory page faults): %s\n",
+   pulongest (value));
+  value = bfd_get (addr_bit, core_bfd,
+   descdata + kp->ki_rusage_ch + kp->ru_majflt);
+  printf_filtered ("Major faults, children: %s\n", pulongest (value));
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage + kp->ru_utime,
+   sec, value);
+  printf_filtered ("utime: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage + kp->ru_stime,
+   sec, value);
+  printf_filtered ("stime: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage_ch + kp->ru_utime,
+   sec, value);
+  printf_filtered ("utime, children: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage_ch + kp->ru_stime,
+   sec, value);
+  printf_filtered ("stime, children: %s.%06d\n", plongest (sec), (int) value);
+  printf_filtered ("'nice' value: %d\n",
+   bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice));
+  fbsd_core_fetch_timeval (gdbarch, descdata + kp->ki_start, sec, value);
+  printf_filtered ("Start time: %s.%06d\n", plongest (sec), (int) value);
+  printf_filtered ("Virtual memory size: %s kB\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_size) / 1024));
+  printf_filtered ("Data size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_dsize)));
+  printf_filtered ("Stack size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_ssize)));
+  printf_filtered ("Text size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_tsize)));
+  printf_filtered ("Resident set size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_rssize)));
+  printf_filtered ("Maximum RSS: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_rusage
+       + kp->ru_maxrss)));
+  fbsd_print_sigset ("Ignored Signals", descdata + kp->ki_sigignore);
+  fbsd_print_sigset ("Caught Signals", descdata + kp->ki_sigcatch);
+}
+
+/* Implement the "core_info_proc" gdbarch method.  */
+
+static void
+fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args,
+     enum info_proc_what what)
+{
+  bool do_cmdline = false;
+  bool do_cwd = false;
+  bool do_exe = false;
+  bool do_mappings = false;
+  bool do_status = false;
+  int pid;
+
+  switch (what)
+    {
+    case IP_MINIMAL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+      break;
+    case IP_MAPPINGS:
+      do_mappings = true;
+      break;
+    case IP_STATUS:
+    case IP_STAT:
+      do_status = true;
+      break;
+    case IP_CMDLINE:
+      do_cmdline = true;
+      break;
+    case IP_EXE:
+      do_exe = true;
+      break;
+    case IP_CWD:
+      do_cwd = true;
+      break;
+    case IP_ALL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+      do_mappings = true;
+      do_status = true;
+      break;
+    default:
+      return;
+    }
+
+  pid = bfd_core_file_pid (core_bfd);
+  if (pid != 0)
+    printf_filtered (_("process %d\n"), pid);
+
+  if (do_cmdline)
+    {
+      const char *cmdline;
+
+      cmdline = bfd_core_file_failing_command (core_bfd);
+      if (cmdline)
+ printf_filtered ("cmdline = '%s'\n", cmdline);
+      else
+ warning (_("Command line unavailable"));
+    }
+  if (do_cwd)
+    {
+      gdb::unique_xmalloc_ptr<char> cwd =
+ fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_CWD);
+      if (cwd)
+ printf_filtered ("cwd = '%s'\n", cwd.get ());
+      else
+ warning (_("unable to read current working directory"));
+    }
+  if (do_exe)
+    {
+      gdb::unique_xmalloc_ptr<char> exe =
+ fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_TEXT);
+      if (exe)
+ printf_filtered ("exe = '%s'\n", exe.get ());
+      else
+ warning (_("unable to read executable path name"));
+    }
+  if (do_mappings)
+    fbsd_core_info_proc_mappings (gdbarch);
+  if (do_status)
+    fbsd_core_info_proc_status (gdbarch);
+}
+
 /* Print descriptions of FreeBSD-specific AUXV entries to FILE.  */
 
 static void
@@ -519,6 +1161,7 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_core_thread_name (gdbarch, fbsd_core_thread_name);
   set_gdbarch_core_xfer_siginfo (gdbarch, fbsd_core_xfer_siginfo);
   set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes);
+  set_gdbarch_core_info_proc (gdbarch, fbsd_core_info_proc);
   set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry);
   set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type);
 
diff --git a/gdb/fbsd-tdep.h b/gdb/fbsd-tdep.h
index 9769903dec..0b293e5a25 100644
--- a/gdb/fbsd-tdep.h
+++ b/gdb/fbsd-tdep.h
@@ -22,4 +22,11 @@
 
 extern void fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
 
+/* Helper function to generate mappings flags for a single VM map
+   entry in 'info proc mappings'.  The KVE_FLAGS and KVE_PROTECTION
+   parameters should contain the values of the corresponding fields in
+   a 'struct kinfo_vmentry'.  */
+
+extern const char *fbsd_vm_map_entry_flags (int kve_flags, int kve_protection);
+
 #endif /* fbsd-tdep.h */
--
2.15.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 2/5] Don't return stale data from fbsd_pid_to_exec_file for kernel processes.

John Baldwin
In reply to this post by John Baldwin
For processes without an associated executable (such as kernel processes),
the kern.proc.pathname.<pid> system control node returns a length of zero
without modifying the user's buffer.  Detect this case and return NULL
rather than the previous contents of the static buffer 'buf'.

gdb/ChangeLog:

        * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
        NULL for an empty pathname.
---
 gdb/ChangeLog  | 5 +++++
 gdb/fbsd-nat.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 29cfbb287b..804dd4f402 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-03  John Baldwin  <[hidden email]>
+
+ * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
+ NULL for an empty pathname.
+
 2018-01-03  John Baldwin  <[hidden email]>
 
  * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index ec4eed9abe..7b1d1bf148 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -63,7 +63,7 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid)
   mib[3] = pid;
   buflen = sizeof buf;
   if (sysctl (mib, 4, buf, &buflen, NULL, 0) == 0)
-    return buf;
+    return buflen == 0 ? NULL : buf;
 #endif
 
   xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
--
2.15.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 3/5] Use gdb::unique_xmalloc_ptr<> instead of a deleter that invokes free().

John Baldwin
In reply to this post by John Baldwin
Since xfree() always wraps free(), it is safe to use the xfree deleter
for buffers allocated by library routines such as kinfo_getvmmap() that
must be released via free().

gdb/ChangeLog:

        * fbsd-nat.c (struct free_deleter): Remove.
        (fbsd_find_memory_regions): Use gdb::unique_xmalloc_ptr<>.
---
 gdb/ChangeLog  |  5 +++++
 gdb/fbsd-nat.c | 10 +---------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 804dd4f402..cdce396e9c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-03  John Baldwin  <[hidden email]>
+
+ * fbsd-nat.c (struct free_deleter): Remove.
+ (fbsd_find_memory_regions): Use gdb::unique_xmalloc_ptr<>.
+
 2018-01-03  John Baldwin  <[hidden email]>
 
  * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 7b1d1bf148..00e5cfb55c 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -78,14 +78,6 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid)
 }
 
 #ifdef HAVE_KINFO_GETVMMAP
-/* Deleter for std::unique_ptr that invokes free.  */
-
-template <typename T>
-struct free_deleter
-{
-  void operator() (T *ptr) const { free (ptr); }
-};
-
 /* 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.  */
@@ -99,7 +91,7 @@ fbsd_find_memory_regions (struct target_ops *self,
   uint64_t size;
   int i, nitems;
 
-  std::unique_ptr<struct kinfo_vmentry, free_deleter<struct kinfo_vmentry>>
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
     vmentl (kinfo_getvmmap (pid, &nitems));
   if (vmentl == NULL)
     perror_with_name (_("Couldn't fetch VM map entries."));
--
2.15.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 4/5] Support 'info proc' for native FreeBSD processes.

John Baldwin
In reply to this post by John Baldwin
- Command line arguments are fetched via the kern.proc.args.<pid>
  sysctl.
- The 'cwd' and 'exe' values are obtained from the per-process
  file descriptor table returned by kinfo_getfile() from libutil.
- 'mappings' is implemented by walking the array of VM map entries
  returned by kinfo_getvmmap() from libutil.
- 'status' output is generated by outputting fields from the structure
  returned by the kern.proc.pid.<pid> sysctl.
- 'stat' is aliased to 'status'.

gdb/ChangeLog:

        * configure.ac: Check for kinfo_getfile in libutil.
        * configure: Regenerate.
        * config.in: Regenerate.
        * fbsd-nat.c: Include "fbsd-tdep.h".
        (fbsd_fetch_cmdline): New.
        (fbsd_fetch_kinfo_proc): Move earlier and change to return a bool
        rather than calling error.
        (fbsd_info_proc): New.
        (fbsd_thread_name): Report error if fbsd_fetch_kinfo_proc fails.
        (fbsd_wait): Report warning if fbsd_fetch_kinfo_proc fails.
        (fbsd_nat_add_target): Set "to_info_proc" to "fbsd_info_proc".
---
 gdb/ChangeLog    |  14 +++
 gdb/config.in    |   3 +
 gdb/configure    |  60 +++++++++
 gdb/configure.ac |   5 +
 gdb/fbsd-nat.c   | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 428 insertions(+), 26 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index cdce396e9c..5812e8f357 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@
+2018-01-03  John Baldwin  <[hidden email]>
+
+ * configure.ac: Check for kinfo_getfile in libutil.
+ * configure: Regenerate.
+ * config.in: Regenerate.
+ * fbsd-nat.c: Include "fbsd-tdep.h".
+ (fbsd_fetch_cmdline): New.
+ (fbsd_fetch_kinfo_proc): Move earlier and change to return a bool
+ rather than calling error.
+ (fbsd_info_proc): New.
+ (fbsd_thread_name): Report error if fbsd_fetch_kinfo_proc fails.
+ (fbsd_wait): Report warning if fbsd_fetch_kinfo_proc fails.
+ (fbsd_nat_add_target): Set "to_info_proc" to "fbsd_info_proc".
+
 2018-01-03  John Baldwin  <[hidden email]>
 
  * fbsd-nat.c (struct free_deleter): Remove.
diff --git a/gdb/config.in b/gdb/config.in
index 1d11a97080..ad2cc1754e 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -219,6 +219,9 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
+/* Define to 1 if your system has the kinfo_getfile function. */
+#undef HAVE_KINFO_GETFILE
+
 /* Define to 1 if your system has the kinfo_getvmmap function. */
 #undef HAVE_KINFO_GETVMMAP
 
diff --git a/gdb/configure b/gdb/configure
index 7b250079de..a0baa7a53a 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -7927,6 +7927,66 @@ $as_echo "#define HAVE_KINFO_GETVMMAP 1" >>confdefs.h
 fi
 
 
+# fbsd-nat.c can also use kinfo_getfile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kinfo_getfile" >&5
+$as_echo_n "checking for library containing kinfo_getfile... " >&6; }
+if test "${ac_cv_search_kinfo_getfile+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char kinfo_getfile ();
+int
+main ()
+{
+return kinfo_getfile ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' util util-freebsd; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_kinfo_getfile=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_kinfo_getfile+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_kinfo_getfile+set}" = set; then :
+
+else
+  ac_cv_search_kinfo_getfile=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_kinfo_getfile" >&5
+$as_echo "$ac_cv_search_kinfo_getfile" >&6; }
+ac_res=$ac_cv_search_kinfo_getfile
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+$as_echo "#define HAVE_KINFO_GETFILE 1" >>confdefs.h
+
+fi
+
+
 
       if test "X$prefix" = "XNONE"; then
     acl_final_prefix="$ac_default_prefix"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 3e073b506e..c1fb550743 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -523,6 +523,11 @@ AC_SEARCH_LIBS(kinfo_getvmmap, util util-freebsd,
   [AC_DEFINE(HAVE_KINFO_GETVMMAP, 1,
             [Define to 1 if your system has the kinfo_getvmmap function. ])])
 
+# fbsd-nat.c can also use kinfo_getfile.
+AC_SEARCH_LIBS(kinfo_getfile, util util-freebsd,
+  [AC_DEFINE(HAVE_KINFO_GETFILE, 1,
+            [Define to 1 if your system has the kinfo_getfile function. ])])
+
 AM_ICONV
 
 # GDB may fork/exec the iconv program to get the list of supported character
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 00e5cfb55c..6908b3f56f 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -32,14 +32,16 @@
 #include <sys/signal.h>
 #include <sys/sysctl.h>
 #include <sys/user.h>
-#ifdef HAVE_KINFO_GETVMMAP
+#if defined(HAVE_KINFO_GETFILE) || defined(HAVE_KINFO_GETVMMAP)
 #include <libutil.h>
-#else
+#endif
+#if !defined(HAVE_KINFO_GETVMMAP)
 #include "filestuff.h"
 #endif
 
 #include "elf-bfd.h"
 #include "fbsd-nat.h"
+#include "fbsd-tdep.h"
 
 #include <list>
 
@@ -202,6 +204,338 @@ fbsd_find_memory_regions (struct target_ops *self,
 }
 #endif
 
+/* Fetch the command line for a running process.  */
+
+static gdb::unique_xmalloc_ptr<char>
+fbsd_fetch_cmdline (pid_t pid)
+{
+  size_t len;
+  int mib[4];
+
+  len = 0;
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_PROC;
+  mib[2] = KERN_PROC_ARGS;
+  mib[3] = pid;
+  if (sysctl (mib, 4, NULL, &len, NULL, 0) == -1)
+    return nullptr;
+
+  if (len == 0)
+    return nullptr;
+
+  gdb::unique_xmalloc_ptr<char> cmdline ((char *) xmalloc (len));
+  if (sysctl (mib, 4, cmdline.get (), &len, NULL, 0) == -1)
+    return nullptr;
+
+  return cmdline;
+}
+
+/* Fetch the external variant of the kernel's internal process
+   structure for the process PID into KP.  */
+
+static bool
+fbsd_fetch_kinfo_proc (pid_t pid, struct kinfo_proc *kp)
+{
+  size_t len;
+  int mib[4];
+
+  len = sizeof *kp;
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_PROC;
+  mib[2] = KERN_PROC_PID;
+  mib[3] = pid;
+  return (sysctl (mib, 4, kp, &len, NULL, 0) == 0);
+}
+
+/* Implement the "to_info_proc target_ops" method.  */
+
+static void
+fbsd_info_proc (struct target_ops *ops, const char *args,
+ enum info_proc_what what)
+{
+#ifdef HAVE_KINFO_GETFILE
+  gdb::unique_xmalloc_ptr<struct kinfo_file> fdtbl;
+  int nfd = 0;
+#endif
+  struct kinfo_proc kp;
+  char *tmp;
+  pid_t pid;
+  bool do_cmdline = false;
+  bool do_cwd = false;
+  bool do_exe = false;
+#ifdef HAVE_KINFO_GETVMMAP
+  bool do_mappings = false;
+#endif
+  bool do_status = false;
+  bool kp_valid = false;
+
+  switch (what)
+    {
+    case IP_MINIMAL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+      break;
+#ifdef HAVE_KINFO_GETVMMAP
+    case IP_MAPPINGS:
+      do_mappings = true;
+      break;
+#endif
+    case IP_STATUS:
+    case IP_STAT:
+      do_status = true;
+      break;
+    case IP_CMDLINE:
+      do_cmdline = true;
+      break;
+    case IP_EXE:
+      do_exe = true;
+      break;
+    case IP_CWD:
+      do_cwd = true;
+      break;
+    case IP_ALL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+#ifdef HAVE_KINFO_GETVMMAP
+      do_mappings = true;
+#endif
+      do_status = true;
+      break;
+    default:
+      error (_("Not supported on this target."));
+    }
+
+  gdb_argv built_argv (args);
+  if (built_argv.count () == 0)
+    {
+      pid = ptid_get_pid (inferior_ptid);
+      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);
+#ifdef HAVE_KINFO_GETFILE
+  if (do_cwd || do_exe)
+    fdtbl.reset (kinfo_getfile (pid, &nfd));
+#endif
+  if (do_status)
+    {
+      kp_valid = fbsd_fetch_kinfo_proc(pid, &kp);
+      if (!kp_valid)
+ warning (_("Failed to fetch process information"));
+    }
+
+  if (do_cmdline)
+    {
+      gdb::unique_xmalloc_ptr<char> cmdline = fbsd_fetch_cmdline (pid);
+      if (cmdline != nullptr)
+ printf_filtered ("cmdline = '%s'\n", cmdline.get ());
+      else
+ warning (_("unable to fetch command line"));
+    }
+  if (do_cwd)
+    {
+      const char *cwd = NULL;
+#ifdef HAVE_KINFO_GETFILE
+      struct kinfo_file *kf = fdtbl.get ();
+      for (int i = 0; i < nfd; i++, kf++)
+ {
+  if (kf->kf_type == KF_TYPE_VNODE && kf->kf_fd == KF_FD_TYPE_CWD)
+    {
+      cwd = kf->kf_path;
+      break;
+    }
+ }
+#endif
+      if (cwd != NULL)
+ printf_filtered ("cwd = '%s'\n", cwd);
+      else
+ warning (_("unable to fetch current working directory"));
+    }
+  if (do_exe)
+    {
+      const char *exe = NULL;
+#ifdef HAVE_KINFO_GETFILE
+      struct kinfo_file *kf = fdtbl.get ();
+      for (int i = 0; i < nfd; i++, kf++)
+ {
+  if (kf->kf_type == KF_TYPE_VNODE && kf->kf_fd == KF_FD_TYPE_TEXT)
+    {
+      exe = kf->kf_path;
+      break;
+    }
+ }
+#endif
+      if (exe == NULL)
+ exe = fbsd_pid_to_exec_file (ops, pid);
+      if (exe != NULL)
+ printf_filtered ("exe = '%s'\n", exe);
+      else
+ warning (_("unable to fetch executable path name"));
+    }
+#ifdef HAVE_KINFO_GETVMMAP
+  if (do_mappings)
+    {
+      int nvment;
+      gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
+ vmentl (kinfo_getvmmap (pid, &nvment));
+
+      if (vmentl != nullptr)
+ {
+  printf_filtered (_("Mapped address spaces:\n\n"));
+#ifdef __LP64__
+  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");
+#endif
+
+  struct kinfo_vmentry *kve = vmentl.get ();
+  for (int i = 0; i < nvment; i++, kve++)
+    {
+      ULONGEST start, end;
+
+      start = kve->kve_start;
+      end = kve->kve_end;
+#ifdef __LP64__
+      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
+       hex_string (start),
+       hex_string (end),
+       hex_string (end - start),
+       hex_string (kve->kve_offset),
+       fbsd_vm_map_entry_flags (kve->kve_flags,
+ kve->kve_protection),
+       kve->kve_path);
+#else
+      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
+       hex_string (start),
+       hex_string (end),
+       hex_string (end - start),
+       hex_string (kve->kve_offset),
+       fbsd_vm_map_entry_flags (kve->kve_flags,
+ kve->kve_protection),
+       kve->kve_path);
+#endif
+    }
+ }
+      else
+ warning (_("unable to fetch virtual memory map"));
+    }
+#endif
+  if (do_status)
+    {
+      if (!fbsd_fetch_kinfo_proc(pid, &kp))
+ warning (_("Failed to fetch process information"));
+      else
+ {
+  const char *state;
+  int pgtok;
+
+  printf_filtered ("Name: %s\n", kp.ki_comm);
+  switch (kp.ki_stat)
+    {
+    case SIDL:
+      state = "I (idle)";
+      break;
+    case SRUN:
+      state = "R (running)";
+      break;
+    case SSTOP:
+      state = "T (stopped)";
+      break;
+    case SZOMB:
+      state = "Z (zombie)";
+      break;
+    case SSLEEP:
+      state = "S (sleeping)";
+      break;
+    case SWAIT:
+      state = "W (interrupt wait)";
+      break;
+    case SLOCK:
+      state = "L (blocked on lock)";
+      break;
+    default:
+      state = "? (unknown)";
+      break;
+    }
+  printf_filtered ("State: %s\n", state);
+  printf_filtered ("Parent process: %d\n", kp.ki_ppid);
+  printf_filtered ("Process group: %d\n", kp.ki_pgid);
+  printf_filtered ("Session id: %d\n", kp.ki_sid);
+  printf_filtered ("TTY: %ju\n", (uintmax_t) kp.ki_tdev);
+  printf_filtered ("TTY owner process group: %d\n", kp.ki_tpgid);
+  printf_filtered ("User IDs (real, effective, saved): %d %d %d\n",
+   kp.ki_ruid, kp.ki_uid, kp.ki_svuid);
+  printf_filtered ("Group IDs (real, effective, saved): %d %d %d\n",
+   kp.ki_rgid, kp.ki_groups[0], kp.ki_svgid);
+  printf_filtered ("Groups: ");
+  for (int i = 0; i < kp.ki_ngroups; i++)
+    printf_filtered ("%d ", kp.ki_groups[i]);
+  printf_filtered ("\n");
+  printf_filtered ("Minor faults (no memory page): %ld\n",
+   kp.ki_rusage.ru_minflt);
+  printf_filtered ("Minor faults, children: %ld\n",
+   kp.ki_rusage_ch.ru_minflt);
+  printf_filtered ("Major faults (memory page faults): %ld\n",
+   kp.ki_rusage.ru_majflt);
+  printf_filtered ("Major faults, children: %ld\n",
+   kp.ki_rusage_ch.ru_majflt);
+  printf_filtered ("utime: %jd.%06ld\n",
+   (intmax_t) kp.ki_rusage.ru_utime.tv_sec,
+   kp.ki_rusage.ru_utime.tv_usec);
+  printf_filtered ("stime: %jd.%06ld\n",
+   (intmax_t) kp.ki_rusage.ru_stime.tv_sec,
+   kp.ki_rusage.ru_stime.tv_usec);
+  printf_filtered ("utime, children: %jd.%06ld\n",
+   (intmax_t) kp.ki_rusage_ch.ru_utime.tv_sec,
+   kp.ki_rusage_ch.ru_utime.tv_usec);
+  printf_filtered ("stime, children: %jd.%06ld\n",
+   (intmax_t) kp.ki_rusage_ch.ru_stime.tv_sec,
+   kp.ki_rusage_ch.ru_stime.tv_usec);
+  printf_filtered ("'nice' value: %d\n", kp.ki_nice);
+  printf_filtered ("Start time: %jd.%06ld\n", kp.ki_start.tv_sec,
+   kp.ki_start.tv_usec);
+  pgtok = getpagesize () / 1024;
+  printf_filtered ("Virtual memory size: %ju kB\n",
+   (uintmax_t) kp.ki_size / 1024);
+  printf_filtered ("Data size: %ju kB\n",
+   (uintmax_t) kp.ki_dsize * pgtok);
+  printf_filtered ("Stack size: %ju kB\n",
+   (uintmax_t) kp.ki_ssize * pgtok);
+  printf_filtered ("Text size: %ju kB\n",
+   (uintmax_t) kp.ki_tsize * pgtok);
+  printf_filtered ("Resident set size: %ju kB\n",
+   (uintmax_t) kp.ki_rssize * pgtok);
+  printf_filtered ("Maximum RSS: %ju kB\n",
+   (uintmax_t) kp.ki_rusage.ru_maxrss);
+  printf_filtered ("Pending Signals: ");
+  for (int i = 0; i < _SIG_WORDS; i++)
+    printf_filtered ("%08x ", kp.ki_siglist.__bits[i]);
+  printf_filtered ("\n");
+  printf_filtered ("Ignored Signals: ");
+  for (int i = 0; i < _SIG_WORDS; i++)
+    printf_filtered ("%08x ", kp.ki_sigignore.__bits[i]);
+  printf_filtered ("\n");
+  printf_filtered ("Caught Signals: ");
+  for (int i = 0; i < _SIG_WORDS; i++)
+    printf_filtered ("%08x ", kp.ki_sigcatch.__bits[i]);
+  printf_filtered ("\n");
+ }
+    }
+}
+
 #ifdef KERN_PROC_AUXV
 static enum target_xfer_status (*super_xfer_partial) (struct target_ops *ops,
       enum target_object object,
@@ -452,26 +786,6 @@ show_fbsd_lwp_debug (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("Debugging of FreeBSD lwp module is %s.\n"), value);
 }
 
-#if defined(TDP_RFPPWAIT) || defined(HAVE_STRUCT_PTRACE_LWPINFO_PL_TDNAME)
-/* Fetch the external variant of the kernel's internal process
-   structure for the process PID into KP.  */
-
-static void
-fbsd_fetch_kinfo_proc (pid_t pid, struct kinfo_proc *kp)
-{
-  size_t len;
-  int mib[4];
-
-  len = sizeof *kp;
-  mib[0] = CTL_KERN;
-  mib[1] = KERN_PROC;
-  mib[2] = KERN_PROC_PID;
-  mib[3] = pid;
-  if (sysctl (mib, 4, kp, &len, NULL, 0) == -1)
-    perror_with_name (("sysctl"));
-}
-#endif
-
 /*
   FreeBSD's first thread support was via a "reentrant" version of libc
   (libc_r) that first shipped in 2.2.7.  This library multiplexed all
@@ -557,7 +871,8 @@ fbsd_thread_name (struct target_ops *self, struct thread_info *thr)
   /* Note that ptrace_lwpinfo returns the process command in pl_tdname
      if a name has not been set explicitly.  Return a NULL name in
      that case.  */
-  fbsd_fetch_kinfo_proc (pid, &kp);
+  if (!fbsd_fetch_kinfo_proc (pid, &kp))
+    perror_with_name (_("Failed to fetch process information"));
   if (ptrace (PT_LWPINFO, lwp, (caddr_t) &pl, sizeof pl) == -1)
     perror_with_name (("ptrace"));
   if (strcmp (kp.ki_comm, pl.pl_tdname) == 0)
@@ -967,9 +1282,13 @@ fbsd_wait (struct target_ops *ops,
 #ifndef PTRACE_VFORK
       /* For vfork, the child process will have the P_PPWAIT
  flag set.  */
-      fbsd_fetch_kinfo_proc (child, &kp);
-      if (kp.ki_flag & P_PPWAIT)
- ourstatus->kind = TARGET_WAITKIND_VFORKED;
+      if (fbsd_fetch_kinfo_proc (child, &kp))
+ {
+  if (kp.ki_flag & P_PPWAIT)
+    ourstatus->kind = TARGET_WAITKIND_VFORKED;
+ }
+      else
+ warning (_("Failed to fetch process information"));
 #endif
       ourstatus->value.related_pid = child_ptid;
 
@@ -1173,6 +1492,7 @@ fbsd_nat_add_target (struct target_ops *t)
 {
   t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
   t->to_find_memory_regions = fbsd_find_memory_regions;
+  t->to_info_proc = fbsd_info_proc;
 #ifdef KERN_PROC_AUXV
   super_xfer_partial = t->to_xfer_partial;
   t->to_xfer_partial = fbsd_xfer_partial;
--
2.15.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 5/5] Document support for 'info proc' on FreeBSD.

John Baldwin
In reply to this post by John Baldwin
Since the 'info proc' support on FreeBSD does not use /proc, reword
the documentation for 'info proc' to not assume /proc.  This includes
renaming the node to 'Process Information' and suggesting that
additional process information can be queried via different
OS-specific interfaces.  This is also cleans up the description of
'info proc' support for core files a bit as /proc is not used for core
file support on any current platform.

gdb/doc/ChangeLog:

        * gdb.texinfo (pwd): Update cross-reference for Process Information
        node and remove explicit /proc reference.
        (Native): Rename subsection from SVR4 Process Information to
        Process Information.
        (Process Information): Reword introduction to be less /proc
        centric.  Document support for "info proc" on FreeBSD.
---
 gdb/doc/ChangeLog   |  9 +++++++
 gdb/doc/gdb.texinfo | 76 +++++++++++++++++++++++++++++++----------------------
 2 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 5a3437cd32..b4e214cc06 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,12 @@
+2018-01-03  John Baldwin  <[hidden email]>
+
+ * gdb.texinfo (pwd): Update cross-reference for Process Information
+ node and remove explicit /proc reference.
+ (Native): Rename subsection from SVR4 Process Information to
+ Process Information.
+ (Process Information): Reword introduction to be less /proc
+ centric.  Document support for "info proc" on FreeBSD.
+
 2018-01-03  Xavier Roirand  <[hidden email]>
 
  * gdb.texinfo (Set Catchpoints): Add documentation for new
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8bdafb0ba4..096c82cc82 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -2523,9 +2523,9 @@ Print the @value{GDBN} working directory.
 
 It is generally impossible to find the current working directory of
 the process being debugged (since a program can change its directory
-during its run).  If you work on a system where @value{GDBN} is
-configured with the @file{/proc} support, you can use the @code{info
-proc} command (@pxref{SVR4 Process Information}) to find out the
+during its run).  If you work on a system where @value{GDBN} supports
+the @code {info proc} command (@pxref{Process Information}), you can
+use the @code{info proc} command to find out the
 current working directory of the debuggee.
 
 @node Input/Output
@@ -21712,7 +21712,7 @@ configurations.
 
 @menu
 * BSD libkvm Interface:: Debugging BSD kernel memory images
-* SVR4 Process Information::    SVR4 process information
+* Process Information::         Process information
 * DJGPP Native::                Features specific to the DJGPP port
 * Cygwin Native:: Features specific to the Cygwin port
 * Hurd Native::                 Features specific to @sc{gnu} Hurd
@@ -21759,24 +21759,32 @@ Set current context from proc address.  This command isn't available on
 modern FreeBSD systems.
 @end table
 
-@node SVR4 Process Information
-@subsection SVR4 Process Information
+@node Process Information
+@subsection Process Information
 @cindex /proc
 @cindex examine process image
 @cindex process info via @file{/proc}
 
-Many versions of SVR4 and compatible systems provide a facility called
-@samp{/proc} that can be used to examine the image of a running
-process using file-system subroutines.
+Some operating systems provide interfaces to fetch additional
+information about running processes beyond memory and per-thread
+register state.  If @value{GDBN} is configured for an operating system
+with a supported interface, the command @code{info proc} is available
+to report information about the process running your program, or about
+any process running on your system.
 
-If @value{GDBN} is configured for an operating system with this
-facility, the command @code{info proc} is available to report
-information about the process running your program, or about any
-process running on your system.  This includes, as of this writing,
-@sc{gnu}/Linux and Solaris, for example.
+One supported interface is a facility called @samp{/proc} that can be
+used to examine the image of a running process using file-system
+subroutines.  This facility is supported on @sc{gnu}/Linux and Solaris
+systems.
 
-This command may also work on core files that were created on a system
-that has the @samp{/proc} facility.
+On FreeBSD systems, system control nodes are used to query process
+information.
+
+In addition, some systems may provide additional process information
+in core files.  Note that a core file may include a subset of the
+information available from a live process.  Process information is
+currently avaiable from cores created on @sc{gnu}/Linux and FreeBSD
+systems.
 
 @table @code
 @kindex info proc
@@ -21800,36 +21808,40 @@ a process ID rather than a thread ID).
 @item info proc cmdline
 @cindex info proc cmdline
 Show the original command line of the process.  This command is
-specific to @sc{gnu}/Linux.
+supported on @sc{gnu}/Linux and FreeBSD.
 
 @item info proc cwd
 @cindex info proc cwd
 Show the current working directory of the process.  This command is
-specific to @sc{gnu}/Linux.
+supported on @sc{gnu}/Linux and FreeBSD.
 
 @item info proc exe
 @cindex info proc exe
-Show the name of executable of the process.  This command is specific
-to @sc{gnu}/Linux.
+Show the name of executable of the process.  This command is supported
+on @sc{gnu}/Linux and FreeBSD.
 
 @item info proc mappings
 @cindex memory address space mappings
-Report the memory address space ranges accessible in the program, with
-information on whether the process has read, write, or execute access
-rights to each range.  On @sc{gnu}/Linux systems, each memory range
-includes the object file which is mapped to that range, instead of the
-memory access rights to that range.
+Report the memory address space ranges accessible in the program.  On
+Solaris and FreeBSD systems, each memory range includes information on
+whether the process has read, write, or execute access rights to each
+range.  On @sc{gnu}/Linux and FreeBSD systems, each memory range
+includes the object file which is mapped to that range.
 
 @item info proc stat
 @itemx info proc status
 @cindex process detailed status information
-These subcommands are specific to @sc{gnu}/Linux systems.  They show
-the process-related information, including the user ID and group ID;
-how many threads are there in the process; its virtual memory usage;
-the signals that are pending, blocked, and ignored; its TTY; its
-consumption of system and user time; its stack size; its @samp{nice}
-value; etc.  For more information, see the @samp{proc} man page
-(type @kbd{man 5 proc} from your shell prompt).
+Show additional process-related information, including the user ID and
+group ID; virtual memory usage; the signals that are pending, blocked,
+and ignored; its TTY; its consumption of system and user time; its
+stack size; its @samp{nice} value; etc.  These commands are supported
+on @sc{gnu}/Linux and FreeBSD.
+
+For @sc{gnu}/Linux systems, see the @samp{proc} man page for more
+information (type @kbd{man 5 proc} from your shell prompt).
+
+For FreeBSD systems, @code{info proc stat} is an alias for @code{info
+proc status}.
 
 @item info proc all
 Show all the information about the process described under all of the
--
2.15.1

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 5/5] Document support for 'info proc' on FreeBSD.

Eli Zaretskii
> From: John Baldwin <[hidden email]>
> Date: Wed,  3 Jan 2018 17:49:23 -0800
>
> Since the 'info proc' support on FreeBSD does not use /proc, reword
> the documentation for 'info proc' to not assume /proc.  This includes
> renaming the node to 'Process Information' and suggesting that
> additional process information can be queried via different
> OS-specific interfaces.  This is also cleans up the description of
> 'info proc' support for core files a bit as /proc is not used for core
> file support on any current platform.
>
> gdb/doc/ChangeLog:
>
> * gdb.texinfo (pwd): Update cross-reference for Process Information
> node and remove explicit /proc reference.
> (Native): Rename subsection from SVR4 Process Information to
> Process Information.
> (Process Information): Reword introduction to be less /proc
> centric.  Document support for "info proc" on FreeBSD.

OK, thanks.

Do we need a NEWS entry for this?
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 5/5] Document support for 'info proc' on FreeBSD.

John Baldwin
On Thursday, January 04, 2018 06:38:37 PM Eli Zaretskii wrote:

> > From: John Baldwin <[hidden email]>
> > Date: Wed,  3 Jan 2018 17:49:23 -0800
> >
> > Since the 'info proc' support on FreeBSD does not use /proc, reword
> > the documentation for 'info proc' to not assume /proc.  This includes
> > renaming the node to 'Process Information' and suggesting that
> > additional process information can be queried via different
> > OS-specific interfaces.  This is also cleans up the description of
> > 'info proc' support for core files a bit as /proc is not used for core
> > file support on any current platform.
> >
> > gdb/doc/ChangeLog:
> >
> > * gdb.texinfo (pwd): Update cross-reference for Process Information
> > node and remove explicit /proc reference.
> > (Native): Rename subsection from SVR4 Process Information to
> > Process Information.
> > (Process Information): Reword introduction to be less /proc
> > centric.  Document support for "info proc" on FreeBSD.
>
> OK, thanks.
>
> Do we need a NEWS entry for this?

I suppose so.  I added this to the documentation patch locally:

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5812e8f357..ac2bf57401 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2018-01-04  John Baldwin  <[hidden email]>
+
+       * NEWS: Document that 'info proc' now works on FreeBSD.
+
 2018-01-03  John Baldwin  <[hidden email]>
 
        * configure.ac: Check for kinfo_getfile in libutil.
diff --git a/gdb/NEWS b/gdb/NEWS
index 14fcdf8674..7b415ce6e6 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 8.0
 
+* 'info proc' now works on running processes on FreeBSD systems and core
+  files created on FreeBSD systems.
+
 * GDB now supports dynamically creating arbitrary register groups specified
   in XML target descriptions.  This allows for finer grain grouping of
   registers on systems with a large amount of registers.


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

Re: [PATCH v2 1/5] Support 'info proc' for FreeBSD process core dumps.

Simon Marchi-4
In reply to this post by John Baldwin
Hi John,

I have two little comments, but otherwise it LGTM.

On 2018-01-03 08:49 PM, John Baldwin wrote:
> +/* Implement "info proc status" for a corefile.  */
> +
> +static void
> +fbsd_core_info_proc_status (struct gdbarch *gdbarch)
> +{
> +  const struct kinfo_proc_layout *kp;
> +  asection *section;
> +  const char *state;
> +  unsigned char *descdata, *descend;

I get this:

/home/simark/src/binutils-gdb/gdb/fbsd-tdep.c: In function ‘void fbsd_core_info_proc_status(gdbarch*)’:
/home/simark/src/binutils-gdb/gdb/fbsd-tdep.c:791:29: error: variable ‘descend’ set but not used [-Werror=unused-but-set-variable]
   unsigned char *descdata, *descend;
                             ^~~~~~~

> +  int addr_bit, long_bit;
> +  size_t note_size;
> +  ULONGEST value;
> +  LONGEST sec;
> +
> +  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
> +  if (section == NULL)
> +    {
> +      warning (_("unable to find process info in core file"));
> +      return;
> +    }
> +
> +  addr_bit = gdbarch_addr_bit (gdbarch);
> +  if (addr_bit == 64)
> +    kp = &kinfo_proc_layout_64;
> +  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
> +    kp = &kinfo_proc_layout_i386;
> +  else
> +    kp = &kinfo_proc_layout_32;
> +
> +  note_size = bfd_get_section_size (section);
> +  if (note_size < 4 + kp->ki_rusage_ch + kp->ru_majflt + addr_bit)

What's the rationale behind that computation?  The field ru_majflt in kp->ki_rusage_ch
is the furthest field we'll actually need in this function?  And addr_bit is the size of
that field?  And 4 is because there's a field at the beginning containing the size of
the structure that comes after?

Maybe a small comment would be good to remove the magic.

Thanks,

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 2/5] Don't return stale data from fbsd_pid_to_exec_file for kernel processes.

Simon Marchi-4
In reply to this post by John Baldwin
On 2018-01-03 08:49 PM, John Baldwin wrote:

> For processes without an associated executable (such as kernel processes),
> the kern.proc.pathname.<pid> system control node returns a length of zero
> without modifying the user's buffer.  Detect this case and return NULL
> rather than the previous contents of the static buffer 'buf'.
>
> gdb/ChangeLog:
>
> * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
> NULL for an empty pathname.
> ---
>  gdb/ChangeLog  | 5 +++++
>  gdb/fbsd-nat.c | 2 +-
>  2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 29cfbb287b..804dd4f402 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,8 @@
> +2018-01-03  John Baldwin  <[hidden email]>
> +
> + * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
> + NULL for an empty pathname.
> +
>  2018-01-03  John Baldwin  <[hidden email]>
>  
>   * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
> diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
> index ec4eed9abe..7b1d1bf148 100644
> --- a/gdb/fbsd-nat.c
> +++ b/gdb/fbsd-nat.c
> @@ -63,7 +63,7 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid)
>    mib[3] = pid;
>    buflen = sizeof buf;
>    if (sysctl (mib, 4, buf, &buflen, NULL, 0) == 0)
> -    return buf;
> +    return buflen == 0 ? NULL : buf;
>  #endif
>  
>    xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
>

LGTM, but maybe add a comment saying in what situation the sysctl can
return a buflen of 0.

Does the alternative method that reads from /proc/<pid>/exe work in that
case too?

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 3/5] Use gdb::unique_xmalloc_ptr<> instead of a deleter that invokes free().

Simon Marchi-4
In reply to this post by John Baldwin
On 2018-01-03 08:49 PM, John Baldwin wrote:

> Since xfree() always wraps free(), it is safe to use the xfree deleter
> for buffers allocated by library routines such as kinfo_getvmmap() that
> must be released via free().
>
> gdb/ChangeLog:
>
> * fbsd-nat.c (struct free_deleter): Remove.
> (fbsd_find_memory_regions): Use gdb::unique_xmalloc_ptr<>.
> ---
>  gdb/ChangeLog  |  5 +++++
>  gdb/fbsd-nat.c | 10 +---------
>  2 files changed, 6 insertions(+), 9 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 804dd4f402..cdce396e9c 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,8 @@
> +2018-01-03  John Baldwin  <[hidden email]>
> +
> + * fbsd-nat.c (struct free_deleter): Remove.
> + (fbsd_find_memory_regions): Use gdb::unique_xmalloc_ptr<>.
> +
>  2018-01-03  John Baldwin  <[hidden email]>
>  
>   * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
> diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
> index 7b1d1bf148..00e5cfb55c 100644
> --- a/gdb/fbsd-nat.c
> +++ b/gdb/fbsd-nat.c
> @@ -78,14 +78,6 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid)
>  }
>  
>  #ifdef HAVE_KINFO_GETVMMAP
> -/* Deleter for std::unique_ptr that invokes free.  */
> -
> -template <typename T>
> -struct free_deleter
> -{
> -  void operator() (T *ptr) const { free (ptr); }
> -};
> -
>  /* 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.  */
> @@ -99,7 +91,7 @@ fbsd_find_memory_regions (struct target_ops *self,
>    uint64_t size;
>    int i, nitems;
>  
> -  std::unique_ptr<struct kinfo_vmentry, free_deleter<struct kinfo_vmentry>>
> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry>
>      vmentl (kinfo_getvmmap (pid, &nitems));
>    if (vmentl == NULL)
>      perror_with_name (_("Couldn't fetch VM map entries."));
>

LGTM, unless there's something I really havn't understood about xfree.

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 4/5] Support 'info proc' for native FreeBSD processes.

Simon Marchi-4
In reply to this post by John Baldwin
On 2018-01-03 08:49 PM, John Baldwin wrote:
> - Command line arguments are fetched via the kern.proc.args.<pid>
>   sysctl.
> - The 'cwd' and 'exe' values are obtained from the per-process
>   file descriptor table returned by kinfo_getfile() from libutil.
> - 'mappings' is implemented by walking the array of VM map entries
>   returned by kinfo_getvmmap() from libutil.
> - 'status' output is generated by outputting fields from the structure
>   returned by the kern.proc.pid.<pid> sysctl.
> - 'stat' is aliased to 'status'.

Hi John,

The patch LGTM in general, I noted 2 comments, the first one could be done
as a separate patch (after this series), if you agree with it.  The second,
I'm fine if you just fix it before pushing.

> +  struct kinfo_vmentry *kve = vmentl.get ();
> +  for (int i = 0; i < nvment; i++, kve++)
> +    {
> +      ULONGEST start, end;
> +
> +      start = kve->kve_start;
> +      end = kve->kve_end;
> +#ifdef __LP64__
> +      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
> +       hex_string (start),
> +       hex_string (end),
> +       hex_string (end - start),
> +       hex_string (kve->kve_offset),
> +       fbsd_vm_map_entry_flags (kve->kve_flags,
> + kve->kve_protection),
> +       kve->kve_path);
> +#else
> +      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
> +       hex_string (start),
> +       hex_string (end),
> +       hex_string (end - start),
> +       hex_string (kve->kve_offset),
> +       fbsd_vm_map_entry_flags (kve->kve_flags,
> + kve->kve_protection),
> +       kve->kve_path);
> +#endif
> +    }

It might be a good idea to factor out the printing of vm map entries from here
and the core code, to make sure that they will always be printed the same way.
It's up to you.

> + }
> +      else
> + warning (_("unable to fetch virtual memory map"));
> +    }
> +#endif
> +  if (do_status)
> +    {
> +      if (!fbsd_fetch_kinfo_proc(pid, &kp))

Missing space here.  But didn't we fetch it already (line 329)?
IIUC, we only need it in this scope, so you could move the
relevant variables here, and only call fbsd_fetch_kinfo_proc here.
I suppose it needed to be this way when stat and status were not
merged.

> + warning (_("Failed to fetch process information"));
> +      else

Thanks,

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 5/5] Document support for 'info proc' on FreeBSD.

Eli Zaretskii
In reply to this post by John Baldwin
> From: John Baldwin <[hidden email]>
> Cc: [hidden email]
> Date: Thu, 04 Jan 2018 13:27:27 -0800
>
> > Do we need a NEWS entry for this?
>
> I suppose so.  I added this to the documentation patch locally:

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v2 2/5] Don't return stale data from fbsd_pid_to_exec_file for kernel processes.

John Baldwin
In reply to this post by Simon Marchi-4
On Thursday, January 04, 2018 09:57:00 PM Simon Marchi wrote:

> On 2018-01-03 08:49 PM, John Baldwin wrote:
> > For processes without an associated executable (such as kernel processes),
> > the kern.proc.pathname.<pid> system control node returns a length of zero
> > without modifying the user's buffer.  Detect this case and return NULL
> > rather than the previous contents of the static buffer 'buf'.
> >
> > gdb/ChangeLog:
> >
> > * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
> > NULL for an empty pathname.
> > ---
> >  gdb/ChangeLog  | 5 +++++
> >  gdb/fbsd-nat.c | 2 +-
> >  2 files changed, 6 insertions(+), 1 deletion(-)
> >
> > diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> > index 29cfbb287b..804dd4f402 100644
> > --- a/gdb/ChangeLog
> > +++ b/gdb/ChangeLog
> > @@ -1,3 +1,8 @@
> > +2018-01-03  John Baldwin  <[hidden email]>
> > +
> > + * fbsd-nat.c (fbsd_pid_to_exec_file) [KERN_PROC_PATHNAME]: Return
> > + NULL for an empty pathname.
> > +
> >  2018-01-03  John Baldwin  <[hidden email]>
> >  
> >   * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
> > diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
> > index ec4eed9abe..7b1d1bf148 100644
> > --- a/gdb/fbsd-nat.c
> > +++ b/gdb/fbsd-nat.c
> > @@ -63,7 +63,7 @@ fbsd_pid_to_exec_file (struct target_ops *self, int pid)
> >    mib[3] = pid;
> >    buflen = sizeof buf;
> >    if (sysctl (mib, 4, buf, &buflen, NULL, 0) == 0)
> > -    return buf;
> > +    return buflen == 0 ? NULL : buf;
> >  #endif
> >  
> >    xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
> >
>
> LGTM, but maybe add a comment saying in what situation the sysctl can
> return a buflen of 0.

Ok.

> Does the alternative method that reads from /proc/<pid>/exe work in that
> case too?

No.  FreeBSD systems don't generally mount /proc (it's not enabled in the
default install), but in the case that 0 is returned, the relevant pointer
in the process structure (p_textvp) that '/proc/%d/exe' returns a path for
is NULL, so the procfs method will also fail.

Actually, I looked at FreeBSD's procfs and the node is named /proc/%d/file,
not /proc/%d/exe.  I did confirm that FreeBSD's procfs does not create
'file' nodes for kernel processes (but also not for init (pid 1)).

I should in fact probably refine this function further to only use procfs
in the #else case if not remove it all together: the last release to not
include the pathname sysctl was FreeBSD 5.5 released in May 2006.

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

Re: [PATCH v2 4/5] Support 'info proc' for native FreeBSD processes.

John Baldwin
In reply to this post by Simon Marchi-4
On Thursday, January 04, 2018 10:20:05 PM Simon Marchi wrote:

> On 2018-01-03 08:49 PM, John Baldwin wrote:
> > - Command line arguments are fetched via the kern.proc.args.<pid>
> >   sysctl.
> > - The 'cwd' and 'exe' values are obtained from the per-process
> >   file descriptor table returned by kinfo_getfile() from libutil.
> > - 'mappings' is implemented by walking the array of VM map entries
> >   returned by kinfo_getvmmap() from libutil.
> > - 'status' output is generated by outputting fields from the structure
> >   returned by the kern.proc.pid.<pid> sysctl.
> > - 'stat' is aliased to 'status'.
>
> Hi John,
>
> The patch LGTM in general, I noted 2 comments, the first one could be done
> as a separate patch (after this series), if you agree with it.  The second,
> I'm fine if you just fix it before pushing.
>
> > +  struct kinfo_vmentry *kve = vmentl.get ();
> > +  for (int i = 0; i < nvment; i++, kve++)
> > +    {
> > +      ULONGEST start, end;
> > +
> > +      start = kve->kve_start;
> > +      end = kve->kve_end;
> > +#ifdef __LP64__
> > +      printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
> > +       hex_string (start),
> > +       hex_string (end),
> > +       hex_string (end - start),
> > +       hex_string (kve->kve_offset),
> > +       fbsd_vm_map_entry_flags (kve->kve_flags,
> > + kve->kve_protection),
> > +       kve->kve_path);
> > +#else
> > +      printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
> > +       hex_string (start),
> > +       hex_string (end),
> > +       hex_string (end - start),
> > +       hex_string (kve->kve_offset),
> > +       fbsd_vm_map_entry_flags (kve->kve_flags,
> > + kve->kve_protection),
> > +       kve->kve_path);
> > +#endif
> > +    }
>
> It might be a good idea to factor out the printing of vm map entries from here
> and the core code, to make sure that they will always be printed the same way.
> It's up to you.

So I thought about that (and that's why the fbsd_vm_map_entry_flags is shared
in fbsd-tdep.c).  I would perhaps need some way to tell the common code which
layout to use as it's based on gdbarch_addr_bit() in the tdep code but uses
an #ifdef in this version.  I also considered doing this for the 'status'
implementation, but I would probably need to export the 'kinfo_proc_layout'
structures from the tdep file and use an #ifdef in the native target to choose
which layout to use.  The 'status' is also a bit trickier as some fields are
printed for native but not for cores, and the native version uses getpagesize()
to convert page counts to Kb that the core version can't do.  Merging the
'mappings' probably is more doable though than 'status' as it really just
needs 'addr_bit' passed in.  (I believe I can't quite pass in 'target_gdbarch()'
since I might be attached to a 32-bit process but be running 'info proc mappings'
with the PID of a 64-bit processes for which target_gdbarch() would be wrong.)

> > + }
> > +      else
> > + warning (_("unable to fetch virtual memory map"));
> > +    }
> > +#endif
> > +  if (do_status)
> > +    {
> > +      if (!fbsd_fetch_kinfo_proc(pid, &kp))
>
> Missing space here.  But didn't we fetch it already (line 329)?
> IIUC, we only need it in this scope, so you could move the
> relevant variables here, and only call fbsd_fetch_kinfo_proc here.
> I suppose it needed to be this way when stat and status were not
> merged.

Oh, whoops, I missed finishing that cleanup when collapsing down to a single
'status'. :-/  Yes, the intention was to remove 'kp_valid' entirely.

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

Re: [PATCH v2 1/5] Support 'info proc' for FreeBSD process core dumps.

John Baldwin
In reply to this post by Simon Marchi-4
On Thursday, January 04, 2018 09:53:47 PM Simon Marchi wrote:

> Hi John,
>
> I have two little comments, but otherwise it LGTM.
>
> On 2018-01-03 08:49 PM, John Baldwin wrote:
> > +/* Implement "info proc status" for a corefile.  */
> > +
> > +static void
> > +fbsd_core_info_proc_status (struct gdbarch *gdbarch)
> > +{
> > +  const struct kinfo_proc_layout *kp;
> > +  asection *section;
> > +  const char *state;
> > +  unsigned char *descdata, *descend;
>
> I get this:
>
> /home/simark/src/binutils-gdb/gdb/fbsd-tdep.c: In function ‘void fbsd_core_info_proc_status(gdbarch*)’:
> /home/simark/src/binutils-gdb/gdb/fbsd-tdep.c:791:29: error: variable ‘descend’ set but not used [-Werror=unused-but-set-variable]
>    unsigned char *descdata, *descend;
>                              ^~~~~~~

Oops, too much copy and paste (and I've only been building with clang so far).

> > +  int addr_bit, long_bit;
> > +  size_t note_size;
> > +  ULONGEST value;
> > +  LONGEST sec;
> > +
> > +  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
> > +  if (section == NULL)
> > +    {
> > +      warning (_("unable to find process info in core file"));
> > +      return;
> > +    }
> > +
> > +  addr_bit = gdbarch_addr_bit (gdbarch);
> > +  if (addr_bit == 64)
> > +    kp = &kinfo_proc_layout_64;
> > +  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
> > +    kp = &kinfo_proc_layout_i386;
> > +  else
> > +    kp = &kinfo_proc_layout_32;
> > +
> > +  note_size = bfd_get_section_size (section);
> > +  if (note_size < 4 + kp->ki_rusage_ch + kp->ru_majflt + addr_bit)
>
> What's the rationale behind that computation?  The field ru_majflt in kp->ki_rusage_ch
> is the furthest field we'll actually need in this function?  And addr_bit is the size of
> that field?  And 4 is because there's a field at the beginning containing the size of
> the structure that comes after?

Correct.  This is the bounds check to avoid overflowing the note buffer,
but it does warrany a comment to explain what it is doing.  And actually,
writing that comment made me realize a bug.  It should be 'addr_bit /
TARGET_CHAR_BIT', not addr_bit directly.  Also, I noticed that the
'long_bit' variable at the start of the quoted section above also isn't
used, but it's probably cleaner to be explicit and assign it to
gdbarch_long_bit() and use it in place of addr_bit for structure members
that are of type long rather than assuming addr_bit == long_bit (even
though that is true on all of the architectures FreeBSD supports or is
likely to support).

Ends up like this:

commit b64825d47b446c6a160a2bf28b62641492d07d82
Author: John Baldwin <[hidden email]>
Date:   Fri Jan 5 11:19:02 2018 -0800

    Support 'info proc' for FreeBSD process core dumps.
   
    - Command line arguments are obtained from the pr_psargs[] array
      saved in the NT_PRPSINFO note.
    - The 'cwd' and 'exe' values are obtained from the per-process file
      descriptor table stored in the NT_PROCSTAT_FILES core note.
    - 'mappings' is implemented by walking the array of VM map entries
      stored in the NT_PROCSTAT_VMMAP core note.
    - 'status' output is generated by outputting fields from
      the first structure stored in the NT_PROCSTAT_PROC core note.
    - 'stat' is aliased to 'status'.
   
    gdb/ChangeLog:
   
            * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
            (KVE_FLAGS, KVE_PROTECTION, KVE_PATH, 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_SUPER, KINFO_VME_FLAG_GROWS_UP)
            (KINFO_VME_FLAG_GROWS_DOWN, KF_STRUCTSIZE, KF_TYPE, KF_FD)
            (KF_PATH, KINFO_FILE_TYPE_VNODE, KINFO_FILE_FD_TYPE_CWD)
            (KINFO_FILE_FD_TYPE_TEXT, SIG_WORDS, struct kinfo_proc_layout)
            (kinfo_proc_layout_32, kinfo_proc_layout_i386)
            (kinfo_proc_layout_64, fbsd_vm_map_entry_flags)
            (fbsd_core_info_proc_mappings, fbsd_core_vnode_path)
            (fbsd_core_fetch_timeval, fbsd_print_sigset)
            (fbsd_core_info_proc_status, fbsd_core_info_proc): New.
            (fbsd_init_abi):  Install gdbarch "core_info_proc" method.
            * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 24ccfe6882..dfdf4336ff 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,21 @@
+2018-01-05  John Baldwin  <[hidden email]>
+
+ * fbsd-tdep.c (KVE_STRUCTSIZE, KVE_START, KVE_END, KVE_OFFSET)
+ (KVE_FLAGS, KVE_PROTECTION, KVE_PATH, 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_SUPER, KINFO_VME_FLAG_GROWS_UP)
+ (KINFO_VME_FLAG_GROWS_DOWN, KF_STRUCTSIZE, KF_TYPE, KF_FD)
+ (KF_PATH, KINFO_FILE_TYPE_VNODE, KINFO_FILE_FD_TYPE_CWD)
+ (KINFO_FILE_FD_TYPE_TEXT, SIG_WORDS, struct kinfo_proc_layout)
+ (kinfo_proc_layout_32, kinfo_proc_layout_i386)
+ (kinfo_proc_layout_64, fbsd_vm_map_entry_flags)
+ (fbsd_core_info_proc_mappings, fbsd_core_vnode_path)
+ (fbsd_core_fetch_timeval, fbsd_print_sigset)
+ (fbsd_core_info_proc_status, fbsd_core_info_proc): New.
+ (fbsd_init_abi):  Install gdbarch "core_info_proc" method.
+ * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.
+
 2018-01-05  Pedro Alves  <[hidden email]>
 
  PR gdb/18653
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index ce17c672d9..8aa0243d54 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -52,6 +52,228 @@
 #define SIZE64_SIGINFO_T 80
 #define SIZE32_SIGINFO_T 64
 
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_VMMAP core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_vmentry.  This data structure should have the same layout on
+   all architectures.  */
+
+#define KVE_STRUCTSIZE 0x0
+#define KVE_START 0x8
+#define KVE_END 0x10
+#define KVE_OFFSET 0x18
+#define KVE_FLAGS 0x2c
+#define KVE_PROTECTION 0x56
+#define KVE_PATH 0x88
+
+/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
+   match the KVME_PROT_* constants in <sys/user.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/user.h>.  */
+
+#define KINFO_VME_FLAG_COW 0x00000001
+#define KINFO_VME_FLAG_NEEDS_COPY 0x00000002
+#define KINFO_VME_FLAG_NOCOREDUMP 0x00000004
+#define KINFO_VME_FLAG_SUPER 0x00000008
+#define KINFO_VME_FLAG_GROWS_UP 0x00000010
+#define KINFO_VME_FLAG_GROWS_DOWN 0x00000020
+
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_FILES core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_file.  This data structure should have the same layout on all
+   architectures.  */
+
+#define KF_STRUCTSIZE 0x0
+#define KF_TYPE 0x4
+#define KF_FD 0x8
+#define KF_PATH 0x170
+
+/* Constants for the 'kf_type' field in struct kinfo_file.  These
+   match the KF_TYPE_* constants in <sys/user.h>.  */
+
+#define KINFO_FILE_TYPE_VNODE 1
+
+/* Special values for the 'kf_fd' field in struct kinfo_file.  These
+   match the KF_FD_TYPE_* constants in <sys/user.h>.  */
+
+#define KINFO_FILE_FD_TYPE_CWD -1
+#define KINFO_FILE_FD_TYPE_TEXT -5
+
+/* Number of 32-bit words in a signal set.  This matches _SIG_WORDS in
+   <sys/_sigset.h> and is the same value on all architectures.  */
+
+#define SIG_WORDS 4
+
+/* Offsets in data structure used in NT_FREEBSD_PROCSTAT_PROC core
+   dump notes.  See <sys/user.h> for the definition of struct
+   kinfo_proc.  This data structure has different layouts on different
+   architectures mostly due to ILP32 vs LP64.  However, FreeBSD/i386
+   uses a 32-bit time_t while all other architectures use a 64-bit
+   time_t.
+
+   The core dump note actually contains one kinfo_proc structure for
+   each thread, but all of the process-wide data can be obtained from
+   the first structure.  One result of this note's format is that some
+   of the process-wide status available in the native target method
+   from the kern.proc.pid.<pid> sysctl such as ki_stat and ki_siglist
+   is not available from a core dump.  Instead, the per-thread data
+   structures contain the value of these fields for individual
+   threads.  */
+
+struct kinfo_proc_layout
+{
+  /* Offsets of struct kinfo_proc members.  */
+  int ki_layout;
+  int ki_pid;
+  int ki_ppid;
+  int ki_pgid;
+  int ki_tpgid;
+  int ki_sid;
+  int ki_tdev_freebsd11;
+  int ki_sigignore;
+  int ki_sigcatch;
+  int ki_uid;
+  int ki_ruid;
+  int ki_svuid;
+  int ki_rgid;
+  int ki_svgid;
+  int ki_ngroups;
+  int ki_groups;
+  int ki_size;
+  int ki_rssize;
+  int ki_tsize;
+  int ki_dsize;
+  int ki_ssize;
+  int ki_start;
+  int ki_nice;
+  int ki_comm;
+  int ki_tdev;
+  int ki_rusage;
+  int ki_rusage_ch;
+
+  /* Offsets of struct rusage members.  */
+  int ru_utime;
+  int ru_stime;
+  int ru_maxrss;
+  int ru_minflt;
+  int ru_majflt;
+};
+
+const struct kinfo_proc_layout kinfo_proc_layout_32 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x28,
+    .ki_ppid = 0x2c,
+    .ki_pgid = 0x30,
+    .ki_tpgid = 0x34,
+    .ki_sid = 0x38,
+    .ki_tdev_freebsd11 = 0x44,
+    .ki_sigignore = 0x68,
+    .ki_sigcatch = 0x78,
+    .ki_uid = 0x88,
+    .ki_ruid = 0x8c,
+    .ki_svuid = 0x90,
+    .ki_rgid = 0x94,
+    .ki_svgid = 0x98,
+    .ki_ngroups = 0x9c,
+    .ki_groups = 0xa0,
+    .ki_size = 0xe0,
+    .ki_rssize = 0xe4,
+    .ki_tsize = 0xec,
+    .ki_dsize = 0xf0,
+    .ki_ssize = 0xf4,
+    .ki_start = 0x118,
+    .ki_nice = 0x145,
+    .ki_comm = 0x17f,
+    .ki_tdev = 0x1f0,
+    .ki_rusage = 0x220,
+    .ki_rusage_ch = 0x278,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x10,
+    .ru_maxrss = 0x20,
+    .ru_minflt = 0x30,
+    .ru_majflt = 0x34,
+  };
+
+const struct kinfo_proc_layout kinfo_proc_layout_i386 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x28,
+    .ki_ppid = 0x2c,
+    .ki_pgid = 0x30,
+    .ki_tpgid = 0x34,
+    .ki_sid = 0x38,
+    .ki_tdev_freebsd11 = 0x44,
+    .ki_sigignore = 0x68,
+    .ki_sigcatch = 0x78,
+    .ki_uid = 0x88,
+    .ki_ruid = 0x8c,
+    .ki_svuid = 0x90,
+    .ki_rgid = 0x94,
+    .ki_svgid = 0x98,
+    .ki_ngroups = 0x9c,
+    .ki_groups = 0xa0,
+    .ki_size = 0xe0,
+    .ki_rssize = 0xe4,
+    .ki_tsize = 0xec,
+    .ki_dsize = 0xf0,
+    .ki_ssize = 0xf4,
+    .ki_start = 0x118,
+    .ki_nice = 0x135,
+    .ki_comm = 0x16f,
+    .ki_tdev = 0x1e0,
+    .ki_rusage = 0x210,
+    .ki_rusage_ch = 0x258,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x8,
+    .ru_maxrss = 0x10,
+    .ru_minflt = 0x20,
+    .ru_majflt = 0x24,
+  };
+
+const struct kinfo_proc_layout kinfo_proc_layout_64 =
+  {
+    .ki_layout = 0x4,
+    .ki_pid = 0x48,
+    .ki_ppid = 0x4c,
+    .ki_pgid = 0x50,
+    .ki_tpgid = 0x54,
+    .ki_sid = 0x58,
+    .ki_tdev_freebsd11 = 0x64,
+    .ki_sigignore = 0x88,
+    .ki_sigcatch = 0x98,
+    .ki_uid = 0xa8,
+    .ki_ruid = 0xac,
+    .ki_svuid = 0xb0,
+    .ki_rgid = 0xb4,
+    .ki_svgid = 0xb8,
+    .ki_ngroups = 0xbc,
+    .ki_groups = 0xc0,
+    .ki_size = 0x100,
+    .ki_rssize = 0x108,
+    .ki_tsize = 0x118,
+    .ki_dsize = 0x120,
+    .ki_ssize = 0x128,
+    .ki_start = 0x150,
+    .ki_nice = 0x185,
+    .ki_comm = 0x1bf,
+    .ki_tdev = 0x230,
+    .ki_rusage = 0x260,
+    .ki_rusage_ch = 0x2f0,
+
+    .ru_utime = 0x0,
+    .ru_stime = 0x10,
+    .ru_maxrss = 0x20,
+    .ru_minflt = 0x40,
+    .ru_majflt = 0x48,
+  };
+
 static struct gdbarch_data *fbsd_gdbarch_data_handle;
 
 struct fbsd_gdbarch_data
@@ -367,6 +589,433 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   return note_data;
 }
 
+/* Helper function to generate mappings flags for a single VM map
+   entry in 'info proc mappings'.  */
+
+const char *
+fbsd_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_SUPER) ? 'S' : '-';
+  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;
+}
+
+/* Implement "info proc mappings" for a corefile.  */
+
+static void
+fbsd_core_info_proc_mappings (struct gdbarch *gdbarch)
+{
+  asection *section;
+  unsigned char *descdata, *descend;
+  size_t note_size;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.vmmap");
+  if (section == NULL)
+    {
+      warning (_("unable to find mappings in core file"));
+      return;
+    }
+
+  note_size = bfd_get_section_size (section);
+  if (note_size < 4)
+    error (_("malformed core note - too short for header"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+  descend = descdata + note_size;
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (gdbarch_addr_bit (gdbarch) == 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");
+    }
+
+  while (descdata + KVE_PATH < descend)
+    {
+      ULONGEST start, end, offset, flags, prot, structsize;
+
+      structsize = bfd_get_32 (core_bfd, descdata + KVE_STRUCTSIZE);
+      if (structsize < KVE_PATH)
+ error (_("malformed core note - vmmap entry too small"));
+
+      start = bfd_get_64 (core_bfd, descdata + KVE_START);
+      end = bfd_get_64 (core_bfd, descdata + KVE_END);
+      offset = bfd_get_64 (core_bfd, descdata + KVE_OFFSET);
+      flags = bfd_get_32 (core_bfd, descdata + KVE_FLAGS);
+      prot = bfd_get_32 (core_bfd, descdata + KVE_PROTECTION);
+      if (gdbarch_addr_bit (gdbarch) == 64)
+ {
+  printf_filtered ("  %18s %18s %10s %10s %9s %s\n",
+   paddress (gdbarch, start),
+   paddress (gdbarch, end),
+   hex_string (end - start),
+   hex_string (offset),
+   fbsd_vm_map_entry_flags (flags, prot),
+   descdata + KVE_PATH);
+ }
+      else
+ {
+  printf_filtered ("\t%10s %10s %10s %10s %9s %s\n",
+   paddress (gdbarch, start),
+   paddress (gdbarch, end),
+   hex_string (end - start),
+   hex_string (offset),
+   fbsd_vm_map_entry_flags (flags, prot),
+   descdata + KVE_PATH);
+ }
+
+      descdata += structsize;
+    }
+}
+
+/* Fetch the pathname of a vnode for a single file descriptor from the
+   file table core note.  */
+
+static gdb::unique_xmalloc_ptr<char>
+fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd)
+{
+  asection *section;
+  unsigned char *descdata, *descend;
+  size_t note_size;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.files");
+  if (section == NULL)
+    return nullptr;
+
+  note_size = bfd_get_section_size (section);
+  if (note_size < 4)
+    error (_("malformed core note - too short for header"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+  descend = descdata + note_size;
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  while (descdata + KVE_PATH < descend)
+    {
+      ULONGEST structsize;
+
+      structsize = bfd_get_32 (core_bfd, descdata + KF_STRUCTSIZE);
+      if (structsize < KVE_PATH)
+ error (_("malformed core note - vmmap entry too small"));
+
+      if (bfd_get_32 (core_bfd, descdata + KF_TYPE) == KINFO_FILE_TYPE_VNODE
+  && bfd_get_signed_32 (core_bfd, descdata + KF_FD) == fd)
+ {
+  char *path = (char *) descdata + KF_PATH;
+  return gdb::unique_xmalloc_ptr<char> (xstrdup (path));
+ }
+
+      descdata += structsize;
+    }
+  return nullptr;
+}
+
+/* Helper function to read a struct timeval.  */
+
+static void
+fbsd_core_fetch_timeval (struct gdbarch *gdbarch, unsigned char *data,
+ LONGEST &sec, ULONGEST &usec)
+{
+  if (gdbarch_addr_bit (gdbarch) == 64)
+    {
+      sec = bfd_get_signed_64 (core_bfd, data);
+      usec = bfd_get_64 (core_bfd, data + 8);
+    }
+  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
+    {
+      sec = bfd_get_signed_32 (core_bfd, data);
+      usec = bfd_get_32 (core_bfd, data + 4);
+    }
+  else
+    {
+      sec = bfd_get_signed_64 (core_bfd, data);
+      usec = bfd_get_32 (core_bfd, data + 8);
+    }
+}
+
+/* Print out the contents of a signal set.  */
+
+static void
+fbsd_print_sigset (const char *descr, unsigned char *sigset)
+{
+  printf_filtered ("%s: ", descr);
+  for (int i = 0; i < SIG_WORDS; i++)
+    printf_filtered ("%08x ",
+     (unsigned int) bfd_get_32 (core_bfd, sigset + i * 4));
+  printf_filtered ("\n");
+}
+
+/* Implement "info proc status" for a corefile.  */
+
+static void
+fbsd_core_info_proc_status (struct gdbarch *gdbarch)
+{
+  const struct kinfo_proc_layout *kp;
+  asection *section;
+  const char *state;
+  unsigned char *descdata;
+  int addr_bit, long_bit;
+  size_t note_size;
+  ULONGEST value;
+  LONGEST sec;
+
+  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
+  if (section == NULL)
+    {
+      warning (_("unable to find process info in core file"));
+      return;
+    }
+
+  addr_bit = gdbarch_addr_bit (gdbarch);
+  if (addr_bit == 64)
+    kp = &kinfo_proc_layout_64;
+  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
+    kp = &kinfo_proc_layout_i386;
+  else
+    kp = &kinfo_proc_layout_32;
+  long_bit = gdbarch_long_bit (gdbarch);
+
+  /*
+   * Ensure that the note is large enough for all of the fields fetched
+   * by this function.  In particular, the note must contain the 32-bit
+   * structure size, then it must be long enough to access the last
+   * field used (ki_rusage_ch.ru_majflt) which is the size of a long.
+   */
+  note_size = bfd_get_section_size (section);
+  if (note_size < (4 + kp->ki_rusage_ch + kp->ru_majflt
+   + long_bit / TARGET_CHAR_BIT))
+    error (_("malformed core note - too short"));
+
+  gdb::def_vector<unsigned char> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ 0, note_size))
+    error (_("could not get core note contents"));
+
+  descdata = contents.data ();
+
+  /* Skip over the structure size.  */
+  descdata += 4;
+
+  /* Verify 'ki_layout' is 0.  */
+  if (bfd_get_32 (core_bfd, descdata + kp->ki_layout) != 0)
+    {
+      warning (_("unsupported process information in core file"));
+      return;
+    }
+
+  printf_filtered ("Name: %.19s\n", descdata + kp->ki_comm);
+  printf_filtered ("Process ID: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
+  printf_filtered ("Parent process: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ppid)));
+  printf_filtered ("Process group: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_pgid)));
+  printf_filtered ("Session id: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_sid)));
+
+  /* FreeBSD 12.0 and later store a 64-bit dev_t at 'ki_tdev'.  Older
+     kernels store a 32-bit dev_t at 'ki_tdev_freebsd11'.  In older
+     kernels the 64-bit 'ki_tdev' field is in a reserved section of
+     the structure that is cleared to zero.  Assume that a zero value
+     in ki_tdev indicates a core dump from an older kernel and use the
+     value in 'ki_tdev_freebsd11' instead.  */
+  value = bfd_get_64 (core_bfd, descdata + kp->ki_tdev);
+  if (value == 0)
+    value = bfd_get_32 (core_bfd, descdata + kp->ki_tdev_freebsd11);
+  printf_filtered ("TTY: %s\n", pulongest (value));
+  printf_filtered ("TTY owner process group: %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_tpgid)));
+  printf_filtered ("User IDs (real, effective, saved): %s %s %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_ruid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_uid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svuid)));
+  printf_filtered ("Group IDs (real, effective, saved): %s %s %s\n",
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_rgid)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_groups)),
+   pulongest (bfd_get_32 (core_bfd, descdata + kp->ki_svgid)));
+  printf_filtered ("Groups: ");
+  uint16_t ngroups = bfd_get_16 (core_bfd, descdata + kp->ki_ngroups);
+  for (int i = 0; i < ngroups; i++)
+    printf_filtered ("%s ",
+     pulongest (bfd_get_32 (core_bfd,
+    descdata + kp->ki_groups + i * 4)));
+  printf_filtered ("\n");
+  value = bfd_get (long_bit, core_bfd,
+   descdata + kp->ki_rusage + kp->ru_minflt);
+  printf_filtered ("Minor faults (no memory page): %s\n", pulongest (value));
+  value = bfd_get (long_bit, core_bfd,
+   descdata + kp->ki_rusage_ch + kp->ru_minflt);
+  printf_filtered ("Minor faults, children: %s\n", pulongest (value));
+  value = bfd_get (long_bit, core_bfd,
+   descdata + kp->ki_rusage + kp->ru_majflt);
+  printf_filtered ("Major faults (memory page faults): %s\n",
+   pulongest (value));
+  value = bfd_get (long_bit, core_bfd,
+   descdata + kp->ki_rusage_ch + kp->ru_majflt);
+  printf_filtered ("Major faults, children: %s\n", pulongest (value));
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage + kp->ru_utime,
+   sec, value);
+  printf_filtered ("utime: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage + kp->ru_stime,
+   sec, value);
+  printf_filtered ("stime: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage_ch + kp->ru_utime,
+   sec, value);
+  printf_filtered ("utime, children: %s.%06d\n", plongest (sec), (int) value);
+  fbsd_core_fetch_timeval (gdbarch,
+   descdata + kp->ki_rusage_ch + kp->ru_stime,
+   sec, value);
+  printf_filtered ("stime, children: %s.%06d\n", plongest (sec), (int) value);
+  printf_filtered ("'nice' value: %d\n",
+   bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice));
+  fbsd_core_fetch_timeval (gdbarch, descdata + kp->ki_start, sec, value);
+  printf_filtered ("Start time: %s.%06d\n", plongest (sec), (int) value);
+  printf_filtered ("Virtual memory size: %s kB\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_size) / 1024));
+  printf_filtered ("Data size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_dsize)));
+  printf_filtered ("Stack size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_ssize)));
+  printf_filtered ("Text size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_tsize)));
+  printf_filtered ("Resident set size: %s pages\n",
+   pulongest (bfd_get (addr_bit, core_bfd,
+       descdata + kp->ki_rssize)));
+  printf_filtered ("Maximum RSS: %s pages\n",
+   pulongest (bfd_get (long_bit, core_bfd,
+       descdata + kp->ki_rusage
+       + kp->ru_maxrss)));
+  fbsd_print_sigset ("Ignored Signals", descdata + kp->ki_sigignore);
+  fbsd_print_sigset ("Caught Signals", descdata + kp->ki_sigcatch);
+}
+
+/* Implement the "core_info_proc" gdbarch method.  */
+
+static void
+fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args,
+     enum info_proc_what what)
+{
+  bool do_cmdline = false;
+  bool do_cwd = false;
+  bool do_exe = false;
+  bool do_mappings = false;
+  bool do_status = false;
+  int pid;
+
+  switch (what)
+    {
+    case IP_MINIMAL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+      break;
+    case IP_MAPPINGS:
+      do_mappings = true;
+      break;
+    case IP_STATUS:
+    case IP_STAT:
+      do_status = true;
+      break;
+    case IP_CMDLINE:
+      do_cmdline = true;
+      break;
+    case IP_EXE:
+      do_exe = true;
+      break;
+    case IP_CWD:
+      do_cwd = true;
+      break;
+    case IP_ALL:
+      do_cmdline = true;
+      do_cwd = true;
+      do_exe = true;
+      do_mappings = true;
+      do_status = true;
+      break;
+    default:
+      return;
+    }
+
+  pid = bfd_core_file_pid (core_bfd);
+  if (pid != 0)
+    printf_filtered (_("process %d\n"), pid);
+
+  if (do_cmdline)
+    {
+      const char *cmdline;
+
+      cmdline = bfd_core_file_failing_command (core_bfd);
+      if (cmdline)
+ printf_filtered ("cmdline = '%s'\n", cmdline);
+      else
+ warning (_("Command line unavailable"));
+    }
+  if (do_cwd)
+    {
+      gdb::unique_xmalloc_ptr<char> cwd =
+ fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_CWD);
+      if (cwd)
+ printf_filtered ("cwd = '%s'\n", cwd.get ());
+      else
+ warning (_("unable to read current working directory"));
+    }
+  if (do_exe)
+    {
+      gdb::unique_xmalloc_ptr<char> exe =
+ fbsd_core_vnode_path (gdbarch, KINFO_FILE_FD_TYPE_TEXT);
+      if (exe)
+ printf_filtered ("exe = '%s'\n", exe.get ());
+      else
+ warning (_("unable to read executable path name"));
+    }
+  if (do_mappings)
+    fbsd_core_info_proc_mappings (gdbarch);
+  if (do_status)
+    fbsd_core_info_proc_status (gdbarch);
+}
+
 /* Print descriptions of FreeBSD-specific AUXV entries to FILE.  */
 
 static void
@@ -519,6 +1168,7 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_core_thread_name (gdbarch, fbsd_core_thread_name);
   set_gdbarch_core_xfer_siginfo (gdbarch, fbsd_core_xfer_siginfo);
   set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes);
+  set_gdbarch_core_info_proc (gdbarch, fbsd_core_info_proc);
   set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry);
   set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type);
 
diff --git a/gdb/fbsd-tdep.h b/gdb/fbsd-tdep.h
index 9769903dec..0b293e5a25 100644
--- a/gdb/fbsd-tdep.h
+++ b/gdb/fbsd-tdep.h
@@ -22,4 +22,11 @@
 
 extern void fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
 
+/* Helper function to generate mappings flags for a single VM map
+   entry in 'info proc mappings'.  The KVE_FLAGS and KVE_PROTECTION
+   parameters should contain the values of the corresponding fields in
+   a 'struct kinfo_vmentry'.  */
+
+extern const char *fbsd_vm_map_entry_flags (int kve_flags, int kve_protection);
+
 #endif /* fbsd-tdep.h */


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

Re: [PATCH v2 1/5] Support 'info proc' for FreeBSD process core dumps.

Simon Marchi-2
On 2018-01-05 02:21 PM, John Baldwin wrote:

> On Thursday, January 04, 2018 09:53:47 PM Simon Marchi wrote:
>> Hi John,
>>
>> I have two little comments, but otherwise it LGTM.
>>
>> On 2018-01-03 08:49 PM, John Baldwin wrote:
>>> +/* Implement "info proc status" for a corefile.  */
>>> +
>>> +static void
>>> +fbsd_core_info_proc_status (struct gdbarch *gdbarch)
>>> +{
>>> +  const struct kinfo_proc_layout *kp;
>>> +  asection *section;
>>> +  const char *state;
>>> +  unsigned char *descdata, *descend;
>>
>> I get this:
>>
>> /home/simark/src/binutils-gdb/gdb/fbsd-tdep.c: In function ‘void fbsd_core_info_proc_status(gdbarch*)’:
>> /home/simark/src/binutils-gdb/gdb/fbsd-tdep.c:791:29: error: variable ‘descend’ set but not used [-Werror=unused-but-set-variable]
>>    unsigned char *descdata, *descend;
>>                              ^~~~~~~
>
> Oops, too much copy and paste (and I've only been building with clang so far).
>
>>> +  int addr_bit, long_bit;
>>> +  size_t note_size;
>>> +  ULONGEST value;
>>> +  LONGEST sec;
>>> +
>>> +  section = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.proc");
>>> +  if (section == NULL)
>>> +    {
>>> +      warning (_("unable to find process info in core file"));
>>> +      return;
>>> +    }
>>> +
>>> +  addr_bit = gdbarch_addr_bit (gdbarch);
>>> +  if (addr_bit == 64)
>>> +    kp = &kinfo_proc_layout_64;
>>> +  else if (bfd_get_arch (core_bfd) == bfd_arch_i386)
>>> +    kp = &kinfo_proc_layout_i386;
>>> +  else
>>> +    kp = &kinfo_proc_layout_32;
>>> +
>>> +  note_size = bfd_get_section_size (section);
>>> +  if (note_size < 4 + kp->ki_rusage_ch + kp->ru_majflt + addr_bit)
>>
>> What's the rationale behind that computation?  The field ru_majflt in kp->ki_rusage_ch
>> is the furthest field we'll actually need in this function?  And addr_bit is the size of
>> that field?  And 4 is because there's a field at the beginning containing the size of
>> the structure that comes after?
>
> Correct.  This is the bounds check to avoid overflowing the note buffer,
> but it does warrany a comment to explain what it is doing.  And actually,
> writing that comment made me realize a bug.  It should be 'addr_bit /
> TARGET_CHAR_BIT', not addr_bit directly.  Also, I noticed that the
> 'long_bit' variable at the start of the quoted section above also isn't
> used, but it's probably cleaner to be explicit and assign it to
> gdbarch_long_bit() and use it in place of addr_bit for structure members
> that are of type long rather than assuming addr_bit == long_bit (even
> though that is true on all of the architectures FreeBSD supports or is
> likely to support).
>
> Ends up like this:

That LGTM, the comment you added is clear.

Simon