Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / fbsd-tdep.c
index 4e9ea816c5915ffe59e4f0bb2def4b3f2b5be2f8..6cab31dde82a66f7f38bd0611bc95e943f0b1f69 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for FreeBSD, architecture-independent.
 
-   Copyright (C) 2002-2018 Free Software Foundation, Inc.
+   Copyright (C) 2002-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "auxv.h"
 #include "gdbcore.h"
 #include "inferior.h"
+#include "objfiles.h"
 #include "regcache.h"
 #include "regset.h"
 #include "gdbthread.h"
+#include "objfiles.h"
 #include "xml-syscall.h"
 #include <sys/socket.h>
 #include <arpa/inet.h>
 
 #include "elf-bfd.h"
 #include "fbsd-tdep.h"
+#include "gcore-elf.h"
 
+/* This enum is derived from FreeBSD's <sys/signal.h>.  */
+
+enum
+  {
+    FREEBSD_SIGHUP = 1,
+    FREEBSD_SIGINT = 2,
+    FREEBSD_SIGQUIT = 3,
+    FREEBSD_SIGILL = 4,
+    FREEBSD_SIGTRAP = 5,
+    FREEBSD_SIGABRT = 6,
+    FREEBSD_SIGEMT = 7,
+    FREEBSD_SIGFPE = 8,
+    FREEBSD_SIGKILL = 9,
+    FREEBSD_SIGBUS = 10,
+    FREEBSD_SIGSEGV = 11,
+    FREEBSD_SIGSYS = 12,
+    FREEBSD_SIGPIPE = 13,
+    FREEBSD_SIGALRM = 14,
+    FREEBSD_SIGTERM = 15,
+    FREEBSD_SIGURG = 16,
+    FREEBSD_SIGSTOP = 17,
+    FREEBSD_SIGTSTP = 18,
+    FREEBSD_SIGCONT = 19,
+    FREEBSD_SIGCHLD = 20,
+    FREEBSD_SIGTTIN = 21,
+    FREEBSD_SIGTTOU = 22,
+    FREEBSD_SIGIO = 23,
+    FREEBSD_SIGXCPU = 24,
+    FREEBSD_SIGXFSZ = 25,
+    FREEBSD_SIGVTALRM = 26,
+    FREEBSD_SIGPROF = 27,
+    FREEBSD_SIGWINCH = 28,
+    FREEBSD_SIGINFO = 29,
+    FREEBSD_SIGUSR1 = 30,
+    FREEBSD_SIGUSR2 = 31,
+    FREEBSD_SIGTHR = 32,
+    FREEBSD_SIGLIBRT = 33,
+    FREEBSD_SIGRTMIN = 65,
+    FREEBSD_SIGRTMAX = 126,
+  };
 
 /* FreeBSD kernels 12.0 and later include a copy of the
    'ptrace_lwpinfo' structure returned by the PT_LWPINFO ptrace
    all architectures.
 
    Note that FreeBSD 7.0 used an older version of this structure
-   (struct kinfo_ovmentry), but the NT_FREEBSD_PROCSTAT_VMMAP core
+   (struct kinfo_vmentry), 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.  */
@@ -404,18 +447,37 @@ get_fbsd_gdbarch_data (struct gdbarch *gdbarch)
          gdbarch_data (gdbarch, fbsd_gdbarch_data_handle));
 }
 
+struct fbsd_pspace_data
+{
+  /* Offsets in the runtime linker's 'Obj_Entry' structure.  */
+  LONGEST off_linkmap = 0;
+  LONGEST off_tlsindex = 0;
+  bool rtld_offsets_valid = false;
+};
+
+/* Per-program-space data for FreeBSD architectures.  */
+static const struct program_space_key<fbsd_pspace_data>
+  fbsd_pspace_data_handle;
+
+static struct fbsd_pspace_data *
+get_fbsd_pspace_data (struct program_space *pspace)
+{
+  struct fbsd_pspace_data *data;
+
+  data = fbsd_pspace_data_handle.get (pspace);
+  if (data == NULL)
+    data = fbsd_pspace_data_handle.emplace (pspace);
+
+  return data;
+}
+
 /* This is how we want PTIDs from core files to be printed.  */
 
-static const char *
+static std::string
 fbsd_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
 {
-  static char buf[80];
-
   if (ptid.lwp () != 0)
-    {
-      xsnprintf (buf, sizeof buf, "LWP %ld", ptid.lwp ());
-      return buf;
-    }
+    return string_printf ("LWP %ld", ptid.lwp ());
 
   return normal_pid_to_str (ptid);
 }
@@ -442,10 +504,10 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr)
       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)
+      if (section != NULL && bfd_section_size (section) > 0)
        {
          /* Truncate the name if it is longer than "buf".  */
-         size = bfd_section_size (core_bfd, section);
+         size = bfd_section_size (section);
          if (size > sizeof buf - 1)
            size = sizeof buf - 1;
          if (bfd_get_section_contents (core_bfd, section, buf, (file_ptr) 0,
@@ -522,106 +584,6 @@ find_signalled_thread (struct thread_info *info, void *data)
   return 0;
 }
 
-/* Structure for passing information from
-   fbsd_collect_thread_registers via an iterator to
-   fbsd_collect_regset_section_cb. */
-
-struct fbsd_collect_regset_section_cb_data
-{
-  const struct regcache *regcache;
-  bfd *obfd;
-  char *note_data;
-  int *note_size;
-  unsigned long lwp;
-  enum gdb_signal stop_signal;
-  int abort_iteration;
-};
-
-static void
-fbsd_collect_regset_section_cb (const char *sect_name, int supply_size,
-                               int collect_size, const struct regset *regset,
-                               const char *human_name, void *cb_data)
-{
-  char *buf;
-  struct fbsd_collect_regset_section_cb_data *data
-    = (struct fbsd_collect_regset_section_cb_data *) cb_data;
-
-  if (data->abort_iteration)
-    return;
-
-  gdb_assert (regset->collect_regset);
-
-  buf = (char *) xmalloc (collect_size);
-  regset->collect_regset (regset, data->regcache, -1, buf, collect_size);
-
-  /* PRSTATUS still needs to be treated specially.  */
-  if (strcmp (sect_name, ".reg") == 0)
-    data->note_data = (char *) elfcore_write_prstatus
-      (data->obfd, data->note_data, data->note_size, data->lwp,
-       gdb_signal_to_host (data->stop_signal), buf);
-  else
-    data->note_data = (char *) elfcore_write_register_note
-      (data->obfd, data->note_data, data->note_size,
-       sect_name, buf, collect_size);
-  xfree (buf);
-
-  if (data->note_data == NULL)
-    data->abort_iteration = 1;
-}
-
-/* Records the thread's register state for the corefile note
-   section.  */
-
-static char *
-fbsd_collect_thread_registers (const struct regcache *regcache,
-                              ptid_t ptid, bfd *obfd,
-                              char *note_data, int *note_size,
-                              enum gdb_signal stop_signal)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct fbsd_collect_regset_section_cb_data data;
-
-  data.regcache = regcache;
-  data.obfd = obfd;
-  data.note_data = note_data;
-  data.note_size = note_size;
-  data.stop_signal = stop_signal;
-  data.abort_iteration = 0;
-  data.lwp = ptid.lwp ();
-
-  gdbarch_iterate_over_regset_sections (gdbarch,
-                                       fbsd_collect_regset_section_cb,
-                                       &data, regcache);
-  return data.note_data;
-}
-
-struct fbsd_corefile_thread_data
-{
-  struct gdbarch *gdbarch;
-  bfd *obfd;
-  char *note_data;
-  int *note_size;
-  enum gdb_signal stop_signal;
-};
-
-/* Records the thread's register state for the corefile note
-   section.  */
-
-static void
-fbsd_corefile_thread (struct thread_info *info,
-                     struct fbsd_corefile_thread_data *args)
-{
-  struct regcache *regcache;
-
-  regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
-
-  target_fetch_registers (regcache, -1);
-
-  args->note_data = fbsd_collect_thread_registers
-    (regcache, info->ptid, args->obfd, args->note_data,
-     args->note_size, args->stop_signal);
-}
-
 /* Return a byte_vector containing the contents of a core dump note
    for the target object of type OBJECT.  If STRUCTSIZE is non-zero,
    the data is prefixed with a 32-bit integer size to match the format
@@ -631,7 +593,7 @@ static gdb::optional<gdb::byte_vector>
 fbsd_make_note_desc (enum target_object object, uint32_t structsize)
 {
   gdb::optional<gdb::byte_vector> buf =
-    target_read_alloc (current_top_target (), object, NULL);
+    target_read_alloc (current_inferior ()->top_target (), object, NULL);
   if (!buf || buf->empty ())
     return {};
 
@@ -647,13 +609,12 @@ fbsd_make_note_desc (enum target_object object, uint32_t structsize)
 /* Create appropriate note sections for a corefile, returning them in
    allocated memory.  */
 
-static char *
+static gdb::unique_xmalloc_ptr<char>
 fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
 {
-  struct fbsd_corefile_thread_data thread_args;
-  char *note_data = NULL;
+  gdb::unique_xmalloc_ptr<char> note_data;
   Elf_Internal_Ehdr *i_ehdrp;
-  struct thread_info *curr_thr, *signalled_thr, *thr;
+  struct thread_info *curr_thr, *signalled_thr;
 
   /* Put a "FreeBSD" label in the ELF header.  */
   i_ehdrp = elf_elfheader (obfd);
@@ -664,26 +625,26 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   if (get_exec_file (0))
     {
       const char *fname = lbasename (get_exec_file (0));
-      char *psargs = xstrdup (fname);
+      std::string psargs = fname;
 
-      if (get_inferior_args ())
-       psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
-                          (char *) NULL);
+      const char *infargs = get_inferior_args ();
+      if (infargs != NULL)
+       psargs = psargs + " " + infargs;
 
-      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
-                                         fname, psargs);
+      note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
+                                              note_size, fname,
+                                              psargs.c_str ()));
     }
 
   /* Thread register information.  */
-  TRY
+  try
     {
       update_thread_list ();
     }
-  CATCH (e, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &e)
     {
       exception_print (gdb_stderr, e);
     }
-  END_CATCH
 
   /* Like the kernel, prefer dumping the signalled thread first.
      "First thread" is what tools use to infer the signalled thread.
@@ -699,34 +660,29 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
        signalled_thr = curr_thr;
     }
 
-  thread_args.gdbarch = gdbarch;
-  thread_args.obfd = obfd;
-  thread_args.note_data = note_data;
-  thread_args.note_size = note_size;
-  thread_args.stop_signal = signalled_thr->suspend.stop_signal;
-
-  fbsd_corefile_thread (signalled_thr, &thread_args);
-  ALL_NON_EXITED_THREADS (thr)
+  enum gdb_signal stop_signal = signalled_thr->suspend.stop_signal;
+  gcore_elf_build_thread_register_notes (gdbarch, signalled_thr, stop_signal,
+                                        obfd, &note_data, note_size);
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
     {
       if (thr == signalled_thr)
        continue;
-      if (thr->ptid.pid () != inferior_ptid.pid ())
-       continue;
 
-      fbsd_corefile_thread (thr, &thread_args);
+      gcore_elf_build_thread_register_notes (gdbarch, thr, stop_signal,
+                                            obfd, &note_data, note_size);
     }
 
-  note_data = thread_args.note_data;
-
   /* Auxiliary vector.  */
   uint32_t structsize = gdbarch_ptr_bit (gdbarch) / 4; /* Elf_Auxinfo  */
   gdb::optional<gdb::byte_vector> note_desc =
     fbsd_make_note_desc (TARGET_OBJECT_AUXV, structsize);
   if (note_desc && !note_desc->empty ())
     {
-      note_data = elfcore_write_note (obfd, note_data, note_size, "FreeBSD",
-                                     NT_FREEBSD_PROCSTAT_AUXV,
-                                     note_desc->data (), note_desc->size ());
+      note_data.reset (elfcore_write_note (obfd, note_data.release (),
+                                          note_size, "FreeBSD",
+                                          NT_FREEBSD_PROCSTAT_AUXV,
+                                          note_desc->data (),
+                                          note_desc->size ()));
       if (!note_data)
        return NULL;
     }
@@ -735,9 +691,11 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   note_desc = fbsd_make_note_desc (TARGET_OBJECT_FREEBSD_VMMAP, 0);
   if (note_desc && !note_desc->empty ())
     {
-      note_data = elfcore_write_note (obfd, note_data, note_size, "FreeBSD",
-                                     NT_FREEBSD_PROCSTAT_VMMAP,
-                                     note_desc->data (), note_desc->size ());
+      note_data.reset (elfcore_write_note (obfd, note_data.release (),
+                                          note_size, "FreeBSD",
+                                          NT_FREEBSD_PROCSTAT_VMMAP,
+                                          note_desc->data (),
+                                          note_desc->size ()));
       if (!note_data)
        return NULL;
     }
@@ -745,13 +703,18 @@ fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
   note_desc = fbsd_make_note_desc (TARGET_OBJECT_FREEBSD_PS_STRINGS, 0);
   if (note_desc && !note_desc->empty ())
     {
-      note_data = elfcore_write_note (obfd, note_data, note_size, "FreeBSD",
-                                     NT_FREEBSD_PROCSTAT_PSSTRINGS,
-                                     note_desc->data (), note_desc->size ());
+      note_data.reset (elfcore_write_note (obfd, note_data.release (),
+                                          note_size, "FreeBSD",
+                                          NT_FREEBSD_PROCSTAT_PSSTRINGS,
+                                          note_desc->data (),
+                                          note_desc->size ()));
       if (!note_data)
        return NULL;
     }
 
+  /* Include the target description when possible.  */
+  gcore_elf_make_tdesc_note (obfd, &note_data, note_size);
+
   return note_data;
 }
 
@@ -961,12 +924,12 @@ fbsd_info_proc_files_entry (int kf_type, int kf_fd, int kf_flags,
 
            /* For local sockets, print out the first non-nul path
               rather than both paths.  */
-           const struct fbsd_sockaddr_un *sun
+           const struct fbsd_sockaddr_un *saddr_un
              = reinterpret_cast<const struct fbsd_sockaddr_un *> (kf_sa_local);
-           if (sun->sun_path[0] == 0)
-             sun = reinterpret_cast<const struct fbsd_sockaddr_un *>
+           if (saddr_un->sun_path[0] == 0)
+             saddr_un = reinterpret_cast<const struct fbsd_sockaddr_un *>
                (kf_sa_peer);
-           printf_filtered ("%s", sun->sun_path);
+           printf_filtered ("%s", saddr_un->sun_path);
            break;
          }
        case FBSD_AF_INET:
@@ -1001,7 +964,7 @@ fbsd_core_info_proc_files (struct gdbarch *gdbarch)
       return;
     }
 
-  size_t note_size = bfd_get_section_size (section);
+  size_t note_size = bfd_section_size (section);
   if (note_size < 4)
     error (_("malformed core note - too short for header"));
 
@@ -1134,7 +1097,7 @@ fbsd_core_info_proc_mappings (struct gdbarch *gdbarch)
       return;
     }
 
-  note_size = bfd_get_section_size (section);
+  note_size = bfd_section_size (section);
   if (note_size < 4)
     error (_("malformed core note - too short for header"));
 
@@ -1182,7 +1145,7 @@ fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd)
   if (section == NULL)
     return nullptr;
 
-  note_size = bfd_get_section_size (section);
+  note_size = bfd_section_size (section);
   if (note_size < 4)
     error (_("malformed core note - too short for header"));
 
@@ -1209,7 +1172,7 @@ fbsd_core_vnode_path (struct gdbarch *gdbarch, int fd)
          && bfd_get_signed_32 (core_bfd, descdata + KF_FD) == fd)
        {
          char *path = (char *) descdata + KF_PATH;
-         return gdb::unique_xmalloc_ptr<char> (xstrdup (path));
+         return make_unique_xstrdup (path);
        }
 
       descdata += structsize;
@@ -1287,7 +1250,7 @@ fbsd_core_info_proc_status (struct gdbarch *gdbarch)
    * structure size, then it must be long enough to access the last
    * field used (ki_rusage_ch.ru_majflt) which is the size of a long.
    */
-  note_size = bfd_get_section_size (section);
+  note_size = bfd_section_size (section);
   if (note_size < (4 + kp->ki_rusage_ch + kp->ru_majflt
                   + long_bit / TARGET_CHAR_BIT))
     error (_("malformed core note - too short"));
@@ -1376,7 +1339,7 @@ fbsd_core_info_proc_status (struct gdbarch *gdbarch)
                           sec, value);
   printf_filtered ("stime, children: %s.%06d\n", plongest (sec), (int) value);
   printf_filtered ("'nice' value: %d\n",
-                  bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice));
+                  (int) bfd_get_signed_8 (core_bfd, descdata + kp->ki_nice));
   fbsd_core_fetch_timeval (gdbarch, descdata + kp->ki_start, sec, value);
   printf_filtered ("Start time: %s.%06d\n", plongest (sec), (int) value);
   printf_filtered ("Virtual memory size: %s kB\n",
@@ -1500,12 +1463,29 @@ static void
 fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file,
                       CORE_ADDR type, CORE_ADDR val)
 {
-  const char *name;
-  const char *description;
-  enum auxv_format format;
+  const char *name = "???";
+  const char *description = "";
+  enum auxv_format format = AUXV_FORMAT_HEX;
 
   switch (type)
     {
+    case AT_NULL:
+    case AT_IGNORE:
+    case AT_EXECFD:
+    case AT_PHDR:
+    case AT_PHENT:
+    case AT_PHNUM:
+    case AT_PAGESZ:
+    case AT_BASE:
+    case AT_FLAGS:
+    case AT_ENTRY:
+    case AT_NOTELF:
+    case AT_UID:
+    case AT_EUID:
+    case AT_GID:
+    case AT_EGID:
+      default_print_auxv_entry (gdbarch, file, type, val);
+      return;
 #define _TAGNAME(tag) #tag
 #define TAGNAME(tag) _TAGNAME(AT_##tag)
 #define TAG(tag, text, kind) \
@@ -1522,9 +1502,12 @@ fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file,
       TAG (EHDRFLAGS, _("ELF header e_flags"), AUXV_FORMAT_HEX);
       TAG (HWCAP, _("Machine-dependent CPU capability hints"), AUXV_FORMAT_HEX);
       TAG (HWCAP2, _("Extension of AT_HWCAP"), AUXV_FORMAT_HEX);
-    default:
-      default_print_auxv_entry (gdbarch, file, type, val);
-      return;
+      TAG (BSDFLAGS, _("ELF BSD flags"), AUXV_FORMAT_HEX);
+      TAG (ARGC, _("Argument count"), AUXV_FORMAT_DEC);
+      TAG (ARGV, _("Argument vector"), AUXV_FORMAT_HEX);
+      TAG (ENVC, _("Environment count"), AUXV_FORMAT_DEC);
+      TAG (ENVV, _("Environment vector"), AUXV_FORMAT_HEX);
+      TAG (PS_STRINGS, _("Pointer to ps_strings"), AUXV_FORMAT_HEX);
     }
 
   fprint_auxv_entry (file, name, description, format, type, val);
@@ -1556,7 +1539,7 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch)
 
   /* union sigval */
   sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
-  TYPE_NAME (sigval_type) = xstrdup ("sigval");
+  sigval_type->set_name (xstrdup ("sigval"));
   append_composite_type_field (sigval_type, "sival_int", int_type);
   append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type);
 
@@ -1564,14 +1547,14 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch)
   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;
+  pid_type->set_target_is_stub (true);
 
   /* __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;
+  pid_type->set_target_is_stub (true);
 
   /* _reason */
   reason_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
@@ -1606,7 +1589,7 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch)
 
   /* struct siginfo */
   siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
-  TYPE_NAME (siginfo_type) = xstrdup ("siginfo");
+  siginfo_type->set_name (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);
@@ -1622,6 +1605,249 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch)
   return siginfo_type;
 }
 
+/* Implement the "gdb_signal_from_target" gdbarch method.  */
+
+static enum gdb_signal
+fbsd_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
+{
+  switch (signal)
+    {
+    case 0:
+      return GDB_SIGNAL_0;
+
+    case FREEBSD_SIGHUP:
+      return GDB_SIGNAL_HUP;
+
+    case FREEBSD_SIGINT:
+      return GDB_SIGNAL_INT;
+
+    case FREEBSD_SIGQUIT:
+      return GDB_SIGNAL_QUIT;
+
+    case FREEBSD_SIGILL:
+      return GDB_SIGNAL_ILL;
+
+    case FREEBSD_SIGTRAP:
+      return GDB_SIGNAL_TRAP;
+
+    case FREEBSD_SIGABRT:
+      return GDB_SIGNAL_ABRT;
+
+    case FREEBSD_SIGEMT:
+      return GDB_SIGNAL_EMT;
+
+    case FREEBSD_SIGFPE:
+      return GDB_SIGNAL_FPE;
+
+    case FREEBSD_SIGKILL:
+      return GDB_SIGNAL_KILL;
+
+    case FREEBSD_SIGBUS:
+      return GDB_SIGNAL_BUS;
+
+    case FREEBSD_SIGSEGV:
+      return GDB_SIGNAL_SEGV;
+
+    case FREEBSD_SIGSYS:
+      return GDB_SIGNAL_SYS;
+
+    case FREEBSD_SIGPIPE:
+      return GDB_SIGNAL_PIPE;
+
+    case FREEBSD_SIGALRM:
+      return GDB_SIGNAL_ALRM;
+
+    case FREEBSD_SIGTERM:
+      return GDB_SIGNAL_TERM;
+
+    case FREEBSD_SIGURG:
+      return GDB_SIGNAL_URG;
+
+    case FREEBSD_SIGSTOP:
+      return GDB_SIGNAL_STOP;
+
+    case FREEBSD_SIGTSTP:
+      return GDB_SIGNAL_TSTP;
+
+    case FREEBSD_SIGCONT:
+      return GDB_SIGNAL_CONT;
+
+    case FREEBSD_SIGCHLD:
+      return GDB_SIGNAL_CHLD;
+
+    case FREEBSD_SIGTTIN:
+      return GDB_SIGNAL_TTIN;
+
+    case FREEBSD_SIGTTOU:
+      return GDB_SIGNAL_TTOU;
+
+    case FREEBSD_SIGIO:
+      return GDB_SIGNAL_IO;
+
+    case FREEBSD_SIGXCPU:
+      return GDB_SIGNAL_XCPU;
+
+    case FREEBSD_SIGXFSZ:
+      return GDB_SIGNAL_XFSZ;
+
+    case FREEBSD_SIGVTALRM:
+      return GDB_SIGNAL_VTALRM;
+
+    case FREEBSD_SIGPROF:
+      return GDB_SIGNAL_PROF;
+
+    case FREEBSD_SIGWINCH:
+      return GDB_SIGNAL_WINCH;
+
+    case FREEBSD_SIGINFO:
+      return GDB_SIGNAL_INFO;
+
+    case FREEBSD_SIGUSR1:
+      return GDB_SIGNAL_USR1;
+
+    case FREEBSD_SIGUSR2:
+      return GDB_SIGNAL_USR2;
+
+    /* SIGTHR is the same as SIGLWP on FreeBSD. */
+    case FREEBSD_SIGTHR:
+      return GDB_SIGNAL_LWP;
+
+    case FREEBSD_SIGLIBRT:
+      return GDB_SIGNAL_LIBRT;
+    }
+
+  if (signal >= FREEBSD_SIGRTMIN && signal <= FREEBSD_SIGRTMAX)
+    {
+      int offset = signal - FREEBSD_SIGRTMIN;
+
+      return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_65 + offset);
+    }
+
+  return GDB_SIGNAL_UNKNOWN;
+}
+
+/* Implement the "gdb_signal_to_target" gdbarch method.  */
+
+static int
+fbsd_gdb_signal_to_target (struct gdbarch *gdbarch,
+               enum gdb_signal signal)
+{
+  switch (signal)
+    {
+    case GDB_SIGNAL_0:
+      return 0;
+
+    case GDB_SIGNAL_HUP:
+      return FREEBSD_SIGHUP;
+
+    case GDB_SIGNAL_INT:
+      return FREEBSD_SIGINT;
+
+    case GDB_SIGNAL_QUIT:
+      return FREEBSD_SIGQUIT;
+
+    case GDB_SIGNAL_ILL:
+      return FREEBSD_SIGILL;
+
+    case GDB_SIGNAL_TRAP:
+      return FREEBSD_SIGTRAP;
+
+    case GDB_SIGNAL_ABRT:
+      return FREEBSD_SIGABRT;
+
+    case GDB_SIGNAL_EMT:
+      return FREEBSD_SIGEMT;
+
+    case GDB_SIGNAL_FPE:
+      return FREEBSD_SIGFPE;
+
+    case GDB_SIGNAL_KILL:
+      return FREEBSD_SIGKILL;
+
+    case GDB_SIGNAL_BUS:
+      return FREEBSD_SIGBUS;
+
+    case GDB_SIGNAL_SEGV:
+      return FREEBSD_SIGSEGV;
+
+    case GDB_SIGNAL_SYS:
+      return FREEBSD_SIGSYS;
+
+    case GDB_SIGNAL_PIPE:
+      return FREEBSD_SIGPIPE;
+
+    case GDB_SIGNAL_ALRM:
+      return FREEBSD_SIGALRM;
+
+    case GDB_SIGNAL_TERM:
+      return FREEBSD_SIGTERM;
+
+    case GDB_SIGNAL_URG:
+      return FREEBSD_SIGURG;
+
+    case GDB_SIGNAL_STOP:
+      return FREEBSD_SIGSTOP;
+
+    case GDB_SIGNAL_TSTP:
+      return FREEBSD_SIGTSTP;
+
+    case GDB_SIGNAL_CONT:
+      return FREEBSD_SIGCONT;
+
+    case GDB_SIGNAL_CHLD:
+      return FREEBSD_SIGCHLD;
+
+    case GDB_SIGNAL_TTIN:
+      return FREEBSD_SIGTTIN;
+
+    case GDB_SIGNAL_TTOU:
+      return FREEBSD_SIGTTOU;
+
+    case GDB_SIGNAL_IO:
+      return FREEBSD_SIGIO;
+
+    case GDB_SIGNAL_XCPU:
+      return FREEBSD_SIGXCPU;
+
+    case GDB_SIGNAL_XFSZ:
+      return FREEBSD_SIGXFSZ;
+
+    case GDB_SIGNAL_VTALRM:
+      return FREEBSD_SIGVTALRM;
+
+    case GDB_SIGNAL_PROF:
+      return FREEBSD_SIGPROF;
+
+    case GDB_SIGNAL_WINCH:
+      return FREEBSD_SIGWINCH;
+
+    case GDB_SIGNAL_INFO:
+      return FREEBSD_SIGINFO;
+
+    case GDB_SIGNAL_USR1:
+      return FREEBSD_SIGUSR1;
+
+    case GDB_SIGNAL_USR2:
+      return FREEBSD_SIGUSR2;
+
+    case GDB_SIGNAL_LWP:
+      return FREEBSD_SIGTHR;
+
+    case GDB_SIGNAL_LIBRT:
+      return FREEBSD_SIGLIBRT;
+    }
+
+  if (signal >= GDB_SIGNAL_REALTIME_65
+      && signal <= GDB_SIGNAL_REALTIME_126)
+    {
+      int offset = signal - GDB_SIGNAL_REALTIME_65;
+
+      return FREEBSD_SIGRTMIN + offset;
+    }
+
+  return -1;
+}
+
 /* Implement the "get_syscall_number" gdbarch method.  */
 
 static LONGEST
@@ -1637,6 +1863,131 @@ fbsd_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread)
   internal_error (__FILE__, __LINE__, _("fbsd_get_sycall_number called"));
 }
 
+/* Read an integer symbol value from the current target.  */
+
+static LONGEST
+fbsd_read_integer_by_name (struct gdbarch *gdbarch, const char *name)
+{
+  bound_minimal_symbol ms = lookup_minimal_symbol (name, NULL, NULL);
+  if (ms.minsym == NULL)
+    error (_("Unable to resolve symbol '%s'"), name);
+
+  gdb_byte buf[4];
+  if (target_read_memory (BMSYMBOL_VALUE_ADDRESS (ms), buf, sizeof buf) != 0)
+    error (_("Unable to read value of '%s'"), name);
+
+  return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch));
+}
+
+/* Lookup offsets of fields in the runtime linker's 'Obj_Entry'
+   structure needed to determine the TLS index of an object file.  */
+
+static void
+fbsd_fetch_rtld_offsets (struct gdbarch *gdbarch, struct fbsd_pspace_data *data)
+{
+  try
+    {
+      /* Fetch offsets from debug symbols in rtld.  */
+      struct symbol *obj_entry_sym
+       = lookup_symbol_in_language ("Struct_Obj_Entry", NULL, STRUCT_DOMAIN,
+                                    language_c, NULL).symbol;
+      if (obj_entry_sym == NULL)
+       error (_("Unable to find Struct_Obj_Entry symbol"));
+      data->off_linkmap = lookup_struct_elt (SYMBOL_TYPE (obj_entry_sym),
+                                            "linkmap", 0).offset / 8;
+      data->off_tlsindex = lookup_struct_elt (SYMBOL_TYPE (obj_entry_sym),
+                                             "tlsindex", 0).offset / 8;
+      data->rtld_offsets_valid = true;
+      return;
+    }
+  catch (const gdb_exception_error &e)
+    {
+      data->off_linkmap = -1;
+    }
+
+  try
+    {
+      /* Fetch offsets from global variables in libthr.  Note that
+        this does not work for single-threaded processes that are not
+        linked against libthr.  */
+      data->off_linkmap = fbsd_read_integer_by_name (gdbarch,
+                                                    "_thread_off_linkmap");
+      data->off_tlsindex = fbsd_read_integer_by_name (gdbarch,
+                                                     "_thread_off_tlsindex");
+      data->rtld_offsets_valid = true;
+      return;
+    }
+  catch (const gdb_exception_error &e)
+    {
+      data->off_linkmap = -1;
+    }
+}
+
+/* Helper function to read the TLS index of an object file associated
+   with a link map entry at LM_ADDR.  */
+
+static LONGEST
+fbsd_get_tls_index (struct gdbarch *gdbarch, CORE_ADDR lm_addr)
+{
+  struct fbsd_pspace_data *data = get_fbsd_pspace_data (current_program_space);
+
+  if (!data->rtld_offsets_valid)
+    fbsd_fetch_rtld_offsets (gdbarch, data);
+
+  if (data->off_linkmap == -1)
+    throw_error (TLS_GENERIC_ERROR,
+                _("Cannot fetch runtime linker structure offsets"));
+
+  /* Simulate container_of to convert from LM_ADDR to the Obj_Entry
+     pointer and then compute the offset of the tlsindex member.  */
+  CORE_ADDR tlsindex_addr = lm_addr - data->off_linkmap + data->off_tlsindex;
+
+  gdb_byte buf[4];
+  if (target_read_memory (tlsindex_addr, buf, sizeof buf) != 0)
+    throw_error (TLS_GENERIC_ERROR,
+                _("Cannot find thread-local variables on this target"));
+
+  return extract_signed_integer (buf, sizeof buf, gdbarch_byte_order (gdbarch));
+}
+
+/* See fbsd-tdep.h.  */
+
+CORE_ADDR
+fbsd_get_thread_local_address (struct gdbarch *gdbarch, CORE_ADDR dtv_addr,
+                              CORE_ADDR lm_addr, CORE_ADDR offset)
+{
+  LONGEST tls_index = fbsd_get_tls_index (gdbarch, lm_addr);
+
+  gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT];
+  if (target_read_memory (dtv_addr, buf, sizeof buf) != 0)
+    throw_error (TLS_GENERIC_ERROR,
+                _("Cannot find thread-local variables on this target"));
+
+  const struct builtin_type *builtin = builtin_type (gdbarch);
+  CORE_ADDR addr = gdbarch_pointer_to_address (gdbarch,
+                                              builtin->builtin_data_ptr, buf);
+
+  addr += (tls_index + 1) * TYPE_LENGTH (builtin->builtin_data_ptr);
+  if (target_read_memory (addr, buf, sizeof buf) != 0)
+    throw_error (TLS_GENERIC_ERROR,
+                _("Cannot find thread-local variables on this target"));
+
+  addr = gdbarch_pointer_to_address (gdbarch, builtin->builtin_data_ptr, buf);
+  return addr + offset;
+}
+
+/* See fbsd-tdep.h.  */
+
+CORE_ADDR
+fbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  struct bound_minimal_symbol msym = lookup_bound_minimal_symbol ("_rtld_bind");
+  if (msym.minsym != nullptr && BMSYMBOL_VALUE_ADDRESS (msym) == pc)
+    return frame_unwind_caller_pc (get_current_frame ());
+
+  return 0;
+}
+
 /* To be called from GDB_OSABI_FREEBSD handlers. */
 
 void
@@ -1649,14 +2000,18 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_core_info_proc (gdbarch, fbsd_core_info_proc);
   set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry);
   set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type);
+  set_gdbarch_gdb_signal_from_target (gdbarch, fbsd_gdb_signal_from_target);
+  set_gdbarch_gdb_signal_to_target (gdbarch, fbsd_gdb_signal_to_target);
+  set_gdbarch_skip_solib_resolver (gdbarch, fbsd_skip_solib_resolver);
 
   /* `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
-_initialize_fbsd_tdep (void)
+_initialize_fbsd_tdep ()
 {
   fbsd_gdbarch_data_handle =
     gdbarch_data_register_post_init (init_fbsd_gdbarch_data);
This page took 0.036404 seconds and 4 git commands to generate.