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 (¤t_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,
+ ¤t_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 */