Beginnings of Fuchsia amd64 port.

Lots lots more to go, but some basic things are working at this point.

Change-Id: I871a0f2cd459a167b25fe2cdc9e7c299c9a37872
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 59c39fe..32acb09 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,18 @@
+2016-12-14  Doug Evans  <dje@google.com>
+
+	Beginnings of Fuchsia amd64 port.
+	* amd64-fuchsia-tdep.c: New file.
+	* amd64-fuchsia-tdep.h: New file.
+	* fuchsia-tdep.c: New file.
+	* fuchsia-tdep.h: New file.
+	* auxv.c (invalidate_auxv_cache_inf): Make non-static.
+	* auxv.h (invalidate_auxv_cache_inf): Declare
+	* configure.tgt: Add x86_64-*-fuchsia*.
+	* defs.h (enum gdb_osabi): Add GDB_OSABI_FUCHSIA.
+	* osabi.c (gdb_osabi_names): Add Fuchsia.
+	* solib-svr4.c (svr4_relocate_main_executable): Make non-static
+	* solib-svr4.h (svr4_relocate_main_executable): Declare.
+
 2016-11-28  Simon Marchi  <simon.marchi@polymtl.ca>
 
 	* record-full.c (record_full_open_1): Fix debug output.
diff --git a/gdb/amd64-fuchsia-tdep.c b/gdb/amd64-fuchsia-tdep.c
new file mode 100644
index 0000000..d40852a
--- /dev/null
+++ b/gdb/amd64-fuchsia-tdep.c
@@ -0,0 +1,83 @@
+/* Target-dependent code for Fuchsia x86-64.
+
+   Copyright (C) 2001-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "reggroups.h"
+#include "regset.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include "amd64-fuchsia-tdep.h"
+#include "fuchsia-tdep.h"
+#include "amd64-tdep.h"
+
+static int
+amd64_fuchsia_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+				 struct reggroup *group)
+{ 
+  return i386_register_reggroup_p (gdbarch, regnum, group);
+}
+
+static void
+amd64_fuchsia_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  const struct target_desc *tdesc = info.target_desc;
+  struct tdesc_arch_data *tdesc_data
+    = (struct tdesc_arch_data *) info.tdep_info;
+
+  gdb_assert (tdesc_data);
+
+  amd64_init_abi (info, gdbarch);
+
+  fuchsia_init_abi (info, gdbarch);
+
+  tdep->register_reggroup_p = amd64_fuchsia_register_reggroup_p;
+
+  /* Displaced stepping.  */
+  set_gdbarch_displaced_step_copy_insn (gdbarch,
+					amd64_displaced_step_copy_insn);
+  set_gdbarch_displaced_step_fixup (gdbarch, amd64_displaced_step_fixup);
+  set_gdbarch_displaced_step_free_closure (gdbarch,
+					   simple_displaced_step_free_closure);
+  set_gdbarch_displaced_step_location (gdbarch,
+				       fuchsia_displaced_step_location);
+
+  // TODO:
+  // - set_gdbarch_handle_segmentation_fault
+  //   to display extra info for MPX boundary violations.
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern void _initialize_amd64_fuchsia_tdep (void);
+
+void
+_initialize_amd64_fuchsia_tdep (void)
+{
+  gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+				  fuchsia_osabi_sniffer);
+  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+			  GDB_OSABI_FUCHSIA, amd64_fuchsia_init_abi);
+}
diff --git a/gdb/amd64-fuchsia-tdep.h b/gdb/amd64-fuchsia-tdep.h
new file mode 100644
index 0000000..ab7698c
--- /dev/null
+++ b/gdb/amd64-fuchsia-tdep.h
@@ -0,0 +1,32 @@
+/* Target-dependent code for Fuchsia AMD64.
+
+   Copyright (C) 2006-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef AMD64_FUCHSIA_TDEP_H
+#define AMD64_FUCHSIA_TDEP_H
+
+/* Fuchsia target description.  */
+#if 0 // wip, may not be needed
+extern struct target_desc *tdesc_amd64_fuchsia;
+extern struct target_desc *tdesc_amd64_avx_fuchsia;
+extern struct target_desc *tdesc_amd64_mpx_fuchsia;
+extern struct target_desc *tdesc_amd64_avx_mpx_fuchsia;
+extern struct target_desc *tdesc_amd64_avx512_fuchsia;
+#endif
+
+#endif /* amd64-fuchsia-tdep.h */
diff --git a/gdb/auxv.c b/gdb/auxv.c
index de9205d..203b814 100644
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -331,7 +331,7 @@
 
 /* Invalidate INF's auxv cache.  */
 
-static void
+void
 invalidate_auxv_cache_inf (struct inferior *inf)
 {
   auxv_inferior_data_cleanup (inf, NULL);
diff --git a/gdb/auxv.h b/gdb/auxv.h
index 916f674..57099e9 100644
--- a/gdb/auxv.h
+++ b/gdb/auxv.h
@@ -46,6 +46,11 @@
 extern int target_auxv_search (struct target_ops *ops,
 			       CORE_ADDR match, CORE_ADDR *valp);
 
+/* Invalidate INF's auxv cache.  */
+
+struct inferior;
+extern void invalidate_auxv_cache_inf (struct inferior *inf);
+
 /* Print a description of a single AUXV entry on the specified file.  */
 enum auxv_format { AUXV_FORMAT_DEC, AUXV_FORMAT_HEX, AUXV_FORMAT_STR };
 
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 3a1ea6f..502a46b 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -669,6 +669,11 @@
 x86_64-*-elf*)
 	gdb_target_obs="amd64-tdep.o i386-tdep.o i387-tdep.o"
 	;;
+x86_64-*-fuchsia*)
+	gdb_target_obs="amd64-tdep.o amd64-fuchsia-tdep.o \
+			i386-tdep.o i387-tdep.o \
+			solib-svr4.o symfile-mem.o fuchsia-tdep.o"
+	;;
 x86_64-*-linux*)
 	# Target: GNU/Linux x86-64
 	gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o i386-tdep.o \
@@ -721,6 +726,7 @@
 case "${targ}" in
 *-*-freebsd* | *-*-kfreebsd*-gnu)
 		gdb_osabi=GDB_OSABI_FREEBSD_ELF ;;
+*-*-fuchsia*)	gdb_osabi=GDB_OSABI_FUCHSIA ;;
 *-*-linux* | *-*-uclinux*)
 		gdb_osabi=GDB_OSABI_LINUX ;;
 *-*-nto*)	gdb_osabi=GDB_OSABI_QNXNTO ;;
diff --git a/gdb/defs.h b/gdb/defs.h
index 3d21f62..7dfccfd 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -593,6 +593,7 @@
   GDB_OSABI_LYNXOS178,
   GDB_OSABI_NEWLIB,
   GDB_OSABI_SDE,
+  GDB_OSABI_FUCHSIA,
 
   GDB_OSABI_INVALID		/* keep this last */
 };
diff --git a/gdb/fuchsia-tdep.c b/gdb/fuchsia-tdep.c
new file mode 100644
index 0000000..5eef0af
--- /dev/null
+++ b/gdb/fuchsia-tdep.c
@@ -0,0 +1,743 @@
+/* Target-dependent code for Fuchsia, architecture independent.
+
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* TODO: This is taken from linux-tdep.c.
+   Converting it to fuchsia is a work-in-progress.  */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "fuchsia-tdep.h"
+#include "auxv.h"
+#include "target.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
+#include "elf/common.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "inferior.h"
+#include "cli/cli-utils.h"
+#include "arch-utils.h"
+#include "gdb_obstack.h"
+#include "observer.h"
+#include "objfiles.h"
+#include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
+#include "solib.h"
+#include "solib-svr4.h"
+#include "solist.h"
+#include "common/enum-flags.h"
+
+#include <ctype.h>
+
+static struct target_so_ops fuchsia_so_ops;
+
+/* Signal numbers of the Fuchsia kernel.
+   TODO: Work-in-progress.  */
+
+enum
+  {
+    FUCHSIA_SIGHUP = 1,
+    FUCHSIA_SIGINT = 2,
+    FUCHSIA_SIGQUIT = 3,
+    FUCHSIA_SIGILL = 4,
+    FUCHSIA_SIGTRAP = 5,
+    FUCHSIA_SIGABRT = 6,
+    FUCHSIA_SIGIOT = 6,
+    FUCHSIA_SIGBUS = 7,
+    FUCHSIA_SIGFPE = 8,
+    FUCHSIA_SIGKILL = 9,
+    FUCHSIA_SIGUSR1 = 10,
+    FUCHSIA_SIGSEGV = 11,
+    FUCHSIA_SIGUSR2 = 12,
+    FUCHSIA_SIGPIPE = 13,
+    FUCHSIA_SIGALRM = 14,
+    FUCHSIA_SIGTERM = 15,
+    FUCHSIA_SIGSTKFLT = 16,
+    FUCHSIA_SIGCHLD = 17,
+    FUCHSIA_SIGCONT = 18,
+    FUCHSIA_SIGSTOP = 19,
+    FUCHSIA_SIGTSTP = 20,
+    FUCHSIA_SIGTTIN = 21,
+    FUCHSIA_SIGTTOU = 22,
+    FUCHSIA_SIGURG = 23,
+    FUCHSIA_SIGXCPU = 24,
+    FUCHSIA_SIGXFSZ = 25,
+    FUCHSIA_SIGVTALRM = 26,
+    FUCHSIA_SIGPROF = 27,
+    FUCHSIA_SIGWINCH = 28,
+    FUCHSIA_SIGIO = 29,
+    FUCHSIA_SIGPOLL = FUCHSIA_SIGIO,
+    FUCHSIA_SIGPWR = 30,
+    FUCHSIA_SIGSYS = 31,
+    FUCHSIA_SIGUNUSED = 31,
+
+    FUCHSIA_SIGRTMIN = 32,
+    FUCHSIA_SIGRTMAX = 64,
+  };
+
+static struct gdbarch_data *fuchsia_gdbarch_data_handle;
+
+struct fuchsia_gdbarch_data
+  {
+    struct type *siginfo_type;
+  };
+
+static void *
+init_fuchsia_gdbarch_data (struct gdbarch *gdbarch)
+{
+  return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct fuchsia_gdbarch_data);
+}
+
+static struct fuchsia_gdbarch_data *
+get_fuchsia_gdbarch_data (struct gdbarch *gdbarch)
+{
+  return ((struct fuchsia_gdbarch_data *)
+	  gdbarch_data (gdbarch, fuchsia_gdbarch_data_handle));
+}
+
+/* Per-inferior data key.  */
+static const struct inferior_data *fuchsia_inferior_data;
+
+/* Fuchsia-specific cached data.  This is used by GDB for caching
+   purposes for each inferior.  This helps reduce the overhead of
+   transfering data from a remote target to the local host.  */
+struct fuchsia_info
+{
+  // True if the exec displacement of this inferior has been calculated.
+  bool exec_displacement_known;
+
+  /* Cache of the inferior's vsyscall/vDSO mapping range.  Only valid
+     if VSYSCALL_RANGE_P is positive.  This is cached because getting
+     at this info requires an auxv lookup (which is itself cached),
+     and looking through the inferior's mappings (which change
+     throughout execution and therefore cannot be cached).  */
+  struct mem_range vsyscall_range;
+
+  /* Zero if we haven't tried looking up the vsyscall's range before
+     yet.  Positive if we tried looking it up, and found it.  Negative
+     if we tried looking it up but failed.  */
+  int vsyscall_range_p;
+};
+
+/* Frees whatever allocated space there is to be freed and sets INF's
+   fuchsia cache data pointer to NULL.  */
+
+static void
+invalidate_fuchsia_cache_inf (struct inferior *inf)
+{
+  struct fuchsia_info *info;
+
+  info = (struct fuchsia_info *) inferior_data (inf, fuchsia_inferior_data);
+  if (info != NULL)
+    {
+      xfree (info);
+      set_inferior_data (inf, fuchsia_inferior_data, NULL);
+    }
+}
+
+/* Handles the cleanup of the fuchsia cache for inferior INF.  ARG is
+   ignored.  Callback for the inferior_appeared and inferior_exit
+   events.  */
+
+static void
+fuchsia_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+  invalidate_fuchsia_cache_inf (inf);
+}
+
+/* Fetch the fuchsia cache info for INF.  This function always returns a
+   valid INFO pointer.  */
+
+static struct fuchsia_info *
+get_fuchsia_inferior_data (void)
+{
+  struct fuchsia_info *info;
+  struct inferior *inf = current_inferior ();
+
+  info = (struct fuchsia_info *) inferior_data (inf, fuchsia_inferior_data);
+  if (info == NULL)
+    {
+      info = XCNEW (struct fuchsia_info);
+      set_inferior_data (inf, fuchsia_inferior_data, info);
+    }
+
+  return info;
+}
+
+/* siginfo is still a work-in-progress for fuchsia.  */
+
+static struct type *
+fuchsia_get_siginfo_type (struct gdbarch *gdbarch)
+{
+  struct fuchsia_gdbarch_data *fuchsia_gdbarch_data;
+  struct type *int_type;
+  struct type *siginfo_type;
+
+  fuchsia_gdbarch_data = get_fuchsia_gdbarch_data (gdbarch);
+  if (fuchsia_gdbarch_data->siginfo_type != NULL)
+    return fuchsia_gdbarch_data->siginfo_type;
+
+  int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+			 	0, "int");
+
+  /* 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);
+
+  fuchsia_gdbarch_data->siginfo_type = siginfo_type;
+
+  return siginfo_type;
+}
+
+/* Implementation of `gdbarch_gdb_signal_from_target', as defined in
+   gdbarch.h.  This function is not static because it is exported to
+   other -tdep files.  */
+
+enum gdb_signal
+fuchsia_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
+{
+  switch (signal)
+    {
+    case 0:
+      return GDB_SIGNAL_0;
+
+    case FUCHSIA_SIGHUP:
+      return GDB_SIGNAL_HUP;
+
+    case FUCHSIA_SIGINT:
+      return GDB_SIGNAL_INT;
+
+    case FUCHSIA_SIGQUIT:
+      return GDB_SIGNAL_QUIT;
+
+    case FUCHSIA_SIGILL:
+      return GDB_SIGNAL_ILL;
+
+    case FUCHSIA_SIGTRAP:
+      return GDB_SIGNAL_TRAP;
+
+    case FUCHSIA_SIGABRT:
+      return GDB_SIGNAL_ABRT;
+
+    case FUCHSIA_SIGBUS:
+      return GDB_SIGNAL_BUS;
+
+    case FUCHSIA_SIGFPE:
+      return GDB_SIGNAL_FPE;
+
+    case FUCHSIA_SIGKILL:
+      return GDB_SIGNAL_KILL;
+
+    case FUCHSIA_SIGUSR1:
+      return GDB_SIGNAL_USR1;
+
+    case FUCHSIA_SIGSEGV:
+      return GDB_SIGNAL_SEGV;
+
+    case FUCHSIA_SIGUSR2:
+      return GDB_SIGNAL_USR2;
+
+    case FUCHSIA_SIGPIPE:
+      return GDB_SIGNAL_PIPE;
+
+    case FUCHSIA_SIGALRM:
+      return GDB_SIGNAL_ALRM;
+
+    case FUCHSIA_SIGTERM:
+      return GDB_SIGNAL_TERM;
+
+    case FUCHSIA_SIGCHLD:
+      return GDB_SIGNAL_CHLD;
+
+    case FUCHSIA_SIGCONT:
+      return GDB_SIGNAL_CONT;
+
+    case FUCHSIA_SIGSTOP:
+      return GDB_SIGNAL_STOP;
+
+    case FUCHSIA_SIGTSTP:
+      return GDB_SIGNAL_TSTP;
+
+    case FUCHSIA_SIGTTIN:
+      return GDB_SIGNAL_TTIN;
+
+    case FUCHSIA_SIGTTOU:
+      return GDB_SIGNAL_TTOU;
+
+    case FUCHSIA_SIGURG:
+      return GDB_SIGNAL_URG;
+
+    case FUCHSIA_SIGXCPU:
+      return GDB_SIGNAL_XCPU;
+
+    case FUCHSIA_SIGXFSZ:
+      return GDB_SIGNAL_XFSZ;
+
+    case FUCHSIA_SIGVTALRM:
+      return GDB_SIGNAL_VTALRM;
+
+    case FUCHSIA_SIGPROF:
+      return GDB_SIGNAL_PROF;
+
+    case FUCHSIA_SIGWINCH:
+      return GDB_SIGNAL_WINCH;
+
+    /* No way to differentiate between SIGIO and SIGPOLL.
+       Therefore, we just handle the first one.  */
+    case FUCHSIA_SIGIO:
+      return GDB_SIGNAL_IO;
+
+    case FUCHSIA_SIGPWR:
+      return GDB_SIGNAL_PWR;
+
+    case FUCHSIA_SIGSYS:
+      return GDB_SIGNAL_SYS;
+
+    /* SIGRTMIN and SIGRTMAX are not continuous in <gdb/signals.def>,
+       therefore we have to handle them here.  */
+    case FUCHSIA_SIGRTMIN:
+      return GDB_SIGNAL_REALTIME_32;
+
+    case FUCHSIA_SIGRTMAX:
+      return GDB_SIGNAL_REALTIME_64;
+    }
+
+  if (signal >= FUCHSIA_SIGRTMIN + 1 && signal <= FUCHSIA_SIGRTMAX - 1)
+    {
+      int offset = signal - FUCHSIA_SIGRTMIN + 1;
+
+      return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_33 + offset);
+    }
+
+  return GDB_SIGNAL_UNKNOWN;
+}
+
+/* Implementation of `gdbarch_gdb_signal_to_target', as defined in
+   gdbarch.h.  This function is not static because it is exported to
+   other -tdep files.  */
+
+int
+fuchsia_gdb_signal_to_target (struct gdbarch *gdbarch,
+			    enum gdb_signal signal)
+{
+  switch (signal)
+    {
+    case GDB_SIGNAL_0:
+      return 0;
+
+    case GDB_SIGNAL_HUP:
+      return FUCHSIA_SIGHUP;
+
+    case GDB_SIGNAL_INT:
+      return FUCHSIA_SIGINT;
+
+    case GDB_SIGNAL_QUIT:
+      return FUCHSIA_SIGQUIT;
+
+    case GDB_SIGNAL_ILL:
+      return FUCHSIA_SIGILL;
+
+    case GDB_SIGNAL_TRAP:
+      return FUCHSIA_SIGTRAP;
+
+    case GDB_SIGNAL_ABRT:
+      return FUCHSIA_SIGABRT;
+
+    case GDB_SIGNAL_FPE:
+      return FUCHSIA_SIGFPE;
+
+    case GDB_SIGNAL_KILL:
+      return FUCHSIA_SIGKILL;
+
+    case GDB_SIGNAL_BUS:
+      return FUCHSIA_SIGBUS;
+
+    case GDB_SIGNAL_SEGV:
+      return FUCHSIA_SIGSEGV;
+
+    case GDB_SIGNAL_SYS:
+      return FUCHSIA_SIGSYS;
+
+    case GDB_SIGNAL_PIPE:
+      return FUCHSIA_SIGPIPE;
+
+    case GDB_SIGNAL_ALRM:
+      return FUCHSIA_SIGALRM;
+
+    case GDB_SIGNAL_TERM:
+      return FUCHSIA_SIGTERM;
+
+    case GDB_SIGNAL_URG:
+      return FUCHSIA_SIGURG;
+
+    case GDB_SIGNAL_STOP:
+      return FUCHSIA_SIGSTOP;
+
+    case GDB_SIGNAL_TSTP:
+      return FUCHSIA_SIGTSTP;
+
+    case GDB_SIGNAL_CONT:
+      return FUCHSIA_SIGCONT;
+
+    case GDB_SIGNAL_CHLD:
+      return FUCHSIA_SIGCHLD;
+
+    case GDB_SIGNAL_TTIN:
+      return FUCHSIA_SIGTTIN;
+
+    case GDB_SIGNAL_TTOU:
+      return FUCHSIA_SIGTTOU;
+
+    case GDB_SIGNAL_IO:
+      return FUCHSIA_SIGIO;
+
+    case GDB_SIGNAL_XCPU:
+      return FUCHSIA_SIGXCPU;
+
+    case GDB_SIGNAL_XFSZ:
+      return FUCHSIA_SIGXFSZ;
+
+    case GDB_SIGNAL_VTALRM:
+      return FUCHSIA_SIGVTALRM;
+
+    case GDB_SIGNAL_PROF:
+      return FUCHSIA_SIGPROF;
+
+    case GDB_SIGNAL_WINCH:
+      return FUCHSIA_SIGWINCH;
+
+    case GDB_SIGNAL_USR1:
+      return FUCHSIA_SIGUSR1;
+
+    case GDB_SIGNAL_USR2:
+      return FUCHSIA_SIGUSR2;
+
+    case GDB_SIGNAL_PWR:
+      return FUCHSIA_SIGPWR;
+
+    case GDB_SIGNAL_POLL:
+      return FUCHSIA_SIGPOLL;
+
+    /* GDB_SIGNAL_REALTIME_32 is not continuous in <gdb/signals.def>,
+       therefore we have to handle it here.  */
+    case GDB_SIGNAL_REALTIME_32:
+      return FUCHSIA_SIGRTMIN;
+
+    /* Same comment applies to _64.  */
+    case GDB_SIGNAL_REALTIME_64:
+      return FUCHSIA_SIGRTMAX;
+    }
+
+  /* GDB_SIGNAL_REALTIME_33 to _64 are continuous.  */
+  if (signal >= GDB_SIGNAL_REALTIME_33
+      && signal <= GDB_SIGNAL_REALTIME_63)
+    {
+      int offset = signal - GDB_SIGNAL_REALTIME_33;
+
+      return FUCHSIA_SIGRTMIN + 1 + offset;
+    }
+
+  return -1;
+}
+
+/* Helper for fuchsia_vsyscall_range that does the real work of finding
+   the vsyscall's address range.  */
+
+static int
+fuchsia_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  return 0; // TODO
+}
+
+/* Implementation of the "vsyscall_range" gdbarch hook.  Handles
+   caching, and defers the real work to fuchsia_vsyscall_range_raw.  */
+
+static int
+fuchsia_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  struct fuchsia_info *info = get_fuchsia_inferior_data ();
+
+  if (info->vsyscall_range_p == 0)
+    {
+      if (fuchsia_vsyscall_range_raw (gdbarch, &info->vsyscall_range))
+	info->vsyscall_range_p = 1;
+      else
+	info->vsyscall_range_p = -1;
+    }
+
+  if (info->vsyscall_range_p < 0)
+    return 0;
+
+  *range = info->vsyscall_range;
+  return 1;
+}
+
+/* Symbols for fuchsia_infcall_mmap's ARG_FLAGS; their Fuchsia MAP_* system
+   definitions would be dependent on compilation host.  */
+#define GDB_MMAP_MAP_PRIVATE   0x02 /* Changes are private.  */
+#define GDB_MMAP_MAP_ANONYMOUS 0x20 /* Don't use a file.  */
+
+/* See gdbarch.sh 'infcall_mmap'.  */
+
+static CORE_ADDR
+fuchsia_infcall_mmap (CORE_ADDR size, unsigned prot)
+{
+  struct objfile *objf;
+  /* Do there still exist any Fuchsia systems without "mmap64"?
+     "mmap" uses 64-bit off_t on x86_64 and 32-bit off_t on i386 and x32.  */
+  struct value *mmap_val = find_function_in_inferior ("mmap64", &objf);
+  struct value *addr_val;
+  struct gdbarch *gdbarch = get_objfile_arch (objf);
+  CORE_ADDR retval;
+  enum
+    {
+      ARG_ADDR, ARG_LENGTH, ARG_PROT, ARG_FLAGS, ARG_FD, ARG_OFFSET, ARG_LAST
+    };
+  struct value *arg[ARG_LAST];
+
+  arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
+				      0);
+  /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
+  arg[ARG_LENGTH] = value_from_ulongest
+		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
+  gdb_assert ((prot & ~(GDB_MMAP_PROT_READ | GDB_MMAP_PROT_WRITE
+			| GDB_MMAP_PROT_EXEC))
+	      == 0);
+  arg[ARG_PROT] = value_from_longest (builtin_type (gdbarch)->builtin_int, prot);
+  arg[ARG_FLAGS] = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				       GDB_MMAP_MAP_PRIVATE
+				       | GDB_MMAP_MAP_ANONYMOUS);
+  arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
+  arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
+					0);
+  addr_val = call_function_by_hand (mmap_val, ARG_LAST, arg);
+  retval = value_as_address (addr_val);
+  if (retval == (CORE_ADDR) -1)
+    error (_("Failed inferior mmap call for %s bytes, errno is changed."),
+	   pulongest (size));
+  return retval;
+}
+
+/* See gdbarch.sh 'infcall_munmap'.  */
+
+static void
+fuchsia_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
+{
+  struct objfile *objf;
+  struct value *munmap_val = find_function_in_inferior ("munmap", &objf);
+  struct value *retval_val;
+  struct gdbarch *gdbarch = get_objfile_arch (objf);
+  LONGEST retval;
+  enum
+    {
+      ARG_ADDR, ARG_LENGTH, ARG_LAST
+    };
+  struct value *arg[ARG_LAST];
+
+  arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
+				      addr);
+  /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
+  arg[ARG_LENGTH] = value_from_ulongest
+		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
+  retval_val = call_function_by_hand (munmap_val, ARG_LAST, arg);
+  retval = value_as_long (retval_val);
+  if (retval != 0)
+    warning (_("Failed inferior munmap call at %s for %s bytes, "
+	       "errno is changed."),
+	     hex_string (addr), pulongest (size));
+}
+
+/* See fuchsia-tdep.h.  */
+
+CORE_ADDR
+fuchsia_displaced_step_location (struct gdbarch *gdbarch)
+{
+  CORE_ADDR addr;
+  int bp_len;
+
+  // TODO: We're assuming this is called after the first
+  // dynamic linker breakpoint has been hit (where we know the
+  // executable has been loaded). Could try to use the interpreter's
+  // entry point here.
+  /* Determine entry point from target auxiliary vector.  This avoids
+     the need for symbols.  */
+  if (target_auxv_search (&current_target, AT_ENTRY, &addr) <= 0)
+    throw_error (NOT_SUPPORTED_ERROR,
+		 _("Cannot find AT_ENTRY auxiliary vector entry."));
+
+  /* Make certain that the address points at real code, and not a
+     function descriptor.  */
+  addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+					     &current_target);
+
+  /* Inferior calls also use the entry point as a breakpoint location.
+     We don't want displaced stepping to interfere with those
+     breakpoints, so leave space.  */
+  gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
+  addr += bp_len * 2;
+
+  return addr;
+}
+
+/* For Fuchsia we can't relocate the main executable until after we get
+   to the shlib event breakpoint: The main executable is not loaded until
+   the dynamic linker loads it.  */
+
+static void
+fuchsia_handle_solib_event (void)
+{
+  struct fuchsia_info *info = get_fuchsia_inferior_data ();
+
+  if (!info->exec_displacement_known)
+    {
+      // Presumably this is the first time we've hit the dynamic linker bkpt.
+      // It is now that the main executable has been loaded. To fetch the
+      // necessary info (e.g., AT_ENTRY) we need to flush the auxv cache so
+      // gdb will refetch it.
+      invalidate_auxv_cache_inf (current_inferior ());
+      svr4_relocate_main_executable ();
+      info->exec_displacement_known = true;
+    }
+
+  /* If fuchsia starts using probes, call svr4_handle_solib_event here.  */
+}
+
+/* To be called from the various GDB_OSABI_FUCHSIA handlers for the
+   various Fuchsia architectures and machine types.  */
+
+void
+fuchsia_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  set_gdbarch_gdb_signal_from_target (gdbarch,
+				      fuchsia_gdb_signal_from_target);
+  set_gdbarch_gdb_signal_to_target (gdbarch,
+				    fuchsia_gdb_signal_to_target);
+  set_gdbarch_vsyscall_range (gdbarch, fuchsia_vsyscall_range);
+  set_gdbarch_infcall_mmap (gdbarch, fuchsia_infcall_mmap);
+  set_gdbarch_infcall_munmap (gdbarch, fuchsia_infcall_munmap);
+  set_gdbarch_get_siginfo_type (gdbarch, fuchsia_get_siginfo_type);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+					     svr4_fetch_objfile_link_map);
+
+  /* Fuchsia uses SVR4-style shared libraries.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+  /* Fuchsia uses its own dynamic linker.  */
+  set_gdbarch_skip_solib_resolver (gdbarch, fuchsia_skip_solib_resolver);
+
+  /* Fuchsia uses SVR4-style shared libraries.
+     Note: This also calls set_solib_ops.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+
+  /* But we need to use our own so_ops vtable to handle exec displacement
+     computation.
+     Initialize this lazily, to avoid an initialization order
+     dependency on solib-svr4.c's _initialize routine.  */
+  if (fuchsia_so_ops.handle_event == NULL)
+    {
+      fuchsia_so_ops = svr4_so_ops;
+      fuchsia_so_ops.handle_event = fuchsia_handle_solib_event;
+    }
+  set_solib_ops (gdbarch, &fuchsia_so_ops);
+}
+
+/* Calling functions in shared libraries.
+   See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
+   This function:
+   1) decides whether a PLT has sent us into the linker to resolve
+      a function reference, and
+   2) if so, tells us where to set a temporary breakpoint that will
+      trigger when the dynamic linker is done.  */
+
+CORE_ADDR
+fuchsia_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  // TODO: Update for fuchsia/musl.
+  /* The GNU dynamic linker is part of the GNU C library, and is used
+     by all GNU systems (GNU/Hurd, GNU/Linux).  An unresolved PLT
+     entry points to "_dl_runtime_resolve", which calls "fixup" to
+     patch the PLT, and then passes control to the function.
+
+     We look for the symbol `_dl_runtime_resolve', and find `fixup' in
+     the same objfile.  If we are at the entry point of `fixup', then
+     we set a breakpoint at the return address (at the top of the
+     stack), and continue.
+
+     It's kind of gross to do all these checks every time we're
+     called, since they don't change once the executable has gotten
+     started.  But this is only a temporary hack --- upcoming versions
+     of GNU/Linux will provide a portable, efficient interface for
+     debugging programs that use shared libraries.  */
+
+  struct bound_minimal_symbol resolver
+    = lookup_minimal_symbol_and_objfile ("_dl_runtime_resolve");
+
+  if (resolver.minsym)
+    {
+      /* The dynamic linker began using this name in early 2005.  */
+      struct bound_minimal_symbol fixup
+	= lookup_minimal_symbol ("_dl_fixup", NULL, resolver.objfile);
+
+      /* This is the name used in older versions.  */
+      if (! fixup.minsym)
+        fixup = lookup_minimal_symbol ("fixup", NULL, resolver.objfile);
+
+      if (fixup.minsym && BMSYMBOL_VALUE_ADDRESS (fixup) == pc)
+	return frame_unwind_caller_pc (get_current_frame ());
+    }
+
+  return 0;
+}
+
+/* Recognize Fuchsia object files.  */
+
+enum gdb_osabi
+fuchsia_osabi_sniffer (bfd *abfd)
+{
+  /* TODO: Until we have something like a fuchsia .note.ABI-tag, assume the
+     absence of .note.ABI-tag means fuchsia.  */
+  if (bfd_get_section_by_name (abfd, ".note.ABI-tag") == NULL)
+    return GDB_OSABI_FUCHSIA;
+  return GDB_OSABI_UNKNOWN;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_fuchsia_tdep;
+
+void
+_initialize_fuchsia_tdep (void)
+{
+  fuchsia_gdbarch_data_handle =
+    gdbarch_data_register_post_init (init_fuchsia_gdbarch_data);
+
+  /* Set a cache per-inferior.  */
+  fuchsia_inferior_data
+    = register_inferior_data_with_cleanup (NULL, fuchsia_inferior_data_cleanup);
+  /* Observers used to invalidate the cache when needed.  */
+  observer_attach_inferior_exit (invalidate_fuchsia_cache_inf);
+  observer_attach_inferior_appeared (invalidate_fuchsia_cache_inf);
+}
diff --git a/gdb/fuchsia-tdep.h b/gdb/fuchsia-tdep.h
new file mode 100644
index 0000000..1f7af83
--- /dev/null
+++ b/gdb/fuchsia-tdep.h
@@ -0,0 +1,45 @@
+/* Target-dependent code for Fuchsia, architecture independent.
+
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef FUCHSIA_TDEP_H
+#define FUCHSIA_TDEP_H
+
+#include "bfd.h"
+
+extern enum gdb_osabi fuchsia_osabi_sniffer (bfd *abfd);
+
+extern enum gdb_signal fuchsia_gdb_signal_from_target (struct gdbarch *gdbarch,
+						       int signal);
+
+extern int fuchsia_gdb_signal_to_target (struct gdbarch *gdbarch,
+					 enum gdb_signal signal);
+
+/* Default Fuchsia implementation of `displaced_step_location', as
+   defined in gdbarch.h.  Determines the entry point from AT_ENTRY in
+   the target auxiliary vector.
+   TODO: This AT_ENTRY is for ld.so.  */
+extern CORE_ADDR fuchsia_displaced_step_location (struct gdbarch *gdbarch);
+
+extern void fuchsia_init_abi (struct gdbarch_info info,
+			      struct gdbarch *gdbarch);
+
+extern CORE_ADDR fuchsia_skip_solib_resolver (struct gdbarch *gdbarch,
+					      CORE_ADDR);
+
+#endif /* fuchsia-tdep.h */
diff --git a/gdb/osabi.c b/gdb/osabi.c
index 8b44a85..5a5612e 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -83,6 +83,7 @@
   { "LynxOS178", NULL },
   { "Newlib", NULL },
   { "SDE", NULL },
+  { "Fuchsia", NULL },
 
   { "<invalid>", NULL }
 };
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 0e18292..735fa18 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -48,7 +48,6 @@
 
 static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
 static int svr4_have_link_map_offsets (void);
-static void svr4_relocate_main_executable (void);
 static void svr4_free_library_list (void *p_list);
 
 /* Link map info to include in an allocated so_list entry.  */
@@ -2988,12 +2987,9 @@
   return 1;
 }
 
-/* Relocate the main executable.  This function should be called upon
-   stopping the inferior process at the entry point to the program.
-   The entry point from BFD is compared to the AT_ENTRY of AUXV and if they are
-   different, the main executable is relocated by the proper amount.  */
+/* See solib-svr4.h.  */
 
-static void
+void
 svr4_relocate_main_executable (void)
 {
   CORE_ADDR displacement;
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index d541136..996d4aa 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -84,4 +84,10 @@
    SVR4 run time loader.  */
 int svr4_in_dynsym_resolve_code (CORE_ADDR pc);
 
+/* Relocate the main executable.  This function should be called upon
+   stopping the inferior process at the entry point to the program.
+   The entry point from BFD is compared to the AT_ENTRY of AUXV and if they are
+   different, the main executable is relocated by the proper amount.  */
+extern void svr4_relocate_main_executable (void);
+
 #endif /* solib-svr4.h */