diff options
Diffstat (limited to 'gdb/fbsd-tdep.c')
-rw-r--r-- | gdb/fbsd-tdep.c | 194 |
1 files changed, 190 insertions, 4 deletions
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index b834ce3..1908269 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -30,6 +30,48 @@ #include "fbsd-tdep.h" +/* FreeBSD kernels 12.0 and later include a copy of the + 'ptrace_lwpinfo' structure returned by the PT_LWPINFO ptrace + operation in an ELF core note (NT_FREEBSD_PTLWPINFO) for each LWP. + The constants below define the offset of field members and flags in + this structure used by methods in this file. Note that the + 'ptrace_lwpinfo' struct in the note is preceded by a 4 byte integer + containing the size of the structure. */ + +#define LWPINFO_OFFSET 0x4 + +/* Offsets in ptrace_lwpinfo. */ +#define LWPINFO_PL_FLAGS 0x8 +#define LWPINFO64_PL_SIGINFO 0x30 +#define LWPINFO32_PL_SIGINFO 0x2c + +/* Flags in pl_flags. */ +#define PL_FLAG_SI 0x20 /* siginfo is valid */ + +/* Sizes of siginfo_t. */ +#define SIZE64_SIGINFO_T 80 +#define SIZE32_SIGINFO_T 64 + +static struct gdbarch_data *fbsd_gdbarch_data_handle; + +struct fbsd_gdbarch_data + { + struct type *siginfo_type; + }; + +static void * +init_fbsd_gdbarch_data (struct gdbarch *gdbarch) +{ + return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct fbsd_gdbarch_data); +} + +static struct fbsd_gdbarch_data * +get_fbsd_gdbarch_data (struct gdbarch *gdbarch) +{ + return ((struct fbsd_gdbarch_data *) + gdbarch_data (gdbarch, fbsd_gdbarch_data_handle)); +} + /* This is how we want PTIDs from core files to be printed. */ static const char * @@ -55,7 +97,6 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr) static char buf[80]; struct bfd_section *section; bfd_size_type size; - char sectionstr[32]; if (ptid_get_lwp (thr->ptid) != 0) { @@ -66,9 +107,9 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr) structure. Rather than define the full structure here, just extract the null-terminated name from the start of the note. */ - xsnprintf (sectionstr, sizeof sectionstr, ".thrmisc/%ld", - ptid_get_lwp (thr->ptid)); - section = bfd_get_section_by_name (core_bfd, sectionstr); + thread_section_name section_name (".thrmisc", thr->ptid); + + section = bfd_get_section_by_name (core_bfd, section_name.c_str ()); if (section != NULL && bfd_section_size (core_bfd, section) > 0) { /* Truncate the name if it is longer than "buf". */ @@ -94,6 +135,51 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr) return NULL; } +/* Implement the "core_xfer_siginfo" gdbarch method. */ + +static LONGEST +fbsd_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf, + ULONGEST offset, ULONGEST len) +{ + size_t siginfo_size; + + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) + siginfo_size = SIZE32_SIGINFO_T; + else + siginfo_size = SIZE64_SIGINFO_T; + if (offset > siginfo_size) + return -1; + + thread_section_name section_name (".note.freebsdcore.lwpinfo", inferior_ptid); + asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ()); + if (section == NULL) + return -1; + + gdb_byte buf[4]; + if (!bfd_get_section_contents (core_bfd, section, buf, + LWPINFO_OFFSET + LWPINFO_PL_FLAGS, 4)) + return -1; + + int pl_flags = extract_signed_integer (buf, 4, gdbarch_byte_order (gdbarch)); + if (!(pl_flags & PL_FLAG_SI)) + return -1; + + if (offset + len > siginfo_size) + len = siginfo_size - offset; + + ULONGEST siginfo_offset; + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) + siginfo_offset = LWPINFO_OFFSET + LWPINFO32_PL_SIGINFO; + else + siginfo_offset = LWPINFO_OFFSET + LWPINFO64_PL_SIGINFO; + + if (!bfd_get_section_contents (core_bfd, section, readbuf, + siginfo_offset + offset, len)) + return -1; + + return len; +} + static int find_signalled_thread (struct thread_info *info, void *data) { @@ -314,6 +400,97 @@ fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, fprint_auxv_entry (file, name, description, format, type, val); } +/* Implement the "get_siginfo_type" gdbarch method. */ + +static struct type * +fbsd_get_siginfo_type (struct gdbarch *gdbarch) +{ + struct fbsd_gdbarch_data *fbsd_gdbarch_data; + struct type *int_type, *int32_type, *uint32_type, *long_type, *void_ptr_type; + struct type *uid_type, *pid_type; + struct type *sigval_type, *reason_type; + struct type *siginfo_type; + struct type *type; + + fbsd_gdbarch_data = get_fbsd_gdbarch_data (gdbarch); + if (fbsd_gdbarch_data->siginfo_type != NULL) + return fbsd_gdbarch_data->siginfo_type; + + int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), + 0, "int"); + int32_type = arch_integer_type (gdbarch, 32, 0, "int32_t"); + uint32_type = arch_integer_type (gdbarch, 32, 1, "uint32_t"); + long_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), + 0, "long"); + void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); + + /* union sigval */ + sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); + TYPE_NAME (sigval_type) = xstrdup ("sigval"); + append_composite_type_field (sigval_type, "sival_int", int_type); + append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type); + + /* __pid_t */ + pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, + TYPE_LENGTH (int32_type), "__pid_t"); + TYPE_TARGET_TYPE (pid_type) = int32_type; + TYPE_TARGET_STUB (pid_type) = 1; + + /* __uid_t */ + uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF, + TYPE_LENGTH (uint32_type), "__uid_t"); + TYPE_TARGET_TYPE (uid_type) = uint32_type; + TYPE_TARGET_STUB (uid_type) = 1; + + /* _reason */ + reason_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); + + /* _fault */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_trapno", int_type); + append_composite_type_field (reason_type, "_fault", type); + + /* _timer */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_timerid", int_type); + append_composite_type_field (type, "si_overrun", int_type); + append_composite_type_field (reason_type, "_timer", type); + + /* _mesgq */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_mqd", int_type); + append_composite_type_field (reason_type, "_mesgq", type); + + /* _poll */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_band", long_type); + append_composite_type_field (reason_type, "_poll", type); + + /* __spare__ */ + type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "__spare1__", long_type); + append_composite_type_field (type, "__spare2__", + init_vector_type (int_type, 7)); + append_composite_type_field (reason_type, "__spare__", type); + + /* struct siginfo */ + siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (siginfo_type) = xstrdup ("siginfo"); + append_composite_type_field (siginfo_type, "si_signo", int_type); + append_composite_type_field (siginfo_type, "si_errno", int_type); + append_composite_type_field (siginfo_type, "si_code", int_type); + append_composite_type_field (siginfo_type, "si_pid", pid_type); + append_composite_type_field (siginfo_type, "si_uid", uid_type); + append_composite_type_field (siginfo_type, "si_status", int_type); + append_composite_type_field (siginfo_type, "si_addr", void_ptr_type); + append_composite_type_field (siginfo_type, "si_value", sigval_type); + append_composite_type_field (siginfo_type, "_reason", reason_type); + + fbsd_gdbarch_data->siginfo_type = siginfo_type; + + return siginfo_type; +} + /* Implement the "get_syscall_number" gdbarch method. */ static LONGEST @@ -337,10 +514,19 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { set_gdbarch_core_pid_to_str (gdbarch, fbsd_core_pid_to_str); 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_print_auxv_entry (gdbarch, fbsd_print_auxv_entry); + set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type); /* `catch syscall' */ set_xml_syscall_file_name (gdbarch, "syscalls/freebsd.xml"); set_gdbarch_get_syscall_number (gdbarch, fbsd_get_syscall_number); } + +void +_initialize_fbsd_tdep (void) +{ + fbsd_gdbarch_data_handle = + gdbarch_data_register_post_init (init_fbsd_gdbarch_data); +} |