Message ID | 20171222220513.54983-3-jhb@FreeBSD.org |
---|---|
State | New |
Headers | show |
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.
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 + { + /* 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); 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); #endif /* fbsd-tdep.h */