[2/4] Support 'info proc' for FreeBSD process core dumps.
Commit Message
- 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.
- 'stat' and 'status' output is generated by outputting fields from
the first structure stored in the NT_PROCSTAT_PROC core note.
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, 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_print_sigset)
(fbsd_core_info_proc_status, fbsd_core_fetch_timeval)
(fbsd_core_info_proc_stat, 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 | 19 ++
gdb/fbsd-tdep.c | 698 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/fbsd-tdep.h | 1 +
3 files changed, 718 insertions(+)
Comments
On 2017-12-22 05:05 PM, John Baldwin wrote:
> - 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.
> - 'stat' and 'status' output is generated by outputting fields from
> the first structure stored in the NT_PROCSTAT_PROC core note.
>
> 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, 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_print_sigset)
> (fbsd_core_info_proc_status, fbsd_core_fetch_timeval)
> (fbsd_core_info_proc_stat, 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 | 19 ++
> gdb/fbsd-tdep.c | 698 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/fbsd-tdep.h | 1 +
> 3 files changed, 718 insertions(+)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 1b4b13aba9..2311749de7 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,22 @@
> +2017-12-22 John Baldwin <jhb@FreeBSD.org>
> +
> + * 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, 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_print_sigset)
> + (fbsd_core_info_proc_status, fbsd_core_fetch_timeval)
> + (fbsd_core_info_proc_stat, fbsd_core_info_proc): New.
> + (fbsd_init_abi): Install gdbarch "core_info_proc" method.
> + * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.
> +
> 2017-12-21 Simon Marchi <simon.marchi@ericsson.com>
> Sergio Durigan Junior <sergiodj@redhat.com>
>
> diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> index f89b520c5f..454036dcac 100644
> --- a/gdb/fbsd-tdep.c
> +++ b/gdb/fbsd-tdep.c
> @@ -52,6 +52,223 @@
> #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
> +
> +/* 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
struct definitions should not be indented, they should look like:
struct kinfo_proc_layout
{
int ki_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;
> + };
> +
> +struct kinfo_proc_layout kinfo_proc_layout_32 =
I would suggest making these const.
> + {
> + .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,
> + };
> +
> +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,
> + };
> +
> +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 +584,486 @@ 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. */
> +
> +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;
> +}
> +
> +/* Print out the contents of a signal set. */
> +
> +static void
> +fbsd_print_sigset (const char *descr, unsigned char *sigset)
> +{
> + printf_filtered ("%s:\t", descr);
> + for (int i = 0; i < _SIG_WORDS; i++)
_SIG_WORDS seems to be FreeBSD-specific, so shouldn't be used in the tdep file,
unless we redefine it.
> + 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)
> +{
> + 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;
> +
> + 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:\t%.19s\n", descdata + kp->ki_comm);
> + printf_filtered ("Pid:\t%s\n",
> + pulongest(bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
Missing a few spaces before parentheses here and there.
> + printf_filtered ("PPid:\t%s\n",
> + pulongest(bfd_get_32 (core_bfd, descdata + kp->ki_ppid)));
> + printf_filtered ("Uid:\t%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 ("Gid:\t%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:\t");
> + 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_size);
> + printf_filtered ("VmSize:\t%8ju kB\n", (uintmax_t) value / 1024);
> + value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_rssize);
> + printf_filtered ("VmRSS:\t%8ju pages\n", (uintmax_t) value);
> + value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_dsize);
> + printf_filtered ("VmData:\t%8ju pages\n", (uintmax_t) value);
> + value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_ssize);
> + printf_filtered ("VmStk:\t%8ju pages\n", (uintmax_t) value);
> + value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_tsize);
> + printf_filtered ("VmExe:\t%8ju pages\n", (uintmax_t) value);
> + fbsd_print_sigset ("SigIgn", descdata + kp->ki_sigignore);
> + fbsd_print_sigset ("SigCgt", descdata + kp->ki_sigcatch);
> +}
> +
> +/* 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);
> + }
> +}
> +
> +/* Implement "info proc stat" for a corefile. */
> +
> +static void
> +fbsd_core_info_proc_stat (struct gdbarch *gdbarch)
> +{
> + struct kinfo_proc_layout *kp;
> + asection *section;
> + char state;
> + unsigned char *descdata, *descend;
> + int addr_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 ("Exec file: %.19s\n", descdata + kp->ki_comm);
> + 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)));
> + 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_start) / 1024));
> + printf_filtered ("Resident set size: %s pages\n",
> + pulongest (bfd_get (addr_bit, core_bfd,
> + descdata + kp->ki_rssize)));
> + value = bfd_get (addr_bit, core_bfd,
> + descdata + kp->ki_rusage + kp->ru_maxrss);
> + printf_filtered ("rlim: %s kB\n", pulongest (value));
> +}
> +
> +/* 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;
> + bool do_stat = 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:
> + do_status = true;
> + break;
> + case IP_STAT:
> + do_stat = 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;
> + do_stat = true;
> + break;
> + default:
> + error (_("Not supported on this architecture."));
If you mean "not supported for FreeBSD", I'm not sure architecture
is the right word, since architecture usually refers to CPU architecture.
> + }
> +
> + 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);
> + if (do_stat)
> + fbsd_core_info_proc_stat (gdbarch);
> +}
> +
> /* Print descriptions of FreeBSD-specific AUXV entries to FILE. */
>
> static void
> @@ -519,6 +1216,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 ff2e207aae..0029e03d41 100644
> --- a/gdb/fbsd-tdep.h
> +++ b/gdb/fbsd-tdep.h
> @@ -21,5 +21,6 @@
> #define FBSD_TDEP_H
>
> extern void fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
> +extern const char *fbsd_vm_map_entry_flags (int kve_flags, int kve_protection);
Can you please add doc for this new function?
>
> #endif /* fbsd-tdep.h */
>
Thanks,
Simon
On Tuesday, December 26, 2017 08:56:51 PM Simon Marchi wrote:
> On 2017-12-22 05:05 PM, John Baldwin wrote:
> > - 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.
> > - 'stat' and 'status' output is generated by outputting fields from
> > the first structure stored in the NT_PROCSTAT_PROC core note.
> >
> > diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> > index f89b520c5f..454036dcac 100644
> > --- a/gdb/fbsd-tdep.c
> > +++ b/gdb/fbsd-tdep.c
> > + 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
>
> struct definitions should not be indented, they should look like:
>
> struct kinfo_proc_layout
> {
> int ki_layout;
> ...
> }
Fixed.
> > +
> > +struct kinfo_proc_layout kinfo_proc_layout_32 =
>
> I would suggest making these const.
Fixed.
> > +static void
> > +fbsd_print_sigset (const char *descr, unsigned char *sigset)
> > +{
> > + printf_filtered ("%s:\t", descr);
> > + for (int i = 0; i < _SIG_WORDS; i++)
>
> _SIG_WORDS seems to be FreeBSD-specific, so shouldn't be used in the tdep file,
> unless we redefine it.
Oops, yes. I added a local constant.
> > + printf_filtered ("Name:\t%.19s\n", descdata + kp->ki_comm);
> > + printf_filtered ("Pid:\t%s\n",
> > + pulongest(bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
>
> Missing a few spaces before parentheses here and there.
Fixed.
> > + default:
> > + error (_("Not supported on this architecture."));
>
> If you mean "not supported for FreeBSD", I'm not sure architecture
> is the right word, since architecture usually refers to CPU architecture.
Mmm, yes. I think I was trying to say "not supported on this gdbarch"
in effect. However, the core target doesn't output any error if there
is no valid core_info_proc method, so perhaps it would be best to just
not output any error at all. This also matches linux-tdep.c which doesn't
output anything for an unsupported enum value.
> > diff --git a/gdb/fbsd-tdep.h b/gdb/fbsd-tdep.h
> > index ff2e207aae..0029e03d41 100644
> > --- a/gdb/fbsd-tdep.h
> > +++ b/gdb/fbsd-tdep.h
> > @@ -21,5 +21,6 @@
> > #define FBSD_TDEP_H
> >
> > extern void fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
> > +extern const char *fbsd_vm_map_entry_flags (int kve_flags, int kve_protection);
>
> Can you please add doc for this new function?
Fixed.
@@ -1,3 +1,22 @@
+2017-12-22 John Baldwin <jhb@FreeBSD.org>
+
+ * 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, 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_print_sigset)
+ (fbsd_core_info_proc_status, fbsd_core_fetch_timeval)
+ (fbsd_core_info_proc_stat, fbsd_core_info_proc): New.
+ (fbsd_init_abi): Install gdbarch "core_info_proc" method.
+ * fbsd-tdep.h (fbsd_vm_map_entry_flags): New.
+
2017-12-21 Simon Marchi <simon.marchi@ericsson.com>
Sergio Durigan Junior <sergiodj@redhat.com>
@@ -52,6 +52,223 @@
#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
+
+/* 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;
+ };
+
+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,
+ };
+
+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,
+ };
+
+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 +584,486 @@ 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. */
+
+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;
+}
+
+/* Print out the contents of a signal set. */
+
+static void
+fbsd_print_sigset (const char *descr, unsigned char *sigset)
+{
+ printf_filtered ("%s:\t", 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)
+{
+ 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;
+
+ 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:\t%.19s\n", descdata + kp->ki_comm);
+ printf_filtered ("Pid:\t%s\n",
+ pulongest(bfd_get_32 (core_bfd, descdata + kp->ki_pid)));
+ printf_filtered ("PPid:\t%s\n",
+ pulongest(bfd_get_32 (core_bfd, descdata + kp->ki_ppid)));
+ printf_filtered ("Uid:\t%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 ("Gid:\t%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:\t");
+ 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_size);
+ printf_filtered ("VmSize:\t%8ju kB\n", (uintmax_t) value / 1024);
+ value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_rssize);
+ printf_filtered ("VmRSS:\t%8ju pages\n", (uintmax_t) value);
+ value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_dsize);
+ printf_filtered ("VmData:\t%8ju pages\n", (uintmax_t) value);
+ value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_ssize);
+ printf_filtered ("VmStk:\t%8ju pages\n", (uintmax_t) value);
+ value = bfd_get (addr_bit, core_bfd, descdata + kp->ki_tsize);
+ printf_filtered ("VmExe:\t%8ju pages\n", (uintmax_t) value);
+ fbsd_print_sigset ("SigIgn", descdata + kp->ki_sigignore);
+ fbsd_print_sigset ("SigCgt", descdata + kp->ki_sigcatch);
+}
+
+/* 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);
+ }
+}
+
+/* Implement "info proc stat" for a corefile. */
+
+static void
+fbsd_core_info_proc_stat (struct gdbarch *gdbarch)
+{
+ struct kinfo_proc_layout *kp;
+ asection *section;
+ char state;
+ unsigned char *descdata, *descend;
+ int addr_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 ("Exec file: %.19s\n", descdata + kp->ki_comm);
+ 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)));
+ 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_start) / 1024));
+ printf_filtered ("Resident set size: %s pages\n",
+ pulongest (bfd_get (addr_bit, core_bfd,
+ descdata + kp->ki_rssize)));
+ value = bfd_get (addr_bit, core_bfd,
+ descdata + kp->ki_rusage + kp->ru_maxrss);
+ printf_filtered ("rlim: %s kB\n", pulongest (value));
+}
+
+/* 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;
+ bool do_stat = 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:
+ do_status = true;
+ break;
+ case IP_STAT:
+ do_stat = 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;
+ do_stat = true;
+ break;
+ default:
+ error (_("Not supported on this architecture."));
+ }
+
+ 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);
+ if (do_stat)
+ fbsd_core_info_proc_stat (gdbarch);
+}
+
/* Print descriptions of FreeBSD-specific AUXV entries to FILE. */
static void
@@ -519,6 +1216,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);
@@ -21,5 +21,6 @@
#define FBSD_TDEP_H
extern void fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
+extern const char *fbsd_vm_map_entry_flags (int kve_flags, int kve_protection);
#endif /* fbsd-tdep.h */