diff options
Diffstat (limited to 'gdb/fbsd-tdep.c')
-rw-r--r-- | gdb/fbsd-tdep.c | 410 |
1 files changed, 408 insertions, 2 deletions
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index 48544b5..d4ffc71 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -25,6 +25,8 @@ #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" @@ -55,7 +57,13 @@ /* 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 @@ -85,23 +93,125 @@ /* 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. */ @@ -645,6 +755,295 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) 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'. */ @@ -995,6 +1394,7 @@ fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args, 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; @@ -1022,10 +1422,14 @@ fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args, 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; @@ -1065,6 +1469,8 @@ fbsd_core_info_proc (struct gdbarch *gdbarch, const char *args, 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) |