Add xml selftests for aarch64 target description.
[deliverable/binutils-gdb.git] / gdb / fbsd-tdep.c
index 4329f974835b8668524fe01cf983c224c369ed79..f89b520c5f14a082c9e37a23227633ac5801a251 100644 (file)
@@ -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.
 
 #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);
+}
This page took 0.029156 seconds and 4 git commands to generate.