#include "regset.h"
#include "gdbthread.h"
#include "xml-syscall.h"
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include "elf-bfd.h"
#include "fbsd-tdep.h"
/* 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. */
+ all architectures.
+
+ Note that FreeBSD 7.0 used an older version of this structure
+ (struct kinfo_ovmentry), but the NT_FREEBSD_PROCSTAT_VMMAP core
+ dump note wasn't introduced until FreeBSD 9.2. As a result, the
+ core dump note has always used the 7.1 and later structure
+ format. */
#define KVE_STRUCTSIZE 0x0
#define KVE_START 0x8
/* 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. */
+ architectures.
+
+ Note that FreeBSD 7.0 used an older version of this structure
+ (struct kinfo_ofile), but the NT_FREEBSD_PROCSTAT_FILES core dump
+ note wasn't introduced until FreeBSD 9.2. As a result, the core
+ dump note has always used the 7.1 and later structure format. */
#define KF_STRUCTSIZE 0x0
#define KF_TYPE 0x4
#define KF_FD 0x8
+#define KF_FLAGS 0x10
+#define KF_OFFSET 0x18
+#define KF_VNODE_TYPE 0x20
+#define KF_SOCK_DOMAIN 0x24
+#define KF_SOCK_TYPE 0x28
+#define KF_SOCK_PROTOCOL 0x2c
+#define KF_SA_LOCAL 0x30
+#define KF_SA_PEER 0xb0
#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
+#define KINFO_FILE_TYPE_SOCKET 2
+#define KINFO_FILE_TYPE_PIPE 3
+#define KINFO_FILE_TYPE_FIFO 4
+#define KINFO_FILE_TYPE_KQUEUE 5
+#define KINFO_FILE_TYPE_CRYPTO 6
+#define KINFO_FILE_TYPE_MQUEUE 7
+#define KINFO_FILE_TYPE_SHM 8
+#define KINFO_FILE_TYPE_SEM 9
+#define KINFO_FILE_TYPE_PTS 10
+#define KINFO_FILE_TYPE_PROCDESC 11
/* 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_ROOT -2
+#define KINFO_FILE_FD_TYPE_JAIL -3
+#define KINFO_FILE_FD_TYPE_TRACE -4
#define KINFO_FILE_FD_TYPE_TEXT -5
+#define KINFO_FILE_FD_TYPE_CTTY -6
+
+/* Flags in the 'kf_flags' field in struct kinfo_file. These match
+ the KF_FLAG_* constants in <sys/user.h>. */
+
+#define KINFO_FILE_FLAG_READ 0x00000001
+#define KINFO_FILE_FLAG_WRITE 0x00000002
+#define KINFO_FILE_FLAG_APPEND 0x00000004
+#define KINFO_FILE_FLAG_ASYNC 0x00000008
+#define KINFO_FILE_FLAG_FSYNC 0x00000010
+#define KINFO_FILE_FLAG_NONBLOCK 0x00000020
+#define KINFO_FILE_FLAG_DIRECT 0x00000040
+#define KINFO_FILE_FLAG_HASLOCK 0x00000080
+#define KINFO_FILE_FLAG_EXEC 0x00004000
+
+/* Constants for the 'kf_vnode_type' field in struct kinfo_file.
+ These match the KF_VTYPE_* constants in <sys/user.h>. */
+
+#define KINFO_FILE_VTYPE_VREG 1
+#define KINFO_FILE_VTYPE_VDIR 2
+#define KINFO_FILE_VTYPE_VCHR 4
+#define KINFO_FILE_VTYPE_VLNK 5
+#define KINFO_FILE_VTYPE_VSOCK 6
+#define KINFO_FILE_VTYPE_VFIFO 7
+
+/* Constants for socket address families. These match AF_* constants
+ in <sys/socket.h>. */
+
+#define FBSD_AF_UNIX 1
+#define FBSD_AF_INET 2
+#define FBSD_AF_INET6 28
+
+/* Constants for socket types. These match SOCK_* constants in
+ <sys/socket.h>. */
+
+#define FBSD_SOCK_STREAM 1
+#define FBSD_SOCK_DGRAM 2
+#define FBSD_SOCK_SEQPACKET 5
+
+/* Constants for IP protocols. These match IPPROTO_* constants in
+ <netinet/in.h>. */
+
+#define FBSD_IPPROTO_ICMP 1
+#define FBSD_IPPROTO_TCP 6
+#define FBSD_IPPROTO_UDP 17
+#define FBSD_IPPROTO_SCTP 132
+
+/* Socket address structures. These have the same layout on all
+ FreeBSD architectures. In addition, multibyte fields such as IP
+ addresses are always stored in network byte order. */
+
+struct fbsd_sockaddr_in
+{
+ uint8_t sin_len;
+ uint8_t sin_family;
+ uint8_t sin_port[2];
+ uint8_t sin_addr[4];
+ char sin_zero[8];
+};
+
+struct fbsd_sockaddr_in6
+{
+ uint8_t sin6_len;
+ uint8_t sin6_family;
+ uint8_t sin6_port[2];
+ uint32_t sin6_flowinfo;
+ uint8_t sin6_addr[16];
+ uint32_t sin6_scope_id;
+};
+
+struct fbsd_sockaddr_un
+{
+ uint8_t sun_len;
+ uint8_t sun_family;
+ char sun_path[104];
+};
/* Number of 32-bit words in a signal set. This matches _SIG_WORDS in
<sys/_sigset.h> and is the same value on all architectures. */
return note_data;
}
+/* Helper function to generate the file descriptor description for a
+ single open file in 'info proc files'. */
+
+static const char *
+fbsd_file_fd (int kf_fd)
+{
+ switch (kf_fd)
+ {
+ case KINFO_FILE_FD_TYPE_CWD:
+ return "cwd";
+ case KINFO_FILE_FD_TYPE_ROOT:
+ return "root";
+ case KINFO_FILE_FD_TYPE_JAIL:
+ return "jail";
+ case KINFO_FILE_FD_TYPE_TRACE:
+ return "trace";
+ case KINFO_FILE_FD_TYPE_TEXT:
+ return "text";
+ case KINFO_FILE_FD_TYPE_CTTY:
+ return "ctty";
+ default:
+ return int_string (kf_fd, 10, 1, 0, 0);
+ }
+}
+
+/* Helper function to generate the file type for a single open file in
+ 'info proc files'. */
+
+static const char *
+fbsd_file_type (int kf_type, int kf_vnode_type)
+{
+ switch (kf_type)
+ {
+ case KINFO_FILE_TYPE_VNODE:
+ switch (kf_vnode_type)
+ {
+ case KINFO_FILE_VTYPE_VREG:
+ return "file";
+ case KINFO_FILE_VTYPE_VDIR:
+ return "dir";
+ case KINFO_FILE_VTYPE_VCHR:
+ return "chr";
+ case KINFO_FILE_VTYPE_VLNK:
+ return "link";
+ case KINFO_FILE_VTYPE_VSOCK:
+ return "socket";
+ case KINFO_FILE_VTYPE_VFIFO:
+ return "fifo";
+ default:
+ {
+ char *str = get_print_cell ();
+
+ xsnprintf (str, PRINT_CELL_SIZE, "vn:%d", kf_vnode_type);
+ return str;
+ }
+ }
+ case KINFO_FILE_TYPE_SOCKET:
+ return "socket";
+ case KINFO_FILE_TYPE_PIPE:
+ return "pipe";
+ case KINFO_FILE_TYPE_FIFO:
+ return "fifo";
+ case KINFO_FILE_TYPE_KQUEUE:
+ return "kqueue";
+ case KINFO_FILE_TYPE_CRYPTO:
+ return "crypto";
+ case KINFO_FILE_TYPE_MQUEUE:
+ return "mqueue";
+ case KINFO_FILE_TYPE_SHM:
+ return "shm";
+ case KINFO_FILE_TYPE_SEM:
+ return "sem";
+ case KINFO_FILE_TYPE_PTS:
+ return "pts";
+ case KINFO_FILE_TYPE_PROCDESC:
+ return "proc";
+ default:
+ return int_string (kf_type, 10, 1, 0, 0);
+ }
+}
+
+/* Helper function to generate the file flags for a single open file in
+ 'info proc files'. */
+
+static const char *
+fbsd_file_flags (int kf_flags)
+{
+ static char file_flags[10];
+
+ file_flags[0] = (kf_flags & KINFO_FILE_FLAG_READ) ? 'r' : '-';
+ file_flags[1] = (kf_flags & KINFO_FILE_FLAG_WRITE) ? 'w' : '-';
+ file_flags[2] = (kf_flags & KINFO_FILE_FLAG_EXEC) ? 'x' : '-';
+ file_flags[3] = (kf_flags & KINFO_FILE_FLAG_APPEND) ? 'a' : '-';
+ file_flags[4] = (kf_flags & KINFO_FILE_FLAG_ASYNC) ? 's' : '-';
+ file_flags[5] = (kf_flags & KINFO_FILE_FLAG_FSYNC) ? 'f' : '-';
+ file_flags[6] = (kf_flags & KINFO_FILE_FLAG_NONBLOCK) ? 'n' : '-';
+ file_flags[7] = (kf_flags & KINFO_FILE_FLAG_DIRECT) ? 'd' : '-';
+ file_flags[8] = (kf_flags & KINFO_FILE_FLAG_HASLOCK) ? 'l' : '-';
+ file_flags[9] = '\0';
+
+ return file_flags;
+}
+
+/* Helper function to generate the name of an IP protocol. */
+
+static const char *
+fbsd_ipproto (int protocol)
+{
+ switch (protocol)
+ {
+ case FBSD_IPPROTO_ICMP:
+ return "icmp";
+ case FBSD_IPPROTO_TCP:
+ return "tcp";
+ case FBSD_IPPROTO_UDP:
+ return "udp";
+ case FBSD_IPPROTO_SCTP:
+ return "sctp";
+ default:
+ {
+ char *str = get_print_cell ();
+
+ xsnprintf (str, PRINT_CELL_SIZE, "ip<%d>", protocol);
+ return str;
+ }
+ }
+}
+
+/* Helper function to print out an IPv4 socket address. */
+
+static void
+fbsd_print_sockaddr_in (const void *sockaddr)
+{
+ const struct fbsd_sockaddr_in *sin =
+ reinterpret_cast<const struct fbsd_sockaddr_in *> (sockaddr);
+ char buf[INET_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET, sin->sin_addr, buf, sizeof buf) == nullptr)
+ error (_("Failed to format IPv4 address"));
+ printf_filtered ("%s:%u", buf,
+ (sin->sin_port[0] << 8) | sin->sin_port[1]);
+}
+
+/* Helper function to print out an IPv6 socket address. */
+
+static void
+fbsd_print_sockaddr_in6 (const void *sockaddr)
+{
+ const struct fbsd_sockaddr_in6 *sin6 =
+ reinterpret_cast<const struct fbsd_sockaddr_in6 *> (sockaddr);
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, sin6->sin6_addr, buf, sizeof buf) == nullptr)
+ error (_("Failed to format IPv6 address"));
+ printf_filtered ("%s.%u", buf,
+ (sin6->sin6_port[0] << 8) | sin6->sin6_port[1]);
+}
+
+/* See fbsd-tdep.h. */
+
+void
+fbsd_info_proc_files_header ()
+{
+ printf_filtered (_("Open files:\n\n"));
+ printf_filtered (" %6s %6s %10s %9s %s\n",
+ "FD", "Type", "Offset", "Flags ", "Name");
+}
+
+/* See fbsd-tdep.h. */
+
+void
+fbsd_info_proc_files_entry (int kf_type, int kf_fd, int kf_flags,
+ LONGEST kf_offset, int kf_vnode_type,
+ int kf_sock_domain, int kf_sock_type,
+ int kf_sock_protocol, const void *kf_sa_local,
+ const void *kf_sa_peer, const void *kf_path)
+{
+ printf_filtered (" %6s %6s %10s %8s ",
+ fbsd_file_fd (kf_fd),
+ fbsd_file_type (kf_type, kf_vnode_type),
+ kf_offset > -1 ? hex_string (kf_offset) : "-",
+ fbsd_file_flags (kf_flags));
+ if (kf_type == KINFO_FILE_TYPE_SOCKET)
+ {
+ switch (kf_sock_domain)
+ {
+ case FBSD_AF_UNIX:
+ {
+ switch (kf_sock_type)
+ {
+ case FBSD_SOCK_STREAM:
+ printf_filtered ("unix stream:");
+ break;
+ case FBSD_SOCK_DGRAM:
+ printf_filtered ("unix dgram:");
+ break;
+ case FBSD_SOCK_SEQPACKET:
+ printf_filtered ("unix seqpacket:");
+ break;
+ default:
+ printf_filtered ("unix <%d>:", kf_sock_type);
+ break;
+ }
+
+ /* For local sockets, print out the first non-nul path
+ rather than both paths. */
+ const struct fbsd_sockaddr_un *sun
+ = reinterpret_cast<const struct fbsd_sockaddr_un *> (kf_sa_local);
+ if (sun->sun_path[0] == 0)
+ sun = reinterpret_cast<const struct fbsd_sockaddr_un *>
+ (kf_sa_peer);
+ printf_filtered ("%s", sun->sun_path);
+ break;
+ }
+ case FBSD_AF_INET:
+ printf_filtered ("%s4 ", fbsd_ipproto (kf_sock_protocol));
+ fbsd_print_sockaddr_in (kf_sa_local);
+ printf_filtered (" -> ");
+ fbsd_print_sockaddr_in (kf_sa_peer);
+ break;
+ case FBSD_AF_INET6:
+ printf_filtered ("%s6 ", fbsd_ipproto (kf_sock_protocol));
+ fbsd_print_sockaddr_in6 (kf_sa_local);
+ printf_filtered (" -> ");
+ fbsd_print_sockaddr_in6 (kf_sa_peer);
+ break;
+ }
+ }
+ else
+ printf_filtered ("%s", reinterpret_cast<const char *> (kf_path));
+ printf_filtered ("\n");
+}
+
+/* Implement "info proc files" for a corefile. */
+
+static void
+fbsd_core_info_proc_files (struct gdbarch *gdbarch)
+{
+ asection *section
+ = bfd_get_section_by_name (core_bfd, ".note.freebsdcore.files");
+ if (section == NULL)
+ {
+ warning (_("unable to find open files in core file"));
+ return;
+ }
+
+ size_t 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"));
+
+ unsigned char *descdata = contents.data ();
+ unsigned char *descend = descdata + note_size;
+
+ /* Skip over the structure size. */
+ descdata += 4;
+
+ fbsd_info_proc_files_header ();
+
+ while (descdata + KF_PATH < descend)
+ {
+ ULONGEST structsize = bfd_get_32 (core_bfd, descdata + KF_STRUCTSIZE);
+ if (structsize < KF_PATH)
+ error (_("malformed core note - file structure too small"));
+
+ LONGEST type = bfd_get_signed_32 (core_bfd, descdata + KF_TYPE);
+ LONGEST fd = bfd_get_signed_32 (core_bfd, descdata + KF_FD);
+ LONGEST flags = bfd_get_signed_32 (core_bfd, descdata + KF_FLAGS);
+ LONGEST offset = bfd_get_signed_64 (core_bfd, descdata + KF_OFFSET);
+ LONGEST vnode_type = bfd_get_signed_32 (core_bfd,
+ descdata + KF_VNODE_TYPE);
+ LONGEST sock_domain = bfd_get_signed_32 (core_bfd,
+ descdata + KF_SOCK_DOMAIN);
+ LONGEST sock_type = bfd_get_signed_32 (core_bfd, descdata + KF_SOCK_TYPE);
+ LONGEST sock_protocol = bfd_get_signed_32 (core_bfd,
+ descdata + KF_SOCK_PROTOCOL);
+ fbsd_info_proc_files_entry (type, fd, flags, offset, vnode_type,
+ sock_domain, sock_type, sock_protocol,
+ descdata + KF_SA_LOCAL, descdata + KF_SA_PEER,
+ descdata + KF_PATH);
+
+ descdata += structsize;
+ }
+}
+
/* Helper function to generate mappings flags for a single VM map
entry in 'info proc mappings'. */
bool do_cmdline = false;
bool do_cwd = false;
bool do_exe = false;
+ bool do_files = false;
bool do_mappings = false;
bool do_status = false;
int pid;
case IP_CWD:
do_cwd = true;
break;
+ case IP_FILES:
+ do_files = true;
+ break;
case IP_ALL:
do_cmdline = true;
do_cwd = true;
do_exe = true;
+ do_files = true;
do_mappings = true;
do_status = true;
break;
else
warning (_("unable to read executable path name"));
}
+ if (do_files)
+ fbsd_core_info_proc_files (gdbarch);
if (do_mappings)
fbsd_core_info_proc_mappings (gdbarch);
if (do_status)