From patchwork Wed Dec 14 17:33:58 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Terekhov, Mikhail via Gdb-patches" X-Patchwork-Id: 18456 Received: (qmail 47131 invoked by alias); 14 Dec 2016 17:34:11 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 47117 invoked by uid 89); 14 Dec 2016 17:34:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.6 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=longest, H*M:sk:001a114, H*MI:sk:001a114, xstrdup X-HELO: mail-oi0-f73.google.com Received: from mail-oi0-f73.google.com (HELO mail-oi0-f73.google.com) (209.85.218.73) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 14 Dec 2016 17:33:59 +0000 Received: by mail-oi0-f73.google.com with SMTP id v129so1342970oif.0 for ; Wed, 14 Dec 2016 09:33:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:message-id:date:subject:from:to; bh=MiDiaoKFJfPLk1fBkOjaEBFu4AooRxqsOQvQGfOuTsw=; b=Sb4yd7C9DW/hLxpyBlBItrMw685WqbdniFgfd7wMkWtpZx83QgblFVJVLRiZPs7kIk p8hVG8niwYjnRG41/f6Y5Duc012itOka8Y37XgmD+Mc0H1dMTjfm6bNel6G7XaCPb+vS ryGYlETJO2ocyNxJ1ttAj5qvtPpE5ZKnteSquxqVpALbJUq42yFC/XdbFnjlGx74cEHA 4xySvheaMX/PGZzPmJYG4gmVZ9NROBaRYb/Sfsn9dhTinEFINJJL2OhesOpubvoR3uyv IH8/Jzc4X2Xr8gZ3cfvq1A7ZRPEpBOzlWF+FkTwJ1Gz7VLPfgMc6WrSy9+/pYBrsVgye a3oA== X-Gm-Message-State: AKaTC027mVaQY4gdIli5xqmzQCKnNU5xzTGTLhR5RhknTy9c0DOEowhL04d8nWm/Ju5lmn637dbd/ORu4dLE2VKQxRyXD84zvNsXLqmO39kfI2GR5g921szrz8GTmpPH6X1tk+4vd6jkqf+yxr03rUoKVoiDeuibLW7vaJUGjuqo3PJUFiqv1A== MIME-Version: 1.0 X-Received: by 10.157.52.240 with SMTP id t45mr26263352otd.148.1481736838047; Wed, 14 Dec 2016 09:33:58 -0800 (PST) Message-ID: <001a1141ca8ce24b530543a1bd14@google.com> Date: Wed, 14 Dec 2016 17:33:58 +0000 Subject: [RFC] Fuchsia amd64 port X-Patchwork-Original-From: "Doug Evans via gdb-patches" From: "Terekhov, Mikhail via Gdb-patches" Reply-To: Doug Evans To: gdb-patches@sourceware.org X-IsSubscribed: yes Hi. This is still a work in progress, but with this patch and some patches still to check into Fuchsia's gdbserver, and a patch to qemu to fix amd64 syscall/sysret handling, some things are starting to work. Lots lots more to go of course. https://fuchsia.googlesource.com/fuchsia/ + #endif /* solib-svr4.h */ diff --git a/bfd/config.bfd b/bfd/config.bfd index b692f0a..8d461e2 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -766,7 +766,7 @@ case "${targ}" in targ_selvecs="i386_elf32_vec iamcu_elf32_vec l1om_elf64_vec k1om_elf64_vec" want64=true ;; - x86_64-*-elf* | x86_64-*-rtems*) + x86_64-*-elf* | x86_64-*-fuchsia* | x86_64-*-rtems*) targ_defvec=x86_64_elf64_vec targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec l1om_elf64_vec k1om_elf64_vec" want64=true 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 . */ + +#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..006d048 --- /dev/null +++ b/gdb/amd64-fuchsia-tdep.h @@ -0,0 +1,33 @@ +/* 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 . */ + +#ifndef AMD64_FUCHSIA_TDEP_H +#define AMD64_FUCHSIA_TDEP_H + +/* Total number of registers for Fuchsia. */ +#define AMD64_FUCHSIA_NUM_REGS (AMD64_ZMM31H_REGNUM + 1) + +/* Fuchsia target description. */ // TODO +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 /* 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 @@ auxv_inferior_data_cleanup (struct inferior *inf, void *arg) /* 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_parse (struct target_ops *ops, 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-*-dicos*) 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 @@ esac 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 @@ enum gdb_osabi 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..4dfd78b --- /dev/null +++ b/gdb/fuchsia-tdep.c @@ -0,0 +1,744 @@ +/* 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 . */ + +/* 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 + +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 , + 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 , + 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; + } + + extern void svr4_handle_solib_event (void); + svr4_handle_solib_event (); +} + +/* 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 . */ + +#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 @@ static const struct osabi_names gdb_osabi_names[] = { "LynxOS178", NULL }, { "Newlib", NULL }, { "SDE", NULL }, + { "Fuchsia", NULL }, { "", NULL } }; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 0e18292..4aa1318 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. */ @@ -1911,7 +1910,9 @@ disable_probes_interface_cleanup (void *arg) probes-based linker interface. Do nothing if using the standard interface. */ -static void +extern void svr4_handle_solib_event (void); + +void svr4_handle_solib_event (void) { struct svr4_info *info = get_svr4_info (); @@ -2988,12 +2989,9 @@ svr4_exec_displacement (CORE_ADDR *displacementp) 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..46467a5 100644 --- a/gdb/solib-svr4.h +++ b/gdb/solib-svr4.h @@ -84,4 +84,10 @@ extern struct link_map_offsets *svr4_lp64_fetch_link_map_offsets (void); 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. */ +void svr4_relocate_main_executable (void);