X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ffbsd-tdep.c;h=f89b520c5f14a082c9e37a23227633ac5801a251;hb=6654d750c7c584dd83b93f062c5628f15c675480;hp=4329f974835b8668524fe01cf983c224c369ed79;hpb=e6cdd38e8f0fead14cd3c528e9a4b666e1871752;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index 4329f97483..f89b520c5f 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for FreeBSD, architecture-independent. - Copyright (C) 2002-2016 Free Software Foundation, Inc. + Copyright (C) 2002-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -30,9 +30,51 @@ #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 char * +static const char * fbsd_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) { static char buf[80]; @@ -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_long_bit (gdbarch) == 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_long_bit (gdbarch) == 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) { @@ -160,7 +246,7 @@ fbsd_collect_thread_registers (const struct regcache *regcache, char *note_data, int *note_size, enum gdb_signal stop_signal) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct fbsd_collect_regset_section_cb_data data; data.regcache = regcache; @@ -193,15 +279,11 @@ static void fbsd_corefile_thread (struct thread_info *info, struct fbsd_corefile_thread_data *args) { - struct cleanup *old_chain; struct regcache *regcache; regcache = get_thread_arch_regcache (info->ptid, args->gdbarch); - old_chain = save_inferior_ptid (); - inferior_ptid = info->ptid; target_fetch_registers (regcache, -1); - do_cleanups (old_chain); args->note_data = fbsd_collect_thread_registers (regcache, info->ptid, args->obfd, args->note_data, @@ -310,6 +392,8 @@ fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, TAG (PAGESIZESLEN, _("Number of pagesizes"), AUXV_FORMAT_DEC); TAG (TIMEKEEP, _("Pointer to timehands"), AUXV_FORMAT_HEX); TAG (STACKPROT, _("Initial stack protection"), AUXV_FORMAT_HEX); + TAG (EHDRFLAGS, _("ELF header e_flags"), AUXV_FORMAT_HEX); + TAG (HWCAP, _("Machine-dependent CPU capability hints"), AUXV_FORMAT_HEX); default: default_print_auxv_entry (gdbarch, file, type, val); return; @@ -318,6 +402,98 @@ 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) * TARGET_CHAR_BIT, "__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) * TARGET_CHAR_BIT, + "__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 @@ -334,17 +510,26 @@ fbsd_get_syscall_number (struct gdbarch *gdbarch, internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called")); } -/* To be called from GDB_OSABI_FREEBSD_ELF handlers. */ +/* To be called from GDB_OSABI_FREEBSD handlers. */ void 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); +}