diff options
author | Andrew Cagney <cagney@redhat.com> | 2001-09-27 00:13:30 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2001-09-27 00:13:30 +0000 |
commit | f7d331bab53bf612f4b9f25c8ad9d4fa2deed1de (patch) | |
tree | 232a5712cf5942a68a6904b320a9cf858220b8fd | |
parent | 3a9d2e1601b21fff21d93cc9204f818d1ac3b2b7 (diff) | |
download | gdb-f7d331bab53bf612f4b9f25c8ad9d4fa2deed1de.tar.gz |
http://www10.software.ibm.com/developerworks/opensource/linux390/exp_src.html
Patch: gdb-5.1pre-050901-s390.tar.gz (09/11/2001)
MD5: 886251f3719a754dd65a69df462ceac1
-rwxr-xr-x | config.sub | 6 | ||||
-rw-r--r-- | gdb/config/s390/nm-linux.h | 94 | ||||
-rw-r--r-- | gdb/config/s390/s390.mh | 15 | ||||
-rw-r--r-- | gdb/config/s390/s390.mt | 7 | ||||
-rw-r--r-- | gdb/config/s390/s390x.mt | 9 | ||||
-rw-r--r-- | gdb/config/s390/tm-linux.h | 36 | ||||
-rw-r--r-- | gdb/config/s390/tm-s390.h | 115 | ||||
-rw-r--r-- | gdb/config/s390/xm-linux.h | 33 | ||||
-rw-r--r-- | gdb/config/tm-sysv4.h | 4 | ||||
-rw-r--r-- | gdb/configure.host | 7 | ||||
-rw-r--r-- | gdb/defs.h | 5 | ||||
-rw-r--r-- | gdb/gdbarch.c | 4 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 2 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 11 | ||||
-rw-r--r-- | gdb/gdbserver/low-linux.c | 615 | ||||
-rw-r--r-- | gdb/gdbserver/remote-utils.c | 22 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 10 | ||||
-rw-r--r-- | gdb/s390-nat.c | 308 | ||||
-rw-r--r-- | gdb/s390-tdep.c | 1504 | ||||
-rw-r--r-- | gdb/signals.c | 45 |
20 files changed, 2512 insertions, 340 deletions
diff --git a/config.sub b/config.sub index 7146a2ffc1c..c87aebb18f1 100755 --- a/config.sub +++ b/config.sub @@ -742,6 +742,12 @@ case $basic_machine in rtpc | rtpc-*) basic_machine=romp-ibm ;; + s390 | s390-* ) + basic_machine=s390-ibm + ;; + s390x | s390x-* ) + basic_machine=s390x-ibm + ;; sa29200) basic_machine=a29k-amd os=-udi diff --git a/gdb/config/s390/nm-linux.h b/gdb/config/s390/nm-linux.h new file mode 100644 index 00000000000..2c00e0b87ef --- /dev/null +++ b/gdb/config/s390/nm-linux.h @@ -0,0 +1,94 @@ +/* Native support for Linux for S390 + + Copyright 1986, 1987, 1989, 1992, 1996, 1998, 2000 + Free Software Foundation, Inc. + Ported by D.J. Barrow for IBM Deutschland Entwicklung GmbH, IBM Corporation. + derived from i390-nmlinux.h + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef NM_LINUX_H +#define NM_LINUX_H + +#include "config/nm-linux.h" + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = s390_register_u_addr((blockend),(regno)); +extern int s390_register_u_addr (int, int); + +/* Return sizeof user struct to callers in less machine dependent routines */ + +#define KERNEL_U_SIZE kernel_u_size() +extern int kernel_u_size (void); + +#define U_REGS_OFFSET 0 + + +/* We define this if link.h is available, because with ELF we use SVR4 style + shared libraries. */ + +#ifdef HAVE_LINK_H +#define SVR4_SHARED_LIBS +#include "solib.h" /* Support for shared libraries. */ +#endif + + +/* WATCHPOINT SPECIFIC STUFF */ + +#define TARGET_HAS_HARDWARE_WATCHPOINTS +#define HAVE_CONTINUABLE_WATCHPOINT +#define HAVE_STEPPABLE_WATCHPOINT +#define target_insert_watchpoint(addr, len, type) \ + s390_insert_watchpoint (PIDGET (inferior_ptid), addr, len, type) + +#define target_remove_watchpoint(addr, len, type) \ + s390_remove_watchpoint (PIDGET (inferior_ptid), addr, len) + +extern int watch_area_cnt; +/* gdb if really stupid & calls this all the time without a + watchpoint even being set */ +#define STOPPED_BY_WATCHPOINT(W) \ + (watch_area_cnt&&s390_stopped_by_watchpoint (PIDGET(inferior_ptid))) + +extern CORE_ADDR s390_stopped_by_watchpoint (int); + +/* + Type can be 1 for a read_watchpoint or 2 for an access watchpoint. + */ +extern int s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw); +extern int s390_remove_watchpoint (int pid, CORE_ADDR addr, int len); +#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \ + (((type) == bp_hardware_watchpoint)|| \ + ((type) == bp_watchpoint)|| \ + ((type) == bp_read_watchpoint) || \ + ((type) == bp_access_watchpoint)) + +#undef PREPARE_TO_PROCEED + +extern void lin_lwp_attach_lwp (ptid_t ptid, int verbose); +#define ATTACH_LWP(ptid, verbose) lin_lwp_attach_lwp ((ptid), (verbose)) + + +#include <signal.h> + +extern void lin_thread_get_thread_signals (sigset_t * mask); +#define GET_THREAD_SIGNALS(mask) lin_thread_get_thread_signals (mask) + +/* Needed for s390x */ +#define PTRACE_ARG3_TYPE long +#define PTRACE_XFER_TYPE long +#endif /* nm_linux.h */ diff --git a/gdb/config/s390/s390.mh b/gdb/config/s390/s390.mh new file mode 100644 index 00000000000..fa953b45294 --- /dev/null +++ b/gdb/config/s390/s390.mh @@ -0,0 +1,15 @@ +# Host: S390, running Linux + +XM_FILE= xm-linux.h +XDEPFILES= ser-tcp.o +XM_CLIBS= + +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \ + s390-nat.o linux-thread.o core-aout.o core-regset.o +# post 5.0 natdepfiles. +NATDEPFILES+= thread-db.o lin-lwp.o proc-service.o +LOADLIBES = -ldl -rdynamic + + + diff --git a/gdb/config/s390/s390.mt b/gdb/config/s390/s390.mt new file mode 100644 index 00000000000..d1dfe9f82c2 --- /dev/null +++ b/gdb/config/s390/s390.mt @@ -0,0 +1,7 @@ +# Target: S390 running Linux +TM_FILE= tm-linux.h +TDEPFILES=s390-tdep.o solib.o +# Post 5.0 tdep-files +TDEPFILES+=solib-svr4.o solib-legacy.o +GDB_MULTI_ARCH=2 +GDBSERVER_DEPFILES= low-linux.o s390-tdep.o s390-nat.o diff --git a/gdb/config/s390/s390x.mt b/gdb/config/s390/s390x.mt new file mode 100644 index 00000000000..632fa5271de --- /dev/null +++ b/gdb/config/s390/s390x.mt @@ -0,0 +1,9 @@ +# Target: S390 running Linux +TM_FILE= tm-linux.h +TDEPFILES=s390-tdep.o solib.o +# Post 5.0 tdep-files +TDEPFILES+=solib-svr4.o solib-legacy.o +GDB_MULTI_ARCH=2 +GDBSERVER_DEPFILES= low-linux.o s390-tdep.o s390-nat.o +# needed for gdbserver. +MT_CFLAGS= -DCONFIG_ARCH_S390X diff --git a/gdb/config/s390/tm-linux.h b/gdb/config/s390/tm-linux.h new file mode 100644 index 00000000000..bb1e58728ce --- /dev/null +++ b/gdb/config/s390/tm-linux.h @@ -0,0 +1,36 @@ +/* Target definitions for GDB for a s390 running Linux. + Copyright (C) 1999-2001 Free Software Foundation, Inc. + Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + for IBM Deutschland Entwicklung GmbH, IBM Corporation. + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef TM_LINUX_H +#define TM_LINUX_H +#ifdef GDBSERVER +#define S390_GNULINUX_TARGET +#endif /* GDBSERVER */ +#undef TARGET_ELF64 +#define TARGET_ELF64 (gdbarch_tdep (current_gdbarch)->intreg_size==8) + +#include "config/tm-linux.h" +#include "s390/tm-s390.h" + + + +#endif /* TM_LINUX_H */ diff --git a/gdb/config/s390/tm-s390.h b/gdb/config/s390/tm-s390.h new file mode 100644 index 00000000000..3e0c2f201c2 --- /dev/null +++ b/gdb/config/s390/tm-s390.h @@ -0,0 +1,115 @@ +/* Macro definitions for GDB on an S390. + Copyright (C) 1999-2001 Free Software Foundation, Inc. + Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + for IBM Deutschland Entwicklung GmbH, IBM Corporation. + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if !defined(TM_S390_H) +#define TM_S390_H 1 + +#define S390_NUM_GPRS (16) +#define S390_GPR_SIZE REGISTER_SIZE +#define S390_PSW_MASK_SIZE REGISTER_SIZE +#define S390_PSW_ADDR_SIZE REGISTER_SIZE +#define S390_NUM_FPRS (16) +#define S390_FPR_SIZE (8) +#define S390_FPC_SIZE (4) +#define S390_FPC_PAD_SIZE (4) /* gcc insists on aligning the fpregs */ +#define S390_NUM_CRS (16) +#define S390_CR_SIZE REGISTER_SIZE +#define S390_NUM_ACRS (16) +#define S390_ACR_SIZE (4) + +#define S390_NUM_REGS (2+S390_NUM_GPRS+S390_NUM_ACRS+S390_NUM_CRS+1+S390_NUM_FPRS) +#define S390_FIRST_ACR (2+S390_NUM_GPRS) +#define S390_LAST_ACR (S390_FIRST_ACR+S390_NUM_ACRS-1) +#define S390_FIRST_CR (S390_FIRST_ACR+S390_NUM_ACRS) +#define S390_LAST_CR (S390_FIRST_CR+S390_NUM_CRS-1) + +#define S390_PSWM_REGNUM 0 +#define S390_PC_REGNUM 1 +#define S390_GP0_REGNUM 2 /* GPR register 0 */ +#define S390_GP_LAST_REGNUM (S390_GP0_REGNUM+S390_NUM_GPRS-1) +/* Usually return address */ +#define S390_RETADDR_REGNUM (S390_GP0_REGNUM+14) +/* Contains address of top of stack */ +#define S390_SP_REGNUM (S390_GP0_REGNUM+15) +/* needed in findvar.c still */ +#define S390_FP_REGNUM S390_SP_REGNUM +#define S390_FRAME_REGNUM (S390_GP0_REGNUM+11) +#define S390_FPC_REGNUM (S390_GP0_REGNUM+S390_NUM_GPRS+S390_NUM_ACRS+S390_NUM_CRS) +/* FPR (Floating point) register 0 */ +#define S390_FP0_REGNUM (S390_FPC_REGNUM+1) +/* Last floating point register */ +#define S390_FPLAST_REGNUM (S390_FP0_REGNUM+S390_NUM_FPRS-1) +#define S390_LAST_REGNUM S390_FPLAST_REGNUM + + +#define S390_ACR0_OFFSET ((S390_PSW_MASK_SIZE+S390_PSW_ADDR_SIZE)+(S390_GPR_SIZE*S390_NUM_GPRS)) +#define S390_CR0_OFFSET (S390_ACR0_OFFSET+(S390_ACR_SIZE*S390_NUM_ACRS)) +#define S390_FPC_OFFSET (S390_CR0_OFFSET+(S390_CR_SIZE*S390_NUM_CRS)) +#define S390_FP0_OFFSET (S390_FPC_OFFSET+(S390_FPC_SIZE+S390_FPC_PAD_SIZE)) +#define S390_GPR6_STACK_OFFSET (GDB_TARGET_IS_ESAME ? 48:24) + +#define S390_REGISTER_BYTES ((4+4)+(4*S390_NUM_GPRS)+(4*S390_NUM_ACRS)+ \ +(4*S390_NUM_CRS)+(S390_FPC_SIZE+S390_FPC_PAD_SIZE)+(S390_FPR_SIZE*S390_NUM_FPRS)) + +#define S390X_REGISTER_BYTES ((8+8)+(8*S390_NUM_GPRS)+(4*S390_NUM_ACRS)+ \ +(8*S390_NUM_CRS)+(S390_FPC_SIZE+S390_FPC_PAD_SIZE)+(S390_FPR_SIZE*S390_NUM_FPRS)) + +#ifdef GDBSERVER + +int s390_register_byte (int reg_nr); +#define REGISTER_BYTE(reg_nr) s390_register_byte(reg_nr) +#define PC_REGNUM S390_PC_REGNUM +#define NUM_REGS S390_NUM_REGS +#define NUM_FREGS S390_NUM_FPRS +#define FP_REGNUM S390_FP_REGNUM +#define SP_REGNUM S390_SP_REGNUM +/* Obviously ptrace for user program tracing cannot be allowed + mess with control registers (except per registers for hardware watchpoints), + when we add kernel debugging we may need to alter these macros. */ +int s390_cannot_fetch_register (int regno); +#define CANNOT_FETCH_REGISTER(regno) s390_cannot_fetch_register(regno) +#define CANNOT_STORE_REGISTER(regno) s390_cannot_fetch_register(regno) + +#if CONFIG_ARCH_S390X + +int s390x_register_raw_size (int reg_nr); +#define REGISTER_RAW_SIZE(reg_nr) s390x_register_raw_size(reg_nr) +#define GDB_TARGET_IS_ESAME (1) +#define REGISTER_SIZE (8) +#define REGISTER_BYTES S390X_REGISTER_BYTES + +#else /* CONFIG_ARCH_S390X */ + +int s390_register_raw_size (int reg_nr); +#define REGISTER_RAW_SIZE(reg_nr) s390_register_raw_size(reg_nr) +#define GDB_TARGET_IS_ESAME (0) +#define REGISTER_SIZE (4) +#define REGISTER_BYTES S390_REGISTER_BYTES + +#endif /* CONFIG_ARCH_S390X */ + +#else /* GDBSERVER */ + +#define GDB_TARGET_IS_ESAME (TARGET_ARCHITECTURE->mach == bfd_mach_s390_esame) + +#endif /* GDBSERVER */ +#endif /* ifndef TM_S390_H */ diff --git a/gdb/config/s390/xm-linux.h b/gdb/config/s390/xm-linux.h new file mode 100644 index 00000000000..216dc17add8 --- /dev/null +++ b/gdb/config/s390/xm-linux.h @@ -0,0 +1,33 @@ +/* Native support for GNU/Linux, for GDB, the GNU debugger. + Copyright (C) 1999-2001 Free Software Foundation, Inc. + Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + for IBM Deutschland Entwicklung GmbH, IBM Corporation. + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef XM_LINUX_H +#define XM_LINUX_H + +#define HOST_BYTE_ORDER BIG_ENDIAN + + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#define KERNEL_U_ADDR 0x0 + +#endif /* #ifndef XM_LINUX_H */ diff --git a/gdb/config/tm-sysv4.h b/gdb/config/tm-sysv4.h index 35b95eb71f8..1ed6bc3c139 100644 --- a/gdb/config/tm-sysv4.h +++ b/gdb/config/tm-sysv4.h @@ -33,9 +33,9 @@ extern int in_plt_section (CORE_ADDR, char *); /* If PC is in a shared library trampoline code, return the PC where the function itself actually starts. If not, return 0. */ - +#if (GDB_MULTI_ARCH <= GDB_MULTI_ARCH_PARTIAL) #define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc) - +#endif /* It is unknown which, if any, SVR4 assemblers do not accept dollar signs in identifiers. The default in G++ is to use dots instead, for all SVR4 systems, so we make that our default also. FIXME: There should be some diff --git a/gdb/configure.host b/gdb/configure.host index 403957b7084..94ea045f8fb 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -162,5 +162,10 @@ xscale-*-*) gdb_host=arm ;; vax-*-bsd*) gdb_host=vaxbsd ;; vax-*-ultrix2*) gdb_host=vaxult2 ;; vax-*-ultrix*) gdb_host=vaxult ;; - +s390*-*-*) gdb_host=s390 ;; esac + + + + + diff --git a/gdb/defs.h b/gdb/defs.h index 3fac36e2610..bf524c2e826 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -1,4 +1,4 @@ -/* *INDENT-OFF* */ /* ATTR_FORMAT confuses indent, avoid running it for now */ +/* *INDENT-OFF* *//* ATTR_FORMAT confuses indent, avoid running it for now */ /* Basic, host-specific, and target-specific definitions for GDB. Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 @@ -25,6 +25,9 @@ #define DEFS_H #include "config.h" /* Generated by configure */ +#if GDBSERVER +#undef GDB_MULTI_ARCH +#endif /* GDBSERVER */ #include <stdio.h> #include <errno.h> /* System call error return status */ #include <limits.h> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 40da7a4d22d..d860bedc760 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -615,7 +615,7 @@ verify_gdbarch (struct gdbarch *gdbarch) internal_error (__FILE__, __LINE__, "gdbarch: verify_gdbarch: call_dummy_start_offset invalid"); if ((GDB_MULTI_ARCH >= 2) - && (gdbarch->call_dummy_breakpoint_offset == -1)) + && (gdbarch->call_dummy_breakpoint_offset_p && gdbarch->call_dummy_breakpoint_offset == -1)) internal_error (__FILE__, __LINE__, "gdbarch: verify_gdbarch: call_dummy_breakpoint_offset invalid"); if ((GDB_MULTI_ARCH >= 1) @@ -3103,7 +3103,7 @@ set_gdbarch_call_dummy_start_offset (struct gdbarch *gdbarch, CORE_ADDR gdbarch_call_dummy_breakpoint_offset (struct gdbarch *gdbarch) { - if (gdbarch->call_dummy_breakpoint_offset == -1) + if (gdbarch->call_dummy_breakpoint_offset_p && gdbarch->call_dummy_breakpoint_offset == -1) internal_error (__FILE__, __LINE__, "gdbarch: gdbarch_call_dummy_breakpoint_offset invalid"); if (gdbarch_debug >= 2) diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 964e16f25ca..a9d00af11fd 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -436,7 +436,7 @@ v:1:USE_GENERIC_DUMMY_FRAMES:int:use_generic_dummy_frames::::0:-1 v:2:CALL_DUMMY_LOCATION:int:call_dummy_location::::0:0 f:2:CALL_DUMMY_ADDRESS:CORE_ADDR:call_dummy_address:void:::0:0::gdbarch->call_dummy_location == AT_ENTRY_POINT && gdbarch->call_dummy_address == 0 v:2:CALL_DUMMY_START_OFFSET:CORE_ADDR:call_dummy_start_offset::::0:-1:::0x%08lx -v:2:CALL_DUMMY_BREAKPOINT_OFFSET:CORE_ADDR:call_dummy_breakpoint_offset::::0:-1:::0x%08lx::CALL_DUMMY_BREAKPOINT_OFFSET_P +v:2:CALL_DUMMY_BREAKPOINT_OFFSET:CORE_ADDR:call_dummy_breakpoint_offset::::0:-1::gdbarch->call_dummy_breakpoint_offset_p && gdbarch->call_dummy_breakpoint_offset == -1:0x%08lx::CALL_DUMMY_BREAKPOINT_OFFSET_P v:1:CALL_DUMMY_BREAKPOINT_OFFSET_P:int:call_dummy_breakpoint_offset_p::::0:-1 v:2:CALL_DUMMY_LENGTH:int:call_dummy_length::::0:-1:::::CALL_DUMMY_LOCATION == BEFORE_TEXT_END || CALL_DUMMY_LOCATION == AFTER_TEXT_END f:2:PC_IN_CALL_DUMMY:int:pc_in_call_dummy:CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address:pc, sp, frame_address::0:0 diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 6884b16c02c..5f450468d02 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -130,18 +130,20 @@ LINTFLAGS= $(BFD_CFLAGS) SFILES = $(srcdir)/low-hppabsd.c $(srcdir)/low-linux.c $(srcdir)/low-lynx.c \ $(srcdir)/low-nbsd.c $(srcdir)/low-sim.c $(srcdir)/low-sparc.c \ $(srcdir)/low-sun3.c $(srcdir)/utils.c $(srcdir)/server.c \ - $(srcdir)/remote-utils.c + $(srcdir)/remote-utils.c ../signals.c DEPFILES = $(GDBSERVER_DEPFILES) SOURCES = $(SFILES) $(ALLDEPFILES) TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} -OBS = utils.o $(GDBSERVER_DEPFILES) server.o remote-utils.o +OBS = $(srcdir)/utils.o $(GDBSERVER_DEPFILES) server.o remote-utils.o signals.o # Prevent Sun make from putting in the machine type. Setting # TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. -.c.o: +%.o: %.c + ${CC} -c ${INTERNAL_CFLAGS} $< +%.o: ../%.c ${CC} -c ${INTERNAL_CFLAGS} $< all: gdbserver gdbreplay @@ -246,6 +248,7 @@ low-sim.o : ${srcdir}/low-sim.c ${srcdir}/server.h low-sparc.o : $(srcdir)/low-sparc.c $(srcdir)/server.h low-sun3.o : $(srcdir)/low-sun3.c $(srcdir)/server.h low-hppabsd.o : $(srcdir)/low-hppabsd.c $(srcdir)/server.h -utils.o : ${srcdir}/utils.c ${srcdir}/server.h +$(srcdir)/utils.o : ${srcdir}/utils.c ${srcdir}/server.h +signals.o : ../signals.c ../target.h # This is the end of "Makefile.in". diff --git a/gdb/gdbserver/low-linux.c b/gdb/gdbserver/low-linux.c index 0c7fce55833..62c74653c70 100644 --- a/gdb/gdbserver/low-linux.c +++ b/gdb/gdbserver/low-linux.c @@ -49,8 +49,9 @@ char *registers = my_registers; extern int errno; +#ifndef S390_GNULINUX_TARGET static void initialize_arch (void); - +#endif /* Start an inferior process and returns its pid. ALLARGS is a vector of program-name and args. */ @@ -113,13 +114,15 @@ mywait (char *status) if (WIFEXITED (w)) { - fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + fprintf (stderr, "\nChild exited with retcode = %x \n", + WEXITSTATUS (w)); *status = 'W'; return ((unsigned char) WEXITSTATUS (w)); } else if (!WIFSTOPPED (w)) { - fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + fprintf (stderr, "\nChild terminated with signal = %x \n", + WTERMSIG (w)); *status = 'X'; return ((unsigned char) WTERMSIG (w)); } @@ -178,17 +181,17 @@ int i386_register_byte[MAX_NUM_REGS]; /* i386_register_raw_size[i] is the number of bytes of storage in GDB's register array occupied by register i. */ int i386_register_raw_size[MAX_NUM_REGS] = { - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, 10, 10, 10, 10, 10, 10, 10, 10, - 4, 4, 4, 4, - 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 16, - 4 + 4 }; static void @@ -212,8 +215,7 @@ initialize_arch (void) /* Mapping between the general-purpose registers in `struct user' format and GDB's register array layout. */ -static int regmap[] = -{ +static int regmap[] = { EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI, EIP, EFL, CS, SS, @@ -236,8 +238,7 @@ initialize_arch (void) } /* This table must line up with REGISTER_NAMES in tm-m68k.h */ -static int regmap[] = -{ +static int regmap[] = { #ifdef PT_D0 PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7, PT_A0, PT_A1, PT_A2, PT_A3, PT_A4, PT_A5, PT_A6, PT_USP, @@ -268,258 +269,257 @@ m68k_linux_register_u_addr (int blockend, int regnum) #include <asm/ptrace_offsets.h> -static int u_offsets[] = - { - /* general registers */ - -1, /* gr0 not available; i.e, it's always zero */ - PT_R1, - PT_R2, - PT_R3, - PT_R4, - PT_R5, - PT_R6, - PT_R7, - PT_R8, - PT_R9, - PT_R10, - PT_R11, - PT_R12, - PT_R13, - PT_R14, - PT_R15, - PT_R16, - PT_R17, - PT_R18, - PT_R19, - PT_R20, - PT_R21, - PT_R22, - PT_R23, - PT_R24, - PT_R25, - PT_R26, - PT_R27, - PT_R28, - PT_R29, - PT_R30, - PT_R31, - /* gr32 through gr127 not directly available via the ptrace interface */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - /* Floating point registers */ - -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */ - PT_F2, - PT_F3, - PT_F4, - PT_F5, - PT_F6, - PT_F7, - PT_F8, - PT_F9, - PT_F10, - PT_F11, - PT_F12, - PT_F13, - PT_F14, - PT_F15, - PT_F16, - PT_F17, - PT_F18, - PT_F19, - PT_F20, - PT_F21, - PT_F22, - PT_F23, - PT_F24, - PT_F25, - PT_F26, - PT_F27, - PT_F28, - PT_F29, - PT_F30, - PT_F31, - PT_F32, - PT_F33, - PT_F34, - PT_F35, - PT_F36, - PT_F37, - PT_F38, - PT_F39, - PT_F40, - PT_F41, - PT_F42, - PT_F43, - PT_F44, - PT_F45, - PT_F46, - PT_F47, - PT_F48, - PT_F49, - PT_F50, - PT_F51, - PT_F52, - PT_F53, - PT_F54, - PT_F55, - PT_F56, - PT_F57, - PT_F58, - PT_F59, - PT_F60, - PT_F61, - PT_F62, - PT_F63, - PT_F64, - PT_F65, - PT_F66, - PT_F67, - PT_F68, - PT_F69, - PT_F70, - PT_F71, - PT_F72, - PT_F73, - PT_F74, - PT_F75, - PT_F76, - PT_F77, - PT_F78, - PT_F79, - PT_F80, - PT_F81, - PT_F82, - PT_F83, - PT_F84, - PT_F85, - PT_F86, - PT_F87, - PT_F88, - PT_F89, - PT_F90, - PT_F91, - PT_F92, - PT_F93, - PT_F94, - PT_F95, - PT_F96, - PT_F97, - PT_F98, - PT_F99, - PT_F100, - PT_F101, - PT_F102, - PT_F103, - PT_F104, - PT_F105, - PT_F106, - PT_F107, - PT_F108, - PT_F109, - PT_F110, - PT_F111, - PT_F112, - PT_F113, - PT_F114, - PT_F115, - PT_F116, - PT_F117, - PT_F118, - PT_F119, - PT_F120, - PT_F121, - PT_F122, - PT_F123, - PT_F124, - PT_F125, - PT_F126, - PT_F127, - /* predicate registers - we don't fetch these individually */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - /* branch registers */ - PT_B0, - PT_B1, - PT_B2, - PT_B3, - PT_B4, - PT_B5, - PT_B6, - PT_B7, - /* virtual frame pointer and virtual return address pointer */ - -1, -1, - /* other registers */ - PT_PR, - PT_CR_IIP, /* ip */ - PT_CR_IPSR, /* psr */ - PT_CFM, /* cfm */ - /* kernel registers not visible via ptrace interface (?) */ - -1, -1, -1, -1, -1, -1, -1, -1, - /* hole */ - -1, -1, -1, -1, -1, -1, -1, -1, - PT_AR_RSC, - PT_AR_BSP, - PT_AR_BSPSTORE, - PT_AR_RNAT, - -1, - -1, /* Not available: FCR, IA32 floating control register */ - -1, -1, - -1, /* Not available: EFLAG */ - -1, /* Not available: CSD */ - -1, /* Not available: SSD */ - -1, /* Not available: CFLG */ - -1, /* Not available: FSR */ - -1, /* Not available: FIR */ - -1, /* Not available: FDR */ - -1, - PT_AR_CCV, - -1, -1, -1, - PT_AR_UNAT, - -1, -1, -1, - PT_AR_FPSR, - -1, -1, -1, - -1, /* Not available: ITC */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, - PT_AR_PFS, - PT_AR_LC, - -1, /* Not available: EC, the Epilog Count register */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, - /* nat bits - not fetched directly; instead we obtain these bits from - either rnat or unat or from memory. */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - }; +static int u_offsets[] = { + /* general registers */ + -1, /* gr0 not available; i.e, it's always zero */ + PT_R1, + PT_R2, + PT_R3, + PT_R4, + PT_R5, + PT_R6, + PT_R7, + PT_R8, + PT_R9, + PT_R10, + PT_R11, + PT_R12, + PT_R13, + PT_R14, + PT_R15, + PT_R16, + PT_R17, + PT_R18, + PT_R19, + PT_R20, + PT_R21, + PT_R22, + PT_R23, + PT_R24, + PT_R25, + PT_R26, + PT_R27, + PT_R28, + PT_R29, + PT_R30, + PT_R31, + /* gr32 through gr127 not directly available via the ptrace interface */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* Floating point registers */ + -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */ + PT_F2, + PT_F3, + PT_F4, + PT_F5, + PT_F6, + PT_F7, + PT_F8, + PT_F9, + PT_F10, + PT_F11, + PT_F12, + PT_F13, + PT_F14, + PT_F15, + PT_F16, + PT_F17, + PT_F18, + PT_F19, + PT_F20, + PT_F21, + PT_F22, + PT_F23, + PT_F24, + PT_F25, + PT_F26, + PT_F27, + PT_F28, + PT_F29, + PT_F30, + PT_F31, + PT_F32, + PT_F33, + PT_F34, + PT_F35, + PT_F36, + PT_F37, + PT_F38, + PT_F39, + PT_F40, + PT_F41, + PT_F42, + PT_F43, + PT_F44, + PT_F45, + PT_F46, + PT_F47, + PT_F48, + PT_F49, + PT_F50, + PT_F51, + PT_F52, + PT_F53, + PT_F54, + PT_F55, + PT_F56, + PT_F57, + PT_F58, + PT_F59, + PT_F60, + PT_F61, + PT_F62, + PT_F63, + PT_F64, + PT_F65, + PT_F66, + PT_F67, + PT_F68, + PT_F69, + PT_F70, + PT_F71, + PT_F72, + PT_F73, + PT_F74, + PT_F75, + PT_F76, + PT_F77, + PT_F78, + PT_F79, + PT_F80, + PT_F81, + PT_F82, + PT_F83, + PT_F84, + PT_F85, + PT_F86, + PT_F87, + PT_F88, + PT_F89, + PT_F90, + PT_F91, + PT_F92, + PT_F93, + PT_F94, + PT_F95, + PT_F96, + PT_F97, + PT_F98, + PT_F99, + PT_F100, + PT_F101, + PT_F102, + PT_F103, + PT_F104, + PT_F105, + PT_F106, + PT_F107, + PT_F108, + PT_F109, + PT_F110, + PT_F111, + PT_F112, + PT_F113, + PT_F114, + PT_F115, + PT_F116, + PT_F117, + PT_F118, + PT_F119, + PT_F120, + PT_F121, + PT_F122, + PT_F123, + PT_F124, + PT_F125, + PT_F126, + PT_F127, + /* predicate registers - we don't fetch these individually */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + /* branch registers */ + PT_B0, + PT_B1, + PT_B2, + PT_B3, + PT_B4, + PT_B5, + PT_B6, + PT_B7, + /* virtual frame pointer and virtual return address pointer */ + -1, -1, + /* other registers */ + PT_PR, + PT_CR_IIP, /* ip */ + PT_CR_IPSR, /* psr */ + PT_CFM, /* cfm */ + /* kernel registers not visible via ptrace interface (?) */ + -1, -1, -1, -1, -1, -1, -1, -1, + /* hole */ + -1, -1, -1, -1, -1, -1, -1, -1, + PT_AR_RSC, + PT_AR_BSP, + PT_AR_BSPSTORE, + PT_AR_RNAT, + -1, + -1, /* Not available: FCR, IA32 floating control register */ + -1, -1, + -1, /* Not available: EFLAG */ + -1, /* Not available: CSD */ + -1, /* Not available: SSD */ + -1, /* Not available: CFLG */ + -1, /* Not available: FSR */ + -1, /* Not available: FIR */ + -1, /* Not available: FDR */ + -1, + PT_AR_CCV, + -1, -1, -1, + PT_AR_UNAT, + -1, -1, -1, + PT_AR_FPSR, + -1, -1, -1, + -1, /* Not available: ITC */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, + PT_AR_PFS, + PT_AR_LC, + -1, /* Not available: EC, the Epilog Count register */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, + /* nat bits - not fetched directly; instead we obtain these bits from + either rnat or unat or from memory. */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; int ia64_register_u_addr (int blockend, int regnum) @@ -569,22 +569,31 @@ fetch_register (int regno) offset = U_REGS_OFFSET; - regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) +#ifdef S390_GNULINUX_TARGET /* intel has CANNOT_FETCH_REGISTER defined but not linked */ + if (CANNOT_FETCH_REGISTER (regno)) + memset (®isters[REGISTER_BYTE (regno)], 0, REGISTER_RAW_SIZE (regno)); + else +#endif { - errno = 0; - *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i] = - ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0); - regaddr += sizeof (PTRACE_XFER_TYPE); - if (errno != 0) + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); + i += sizeof (PTRACE_XFER_TYPE)) { - /* Warning, not error, in case we are attached; sometimes the - kernel doesn't let us at the registers. */ - char *err = strerror (errno); - char *msg = alloca (strlen (err) + 128); - sprintf (msg, "reading register %d: %s", regno, err); - error (msg); - goto error_exit; + errno = 0; + *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i] = + ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes the + kernel doesn't let us at the registers. */ + char *err = strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "reading register %d: %s", regno, err); + error (msg); + goto error_exit; + } } } error_exit:; @@ -596,7 +605,11 @@ void fetch_inferior_registers (int regno) { if (regno == -1 || regno == 0) - for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++) + for (regno = 0; regno < NUM_REGS +#ifndef S390_GNULINUX_TARGET + - NUM_FREGS +#endif + ; regno++) fetch_register (regno); else fetch_register (regno); @@ -615,7 +628,7 @@ store_inferior_registers (int regno) if (regno >= 0) { -#if 0 +#ifdef S390_GNULINUX_TARGET /* intel has CANNOT_STORE_REGISTER defined but not implemented */ if (CANNOT_STORE_REGISTER (regno)) return; #endif @@ -637,19 +650,20 @@ store_inferior_registers (int regno) } else #endif - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + for (i = 0; i < REGISTER_RAW_SIZE (regno); + i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - *(int *) ®isters[REGISTER_BYTE (regno) + i]); + *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + + i]); if (errno != 0) { /* Warning, not error, in case we are attached; sometimes the kernel doesn't let us at the registers. */ char *err = strerror (errno); char *msg = alloca (strlen (err) + 128); - sprintf (msg, "writing register %d: %s", - regno, err); + sprintf (msg, "writing register %d: %s", regno, err); error (msg); return; } @@ -657,7 +671,11 @@ store_inferior_registers (int regno) } } else - for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++) + for (regno = 0; regno < NUM_REGS +#ifndef S390_GNULINUX_TARGET + - NUM_FREGS +#endif + ; regno++) store_inferior_registers (regno); } @@ -677,11 +695,11 @@ read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) /* Round starting address down to longword boundary. */ register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ - register int count - = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) - / sizeof (PTRACE_XFER_TYPE); + register int count + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ - register PTRACE_XFER_TYPE *buffer + register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); /* Read all the longwords */ @@ -691,7 +709,8 @@ read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) } /* Copy appropriate bytes out of the buffer. */ - memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len); + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len); } /* Copy LEN bytes of data from debugger memory at MYADDR @@ -707,9 +726,12 @@ write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ register int count - = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE); + = + (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - + 1) / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ - register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + register PTRACE_XFER_TYPE *buffer = + (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); extern int errno; /* Fill start and end extra bytes of buffer with existing memory data. */ @@ -725,7 +747,8 @@ write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) /* Copy data to be written over corresponding part of buffer */ - memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len); + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, len); /* Write the entire buffer. */ @@ -743,5 +766,7 @@ write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len) void initialize_low (void) { +#ifndef S390_GNULINUX_TARGET initialize_arch (); +#endif } diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index cfde0a7dae4..0e5d5f91d1f 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -34,6 +34,7 @@ #include <fcntl.h> #include <sys/time.h> #include <unistd.h> +#include <target.h> int remote_debug = 0; struct ui_file *gdb_stdlog; @@ -141,7 +142,8 @@ remote_open (char *name) /* Enable TCP keep alive process. */ tmp = 1; - setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp)); + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, + sizeof (tmp)); /* Tell TCP not to delay small packets. This greatly speeds up interactive response. */ @@ -278,7 +280,7 @@ input_interrupt (void) { int cc; char c; - + cc = read (remote_desc, &c, 1); if (cc != 1 || c != '\003') @@ -286,7 +288,7 @@ input_interrupt (void) fprintf (stderr, "input_interrupt, cc = %d c = %d\n", cc, c); return; } - + kill (inferior_pid, SIGINT); } } @@ -463,10 +465,7 @@ prepare_resume_reply (char *buf, char status, unsigned char signo) *buf++ = status; - /* FIXME! Should be converting this signal number (numbered - according to the signal numbering of the system we are running on) - to the signal numbers used by the gdb protocol (see enum target_signal - in gdb/target.h). */ + signo = target_signal_from_host (signo); nib = ((signo & 0xf0) >> 4); *buf++ = tohex (nib); nib = signo & 0x0f; @@ -475,12 +474,11 @@ prepare_resume_reply (char *buf, char status, unsigned char signo) if (status == 'T') { #ifdef GDBSERVER_RESUME_REGS - static int gdbserver_resume_regs[] = GDBSERVER_RESUME_REGS ; + static int gdbserver_resume_regs[] = GDBSERVER_RESUME_REGS; int i; - for (i = 0; - i < sizeof (gdbserver_resume_regs) - / sizeof (gdbserver_resume_regs[0]); - i++) + for (i = 0; + i < sizeof (gdbserver_resume_regs) + / sizeof (gdbserver_resume_regs[0]); i++) { int regnum = gdbserver_resume_regs[i]; buf = outreg (regnum, buf); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index ab37b2ef079..8bb0630f80d 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -20,6 +20,7 @@ Boston, MA 02111-1307, USA. */ #include "server.h" +#include "target.h" int cont_thread; int general_thread; @@ -60,7 +61,6 @@ main (int argc, char *argv[]) error ("Usage: gdbserver tty prog [args ...]"); initialize_low (); - /* Wait till we are at first instruction in program. */ signal = start_inferior (&argv[2], &status); @@ -130,12 +130,14 @@ main (int argc, char *argv[]) break; case 'C': convert_ascii_to_int (own_buf + 1, &sig, 1); + sig = target_signal_to_host (sig); myresume (0, sig); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); break; case 'S': convert_ascii_to_int (own_buf + 1, &sig, 1); + sig = target_signal_to_host (sig); myresume (1, sig); signal = mywait (&status); prepare_resume_reply (own_buf, status, signal); @@ -210,8 +212,7 @@ main (int argc, char *argv[]) putpkt (own_buf); if (status == 'W') - fprintf (stderr, - "\nChild exited with status %d\n", sig); + fprintf (stderr, "\nChild exited with status %d\n", sig); if (status == 'X') fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig); if (status == 'W' || status == 'X') @@ -250,7 +251,8 @@ main (int argc, char *argv[]) } else { - fprintf (stderr, "Remote side has terminated connection. GDBserver will reopen the connection.\n"); + fprintf (stderr, + "Remote side has terminated connection. GDBserver will reopen the connection.\n"); remote_close (); } diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c new file mode 100644 index 00000000000..a7ab4933561 --- /dev/null +++ b/gdb/s390-nat.c @@ -0,0 +1,308 @@ +/* S390 native-dependent code for GDB, the GNU debugger. + Copyright 1999-2001 Free Software Foundation, Inc + Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + for IBM Deutschland Entwicklung GmbH, IBM Corporation. + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "defs.h" +#include "tm.h" +#include <asm/ptrace.h> +#include <sys/ptrace.h> +#include <asm/processor.h> +#include <sys/procfs.h> +#include <sys/user.h> +#include <value.h> +#include <sys/ucontext.h> +#ifndef offsetof +#define offsetof(type,member) ((size_t) &((type *)0)->member) +#endif + + +int +s390_register_u_addr (int blockend, int regnum) +{ + int retval; + + if (regnum >= S390_GP0_REGNUM && regnum <= S390_GP_LAST_REGNUM) + retval = PT_GPR0 + ((regnum - S390_GP0_REGNUM) * S390_GPR_SIZE); + else if (regnum >= S390_PSWM_REGNUM && regnum <= S390_PC_REGNUM) + retval = PT_PSWMASK + ((regnum - S390_PSWM_REGNUM) * S390_PSW_MASK_SIZE); + else if (regnum == S390_FPC_REGNUM) + retval = PT_FPC; + else if (regnum >= S390_FP0_REGNUM && regnum <= S390_FPLAST_REGNUM) + retval = +#if CONFIG_ARCH_S390X + PT_FPR0 +#else + PT_FPR0_HI +#endif + + ((regnum - S390_FP0_REGNUM) * S390_FPR_SIZE); + else if (regnum >= S390_FIRST_ACR && regnum <= S390_LAST_ACR) + retval = PT_ACR0 + ((regnum - S390_FIRST_ACR) * S390_ACR_SIZE); + else if (regnum >= (S390_FIRST_CR + 9) && regnum <= (S390_FIRST_CR + 11)) + retval = PT_CR_9 + ((regnum - (S390_FIRST_CR + 9)) * S390_CR_SIZE); + else + { +#ifdef GDBSERVER + error +#else + internal_error +#endif + ("s390_register_u_addr invalid regnum %s %d regnum=%d", __FILE__, + (int) __LINE__, regnum); + retval = 0; + } + return retval + blockend; +} + +#ifndef GDBSERVER +/* watch_areas are required if you put 2 or more watchpoints on the same + address or overlapping areas gdb will call us to delete the watchpoint + more than once when we try to delete them. + attempted reference counting to reduce the number of areas unfortunately + they didn't shrink when areas had to be split overlapping occurs. */ +struct watch_area; +typedef struct watch_area watch_area; +struct watch_area +{ + watch_area *next; + CORE_ADDR lo_addr; + CORE_ADDR hi_addr; +}; + +static watch_area *watch_base = NULL; +int watch_area_cnt = 0; +static CORE_ADDR watch_lo_addr = 0, watch_hi_addr = 0; + + + +CORE_ADDR +s390_stopped_by_watchpoint (int pid) +{ + per_lowcore_bits per_lowcore; + ptrace_area parea; + + parea.len = sizeof (per_lowcore); + parea.process_addr = (addr_t) & per_lowcore; + parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore); + ptrace (PTRACE_PEEKUSR_AREA, pid, &parea); + return ((per_lowcore.perc_storage_alteration == 1) && + (per_lowcore.perc_store_real_address == 0)); +} + + +void +s390_fix_watch_points (int pid) +{ + per_struct per_info; + ptrace_area parea; + + parea.len = sizeof (per_info); + parea.process_addr = (addr_t) & per_info; + parea.kernel_addr = PT_CR_9; + ptrace (PTRACE_PEEKUSR_AREA, pid, &parea); + /* The kernel automatically sets the psw for per depending */ + /* on whether the per control registers are set for event recording */ + /* & sets cr9 & cr10 appropriately also */ + if (watch_area_cnt) + { + per_info.control_regs.bits.em_storage_alteration = 1; + per_info.control_regs.bits.storage_alt_space_ctl = 1; + } + else + { + per_info.control_regs.bits.em_storage_alteration = 0; + per_info.control_regs.bits.storage_alt_space_ctl = 0; + } + per_info.starting_addr = watch_lo_addr; + per_info.ending_addr = watch_hi_addr; + ptrace (PTRACE_POKEUSR_AREA, pid, &parea); +} + +int +s390_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw) +{ + CORE_ADDR hi_addr = addr + len - 1; + watch_area *newarea = (watch_area *) malloc (sizeof (watch_area)); + + + if (newarea) + { + newarea->next = watch_base; + watch_base = newarea; + watch_lo_addr = min (watch_lo_addr, addr); + watch_hi_addr = max (watch_hi_addr, hi_addr); + newarea->lo_addr = addr; + newarea->hi_addr = hi_addr; + if (watch_area_cnt == 0) + { + watch_lo_addr = newarea->lo_addr; + watch_hi_addr = newarea->hi_addr; + } + watch_area_cnt++; + s390_fix_watch_points (pid); + } + return newarea ? 0 : -1; +} + + +int +s390_remove_watchpoint (int pid, CORE_ADDR addr, int len) +{ + watch_area *curr = watch_base, *prev, *matchCurr; + CORE_ADDR hi_addr = addr + len - 1; + CORE_ADDR watch_second_lo_addr = 0xffffffffUL, watch_second_hi_addr = 0; + int lo_addr_ref_cnt, hi_addr_ref_cnt; + prev = matchCurr = NULL; + lo_addr_ref_cnt = (addr == watch_lo_addr); + hi_addr_ref_cnt = (addr == watch_hi_addr); + while (curr) + { + if (matchCurr == NULL) + { + if (curr->lo_addr == addr && curr->hi_addr == hi_addr) + { + matchCurr = curr; + if (prev) + prev->next = curr->next; + else + watch_base = curr->next; + } + prev = curr; + } + if (lo_addr_ref_cnt) + { + if (watch_lo_addr == curr->lo_addr) + lo_addr_ref_cnt++; + if (curr->lo_addr > watch_lo_addr && + curr->lo_addr < watch_second_lo_addr) + watch_second_lo_addr = curr->lo_addr; + } + if (hi_addr_ref_cnt) + { + if (watch_hi_addr == curr->hi_addr) + hi_addr_ref_cnt++; + if (curr->hi_addr < watch_hi_addr && + curr->hi_addr > watch_second_hi_addr) + watch_second_hi_addr = curr->hi_addr; + } + curr = curr->next; + } + if (matchCurr) + { + free (matchCurr); + watch_area_cnt--; + if (watch_area_cnt) + { + if (lo_addr_ref_cnt == 2) + watch_lo_addr = watch_second_lo_addr; + if (hi_addr_ref_cnt == 2) + watch_hi_addr = watch_second_hi_addr; + } + else + { + watch_lo_addr = watch_hi_addr = 0; + } + s390_fix_watch_points (pid); + return 0; + } + else + { + fprintf_unfiltered (gdb_stderr, + "Attempt to remove nonexistent watchpoint in s390_remove_watchpoint\n"); + return -1; + } +} + +int +kernel_u_size (void) +{ + return sizeof (struct user); +} + + +#if (defined (S390_FP0_REGNUM) && defined (HAVE_FPREGSET_T) && defined(HAVE_SYS_PROCFS_H) && defined (HAVE_GREGSET_T)) +void +supply_gregset (gregset_t * gregsetp) +{ + int regi; + greg_t *gregp = (greg_t *) gregsetp; + + supply_register (S390_PSWM_REGNUM, (char *) &gregp[S390_PSWM_REGNUM]); + supply_register (S390_PC_REGNUM, (char *) &gregp[S390_PC_REGNUM]); + for (regi = 0; regi < S390_NUM_GPRS; regi++) + supply_register (S390_GP0_REGNUM + regi, + (char *) &gregp[S390_GP0_REGNUM + regi]); + for (regi = 0; regi < S390_NUM_ACRS; regi++) + supply_register (S390_FIRST_ACR + regi, + (char *) &gregp[S390_FIRST_ACR + regi]); + /* unfortunately this isn't in gregsetp */ + for (regi = 0; regi < S390_NUM_CRS; regi++) + supply_register (S390_FIRST_CR + regi, NULL); +} + + +void +supply_fpregset (fpregset_t * fpregsetp) +{ + int regi; + + supply_register (S390_FPC_REGNUM, (char *) &fpregsetp->fpc); + for (regi = 0; regi < S390_NUM_FPRS; regi++) + supply_register (S390_FP0_REGNUM + regi, (char *) &fpregsetp->fprs[regi]); + +} + +void +fill_gregset (gregset_t * gregsetp, int regno) +{ + greg_t *gregp = (greg_t *) gregsetp; + + if (regno >= S390_FIRST_CR && regno <= S390_LAST_CR) + supply_register (regno, NULL); + else if (regno != -1) + supply_register (regno, (char *) &gregp[regno]); + else + supply_gregset (gregsetp); +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), update the register specified by REGNO from gdb's idea + of the current floating point register set. If REGNO is -1, update + them all. */ + +void +fill_fpregset (fpregset_t * fpregsetp, int regno) +{ + if (regno == -1) + supply_fpregset (fpregsetp); + else + supply_register (regno, + &((char *) fpregsetp)[REGISTER_BYTE (regno) - + REGISTER_BYTE (S390_FPC_REGNUM)]); +} + + +#else +#error "There are a few possibilities here" +#error "1) You aren't compiling for linux & don't need a core dumps to work." +#error "2) The header files sys/elf.h sys/user.h sys/ptrace.h & sys/procfs.h" +#error "libc files are inconsistent with linux/include/asm-s390/" +#error "3) you didn't do a completely clean build & delete config.cache." +#endif +#endif /* GDBSERVER */ diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c new file mode 100644 index 00000000000..4050607a730 --- /dev/null +++ b/gdb/s390-tdep.c @@ -0,0 +1,1504 @@ +/* Target-dependent code for GDB, the GNU debugger. + Copyright 1999 Free Software Foundation, Inc. + Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + for IBM Deutschland Entwicklung GmbH, IBM Corporation. + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define S390_TDEP /* for special macros in tm-s390.h */ +#include <defs.h> +#include "arch-utils.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "target.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "symfile.h" +#include "objfiles.h" +#include "tm.h" +#include "../bfd/bfd.h" +#include "floatformat.h" +#include "regcache.h" + + + + + +/* Number of bytes of storage in the actual machine representation + for register N. + Note that the unsigned cast here forces the result of the + subtraction to very high positive values if N < S390_FP0_REGNUM */ +int +s390_register_raw_size (int reg_nr) +{ + return ((unsigned) reg_nr - S390_FP0_REGNUM) < + S390_NUM_FPRS ? S390_FPR_SIZE : 4; +} + +int +s390x_register_raw_size (int reg_nr) +{ + return (reg_nr == S390_FPC_REGNUM) + || (reg_nr >= S390_FIRST_ACR && reg_nr <= S390_LAST_ACR) ? 4 : 8; +} + +int +s390_cannot_fetch_register (int regno) +{ + return (regno >= S390_FIRST_CR && regno < (S390_FIRST_CR + 9)) || + (regno >= (S390_FIRST_CR + 12) && regno <= S390_LAST_CR); +} + +int +s390_register_byte (int reg_nr) +{ + if (reg_nr <= S390_GP_LAST_REGNUM) + return reg_nr * S390_GPR_SIZE; + if (reg_nr <= S390_LAST_ACR) + return S390_ACR0_OFFSET + (((reg_nr) - S390_FIRST_ACR) * S390_ACR_SIZE); + if (reg_nr <= S390_LAST_CR) + return S390_CR0_OFFSET + (((reg_nr) - S390_FIRST_CR) * S390_CR_SIZE); + if (reg_nr == S390_FPC_REGNUM) + return S390_FPC_OFFSET; + else + return S390_FP0_OFFSET + (((reg_nr) - S390_FP0_REGNUM) * S390_FPR_SIZE); +} + +#ifndef GDBSERVER +#define S390_MAX_INSTR_SIZE (6) +#define S390_SYSCALL_OPCODE (0x0a) +#define S390_SYSCALL_SIZE (2) +#define S390_SIGCONTEXT_SREGS_OFFSET (8) +#define S390X_SIGCONTEXT_SREGS_OFFSET (8) +#define S390_SIGREGS_FP0_OFFSET (144) +#define S390X_SIGREGS_FP0_OFFSET (216) +#define S390_UC_MCONTEXT_OFFSET (256) +#define S390X_UC_MCONTEXT_OFFSET (344) +#define S390_STACK_FRAME_OVERHEAD (GDB_TARGET_IS_ESAME ? 160:96) +#define S390_SIGNAL_FRAMESIZE (GDB_TARGET_IS_ESAME ? 160:96) +#define s390_NR_sigreturn 119 +#define s390_NR_rt_sigreturn 173 + + + +struct frame_extra_info +{ + int initialised; + int good_prologue; + CORE_ADDR function_start; + CORE_ADDR skip_prologue_function_start; + CORE_ADDR saved_pc_valid; + CORE_ADDR saved_pc; + CORE_ADDR sig_fixed_saved_pc_valid; + CORE_ADDR sig_fixed_saved_pc; + CORE_ADDR frame_pointer_saved_pc; /* frame pointer needed for alloca */ + CORE_ADDR stack_bought; /* amount we decrement the stack pointer by */ + CORE_ADDR sigcontext; +}; + + +static CORE_ADDR s390_frame_saved_pc_nofix (struct frame_info *fi); + +int +s390_readinstruction (bfd_byte instr[], CORE_ADDR at, + struct disassemble_info *info) +{ + int instrlen; + + static int s390_instrlen[] = { + 2, + 4, + 4, + 6 + }; + if ((*info->read_memory_func) (at, &instr[0], 2, info)) + return -1; + instrlen = s390_instrlen[instr[0] >> 6]; + if ((*info->read_memory_func) (at + 2, &instr[2], instrlen - 2, info)) + return -1; + return instrlen; +} + +static void +s390_memset_extra_info (struct frame_extra_info *fextra_info) +{ + memset (fextra_info, 0, sizeof (struct frame_extra_info)); +} + + + +char * +s390_register_name (int reg_nr) +{ + static char *register_names[] = { + "pswm", "pswa", + "gpr0", "gpr1", "gpr2", "gpr3", "gpr4", "gpr5", "gpr6", "gpr7", + "gpr8", "gpr9", "gpr10", "gpr11", "gpr12", "gpr13", "gpr14", "gpr15", + "acr0", "acr1", "acr2", "acr3", "acr4", "acr5", "acr6", "acr7", + "acr8", "acr9", "acr10", "acr11", "acr12", "acr13", "acr14", "acr15", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15", + "fpc", + "fpr0", "fpr1", "fpr2", "fpr3", "fpr4", "fpr5", "fpr6", "fpr7", + "fpr8", "fpr9", "fpr10", "fpr11", "fpr12", "fpr13", "fpr14", "fpr15" + }; + + if (reg_nr >= S390_LAST_REGNUM) + return NULL; + return register_names[reg_nr]; +} + + + + +int +s390_stab_reg_to_regnum (int regno) +{ + return regno >= 64 ? S390_PSWM_REGNUM - 64 : + regno >= 48 ? S390_FIRST_ACR - 48 : + regno >= 32 ? S390_FIRST_CR - 32 : + regno <= 15 ? (regno + 2) : + S390_FP0_REGNUM + ((regno - 16) & 8) + (((regno - 16) & 3) << 1) + + (((regno - 16) & 4) >> 2); +} + + + +/* s390_get_frame_info based on Hartmuts + prologue definition in + gcc-2.8.1/config/l390/linux.c + + It reads one instruction at a time & based on whether + it looks like prologue code or not it makes a decision on + whether the prologue is over, there are various state machines + in the code to determine if the prologue code is possilby valid. + + This is done to hopefully allow the code survive minor revs of + calling conventions. + + */ + +int +s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info, + struct frame_info *fi, int init_extra_info) +{ +#define CONST_POOL_REGIDX 13 +#define GOT_REGIDX 12 + bfd_byte instr[S390_MAX_INSTR_SIZE]; + CORE_ADDR test_pc = pc, test_pc2; + CORE_ADDR orig_sp = 0, save_reg_addr = 0, *saved_regs = NULL; + int valid_prologue, good_prologue = 0; + int gprs_saved[S390_NUM_GPRS]; + int fprs_saved[S390_NUM_FPRS]; + int regidx, instrlen; + int save_link_regidx, subtract_sp_regidx; + int const_pool_state, save_link_state, got_state; + int frame_pointer_found, varargs_state; + int loop_cnt, gdb_gpr_store, gdb_fpr_store; + int frame_pointer_regidx = 0xf; + int offset, expected_offset; + int err = 0; + disassemble_info info; + const_pool_state = save_link_state = got_state = varargs_state = 0; + frame_pointer_found = 0; + memset (gprs_saved, 0, sizeof (gprs_saved)); + memset (fprs_saved, 0, sizeof (fprs_saved)); + info.read_memory_func = dis_asm_read_memory; + + save_link_regidx = subtract_sp_regidx = 0; + if (fextra_info) + { + if (fi && fi->frame) + { + orig_sp = fi->frame + fextra_info->stack_bought; + saved_regs = fi->saved_regs; + } + if (init_extra_info || !fextra_info->initialised) + { + s390_memset_extra_info (fextra_info); + fextra_info->function_start = pc; + fextra_info->initialised = 1; + } + } + instrlen = 0; + do + { + valid_prologue = 0; + test_pc += instrlen; + /* add the previous instruction len */ + instrlen = s390_readinstruction (instr, test_pc, &info); + if (instrlen < 0) + { + good_prologue = 0; + err = -1; + break; + } + /* We probably are in a glibc syscall */ + if (instr[0] == S390_SYSCALL_OPCODE && test_pc == pc) + { + good_prologue = 1; + if (saved_regs && fextra_info && fi->next && fi->next->extra_info + && fi->next->extra_info->sigcontext) + { + /* We are backtracing from a signal handler */ + save_reg_addr = fi->next->extra_info->sigcontext + + REGISTER_BYTE (S390_GP0_REGNUM); + for (regidx = 0; regidx < S390_NUM_GPRS; regidx++) + { + saved_regs[S390_GP0_REGNUM + regidx] = save_reg_addr; + save_reg_addr += S390_GPR_SIZE; + } + save_reg_addr = fi->next->extra_info->sigcontext + + (GDB_TARGET_IS_ESAME ? S390X_SIGREGS_FP0_OFFSET : + S390_SIGREGS_FP0_OFFSET); + for (regidx = 0; regidx < S390_NUM_FPRS; regidx++) + { + saved_regs[S390_FP0_REGNUM + regidx] = save_reg_addr; + save_reg_addr += S390_FPR_SIZE; + } + } + break; + } + if (save_link_state == 0) + { + /* check for a stack relative STMG or STM */ + if (((GDB_TARGET_IS_ESAME && + ((instr[0] == 0xeb) && (instr[5] == 0x24))) || + (instr[0] == 0x90)) && ((instr[2] >> 4) == 0xf)) + { + regidx = (instr[1] >> 4); + if (regidx < 6) + varargs_state = 1; + offset = ((instr[2] & 0xf) << 8) + instr[3]; + expected_offset = + S390_GPR6_STACK_OFFSET + (S390_GPR_SIZE * (regidx - 6)); + if (offset != expected_offset) + { + good_prologue = 0; + break; + } + if (saved_regs) + save_reg_addr = orig_sp + offset; + for (; regidx <= (instr[1] & 0xf); regidx++) + { + if (gprs_saved[regidx]) + { + good_prologue = 0; + break; + } + good_prologue = 1; + gprs_saved[regidx] = 1; + if (saved_regs) + { + saved_regs[S390_GP0_REGNUM + regidx] = save_reg_addr; + save_reg_addr += S390_GPR_SIZE; + } + } + valid_prologue = 1; + continue; + } + } + /* check for a stack relative STG or ST */ + if ((save_link_state == 0 || save_link_state == 3) && + ((GDB_TARGET_IS_ESAME && + ((instr[0] == 0xe3) && (instr[5] == 0x24))) || + (instr[0] == 0x50)) && ((instr[2] >> 4) == 0xf)) + { + regidx = instr[1] >> 4; + offset = ((instr[2] & 0xf) << 8) + instr[3]; + if (offset == 0) + { + if (save_link_state == 3 && regidx == save_link_regidx) + { + save_link_state = 4; + valid_prologue = 1; + continue; + } + else + break; + } + if (regidx < 6) + varargs_state = 1; + expected_offset = + S390_GPR6_STACK_OFFSET + (S390_GPR_SIZE * (regidx - 6)); + if (offset != expected_offset) + { + good_prologue = 0; + break; + } + if (gprs_saved[regidx]) + { + good_prologue = 0; + break; + } + good_prologue = 1; + gprs_saved[regidx] = 1; + if (saved_regs) + { + save_reg_addr = orig_sp + offset; + saved_regs[S390_GP0_REGNUM + regidx] = save_reg_addr; + } + valid_prologue = 1; + continue; + } + + /* check for STD */ + if (instr[0] == 0x60 && (instr[2] >> 4) == 0xf) + { + regidx = instr[1] >> 4; + if (regidx == 0 || regidx == 2) + varargs_state = 1; + if (fprs_saved[regidx]) + { + good_prologue = 0; + break; + } + fprs_saved[regidx] = 1; + if (saved_regs) + { + save_reg_addr = orig_sp + (((instr[2] & 0xf) << 8) + instr[3]); + saved_regs[S390_FP0_REGNUM + regidx] = save_reg_addr; + } + valid_prologue = 1; + continue; + } + + + if (const_pool_state == 0) + { + + if (GDB_TARGET_IS_ESAME) + { + /* Check for larl CONST_POOL_REGIDX,offset on ESAME */ + if ((instr[0] == 0xc0) + && (instr[1] == (CONST_POOL_REGIDX << 4))) + { + const_pool_state = 2; + valid_prologue = 1; + continue; + } + } + else + { + /* Check for BASR gpr13,gpr0 used to load constant pool pointer to r13 in old compiler */ + if (instr[0] == 0xd && (instr[1] & 0xf) == 0 + && ((instr[1] >> 4) == CONST_POOL_REGIDX)) + { + const_pool_state = 1; + valid_prologue = 1; + continue; + } + } + /* Check for new fangled bras %r13,newpc to load new constant pool */ + /* embedded in code, older pre abi compilers also emitted this stuff. */ + if ((instr[0] == 0xa7) && ((instr[1] & 0xf) == 0x5) && + ((instr[1] >> 4) == CONST_POOL_REGIDX) + && ((instr[2] & 0x80) == 0)) + { + const_pool_state = 2; + test_pc += + (((((instr[2] & 0xf) << 8) + instr[3]) << 1) - instrlen); + valid_prologue = 1; + continue; + } + } + /* Check for AGHI or AHI CONST_POOL_REGIDX,val */ + if (const_pool_state == 1 && (instr[0] == 0xa7) && + ((GDB_TARGET_IS_ESAME && + (instr[1] == ((CONST_POOL_REGIDX << 4) | 0xb))) || + (instr[1] == ((CONST_POOL_REGIDX << 4) | 0xa)))) + { + const_pool_state = 2; + valid_prologue = 1; + continue; + } + /* Check for LGR or LR gprx,15 */ + if ((GDB_TARGET_IS_ESAME && + instr[0] == 0xb9 && instr[1] == 0x04 && (instr[3] & 0xf) == 0xf) || + (instr[0] == 0x18 && (instr[1] & 0xf) == 0xf)) + { + if (GDB_TARGET_IS_ESAME) + regidx = instr[3] >> 4; + else + regidx = instr[1] >> 4; + if (save_link_state == 0 && regidx != 0xb) + { + /* Almost defintely code for + decrementing the stack pointer + ( i.e. a non leaf function + or else leaf with locals ) */ + save_link_regidx = regidx; + save_link_state = 1; + valid_prologue = 1; + continue; + } + /* We use this frame pointer for alloca + unfortunately we need to assume its gpr11 + otherwise we would need a smarter prologue + walker. */ + if (!frame_pointer_found && regidx == 0xb) + { + frame_pointer_regidx = 0xb; + frame_pointer_found = 1; + if (fextra_info) + fextra_info->frame_pointer_saved_pc = test_pc; + valid_prologue = 1; + continue; + } + } + /* Check for AHI or AGHI gpr15,val */ + if (save_link_state == 1 && (instr[0] == 0xa7) && + ((GDB_TARGET_IS_ESAME && (instr[1] == 0xfb)) || (instr[1] == 0xfa))) + { + if (fextra_info) + fextra_info->stack_bought = + -extract_signed_integer (&instr[2], 2); + save_link_state = 3; + valid_prologue = 1; + continue; + } + /* Alternatively check for the complex construction for + buying more than 32k of stack + BRAS gprx,.+8 + long vals %r15,0(%gprx) gprx currently r1 */ + if ((save_link_state == 1) && (instr[0] == 0xa7) + && ((instr[1] & 0xf) == 0x5) && (instr[2] == 0) + && (instr[3] == 0x4) && ((instr[1] >> 4) != CONST_POOL_REGIDX)) + { + subtract_sp_regidx = instr[1] >> 4; + save_link_state = 2; + if (fextra_info) + target_read_memory (test_pc + instrlen, + (char *) &fextra_info->stack_bought, + sizeof (fextra_info->stack_bought)); + test_pc += 4; + valid_prologue = 1; + continue; + } + if (save_link_state == 2 && instr[0] == 0x5b + && instr[1] == 0xf0 && + instr[2] == (subtract_sp_regidx << 4) && instr[3] == 0) + { + save_link_state = 3; + valid_prologue = 1; + continue; + } + /* check for LA gprx,offset(15) used for varargs */ + if ((instr[0] == 0x41) && ((instr[2] >> 4) == 0xf) && + ((instr[1] & 0xf) == 0)) + { + /* some code uses gpr7 to point to outgoing args */ + if (((instr[1] >> 4) == 7) && (save_link_state == 0) && + ((instr[2] & 0xf) == 0) + && (instr[3] == S390_STACK_FRAME_OVERHEAD)) + { + valid_prologue = 1; + continue; + } + if (varargs_state == 1) + { + varargs_state = 2; + valid_prologue = 1; + continue; + } + } + /* Check for a GOT load */ + + if (GDB_TARGET_IS_ESAME) + { + /* Check for larl GOT_REGIDX, on ESAME */ + if ((got_state == 0) && (instr[0] == 0xc0) + && (instr[1] == (GOT_REGIDX << 4))) + { + got_state = 2; + valid_prologue = 1; + continue; + } + } + else + { + /* check for l GOT_REGIDX,x(CONST_POOL_REGIDX) */ + if (got_state == 0 && const_pool_state == 2 && instr[0] == 0x58 + && (instr[2] == (CONST_POOL_REGIDX << 4)) + && ((instr[1] >> 4) == GOT_REGIDX)) + { + got_state == 1; + valid_prologue = 1; + continue; + } + /* Check for subsequent ar got_regidx,basr_regidx */ + if (got_state == 1 && instr[0] == 0x1a && + instr[1] == ((GOT_REGIDX << 4) | CONST_POOL_REGIDX)) + { + got_state = 2; + valid_prologue = 1; + continue; + } + } + } + while (valid_prologue && good_prologue); + if (good_prologue) + { + good_prologue = (((got_state == 0) || (got_state == 2)) && + ((const_pool_state == 0) || (const_pool_state == 2)) && + ((save_link_state == 0) || (save_link_state == 4)) && + ((varargs_state == 0) || (varargs_state == 2))); + } + if (fextra_info) + { + fextra_info->good_prologue = good_prologue; + fextra_info->skip_prologue_function_start = + (good_prologue ? test_pc : pc); + } + return err; +} + + +int +s390_check_function_end (CORE_ADDR pc) +{ + bfd_byte instr[S390_MAX_INSTR_SIZE]; + disassemble_info info; + int regidx, instrlen; + + info.read_memory_func = dis_asm_read_memory; + instrlen = s390_readinstruction (instr, pc, &info); + if (instrlen < 0) + return -1; + /* check for BR */ + if (instrlen != 2 || instr[0] != 07 || (instr[1] >> 4) != 0xf) + return 0; + regidx = instr[1] & 0xf; + /* Check for LMG or LG */ + instrlen = + s390_readinstruction (instr, pc - (GDB_TARGET_IS_ESAME ? 6 : 4), &info); + if (instrlen < 0) + return -1; + if (GDB_TARGET_IS_ESAME) + { + + if (instrlen != 6 || instr[0] != 0xeb || instr[5] != 0x4) + return 0; + } + else if (instrlen != 4 || instr[0] != 0x98) + { + return 0; + } + if ((instr[2] >> 4) != 0xf) + return 0; + if (regidx == 14) + return 1; + instrlen = s390_readinstruction (instr, pc - (GDB_TARGET_IS_ESAME ? 12 : 8), + &info); + if (instrlen < 0) + return -1; + if (GDB_TARGET_IS_ESAME) + { + /* Check for LG */ + if (instrlen != 6 || instr[0] != 0xe3 || instr[5] != 0x4) + return 0; + } + else + { + /* Check for L */ + if (instrlen != 4 || instr[0] != 0x58) + return 0; + } + if (instr[2] >> 4 != 0xf) + return 0; + if (instr[1] >> 4 != regidx) + return 0; + return 1; +} + +static CORE_ADDR +s390_sniff_pc_function_start (CORE_ADDR pc, struct frame_info *fi) +{ + CORE_ADDR function_start, test_function_start; + int loop_cnt, err, function_end; + struct frame_extra_info fextra_info; + function_start = get_pc_function_start (pc); + + if (function_start == 0) + { + test_function_start = pc; + if (test_function_start & 1) + return 0; /* This has to be bogus */ + loop_cnt = 0; + do + { + + err = + s390_get_frame_info (test_function_start, &fextra_info, fi, 1); + loop_cnt++; + test_function_start -= 2; + function_end = s390_check_function_end (test_function_start); + } + while (!(function_end == 1 || err || loop_cnt >= 4096 || + (fextra_info.good_prologue))); + if (fextra_info.good_prologue) + function_start = fextra_info.function_start; + else if (function_end == 1) + function_start = test_function_start; + } + return function_start; +} + + + +CORE_ADDR +s390_function_start (struct frame_info *fi) +{ + CORE_ADDR function_start = 0; + + if (fi->extra_info && fi->extra_info->initialised) + function_start = fi->extra_info->function_start; + else if (fi->pc) + function_start = get_pc_function_start (fi->pc); + return function_start; +} + + + + +int +s390_frameless_function_invocation (struct frame_info *fi) +{ + struct frame_extra_info fextra_info, *fextra_info_ptr; + int frameless = 0; + + if (fi->next == NULL) /* no may be frameless */ + { + if (fi->extra_info) + fextra_info_ptr = fi->extra_info; + else + { + fextra_info_ptr = &fextra_info; + s390_get_frame_info (s390_sniff_pc_function_start (fi->pc, fi), + fextra_info_ptr, fi, 1); + } + frameless = ((fextra_info_ptr->stack_bought == 0)); + } + return frameless; + +} + + +static int +s390_is_sigreturn (CORE_ADDR pc, struct frame_info *sighandler_fi, + CORE_ADDR *sregs, CORE_ADDR *sigcaller_pc) +{ + bfd_byte instr[S390_MAX_INSTR_SIZE]; + disassemble_info info; + int instrlen; + CORE_ADDR scontext; + int retval = 0; + CORE_ADDR orig_sp; + CORE_ADDR temp_sregs; + + scontext = temp_sregs = 0; + + info.read_memory_func = dis_asm_read_memory; + instrlen = s390_readinstruction (instr, pc, &info); + if (sigcaller_pc) + *sigcaller_pc = 0; + if (((instrlen == S390_SYSCALL_SIZE) && + (instr[0] == S390_SYSCALL_OPCODE)) && + ((instr[1] == s390_NR_sigreturn) || (instr[1] == s390_NR_rt_sigreturn))) + { + if (sighandler_fi) + { + if (s390_frameless_function_invocation (sighandler_fi)) + orig_sp = sighandler_fi->frame; + else + orig_sp = ADDR_BITS_REMOVE ((CORE_ADDR) + read_memory_integer (sighandler_fi-> + frame, + S390_GPR_SIZE)); + if (orig_sp && sigcaller_pc) + { + scontext = orig_sp + S390_SIGNAL_FRAMESIZE; + if (pc == scontext && instr[1] == s390_NR_rt_sigreturn) + { + /* We got a new style rt_signal */ + /* get address of read ucontext->uc_mcontext */ + temp_sregs = orig_sp + (GDB_TARGET_IS_ESAME ? + S390X_UC_MCONTEXT_OFFSET : + S390_UC_MCONTEXT_OFFSET); + } + else + { + /* read sigcontext->sregs */ + temp_sregs = ADDR_BITS_REMOVE ((CORE_ADDR) + read_memory_integer (scontext + + + (GDB_TARGET_IS_ESAME + ? + S390X_SIGCONTEXT_SREGS_OFFSET + : + S390_SIGCONTEXT_SREGS_OFFSET), + S390_GPR_SIZE)); + + } + /* read sigregs->psw.addr */ + *sigcaller_pc = + ADDR_BITS_REMOVE ((CORE_ADDR) + read_memory_integer (temp_sregs + + REGISTER_BYTE + (S390_PC_REGNUM), + S390_PSW_ADDR_SIZE)); + } + } + retval = 1; + } + if (sregs) + *sregs = temp_sregs; + return retval; +} + +/* + We need to do something better here but this will keep us out of trouble + for the moment. + For some reason the blockframe.c calls us with fi->next->fromleaf + so this seems of little use to us. */ +void +s390_init_frame_pc_first (int next_fromleaf, struct frame_info *fi) +{ + CORE_ADDR sigcaller_pc; + + fi->pc = 0; + if (next_fromleaf) + { + fi->pc = ADDR_BITS_REMOVE (read_register (S390_RETADDR_REGNUM)); + /* fix signal handlers */ + } + else if (fi->next && fi->next->pc) + fi->pc = s390_frame_saved_pc_nofix (fi->next); + if (fi->pc && fi->next && fi->next->frame && + s390_is_sigreturn (fi->pc, fi->next, NULL, &sigcaller_pc)) + { + fi->pc = sigcaller_pc; + } + +} + +void +s390_init_extra_frame_info (int fromleaf, struct frame_info *fi) +{ + fi->extra_info = frame_obstack_alloc (sizeof (struct frame_extra_info)); + if (fi->pc) + s390_get_frame_info (s390_sniff_pc_function_start (fi->pc, fi), + fi->extra_info, fi, 1); + else + s390_memset_extra_info (fi->extra_info); +} + +/* If saved registers of frame FI are not known yet, read and cache them. + &FEXTRA_INFOP contains struct frame_extra_info; TDATAP can be NULL, + in which case the framedata are read. */ + +void +s390_frame_init_saved_regs (struct frame_info *fi) +{ + + int quick; + + if (fi->saved_regs == NULL) + { + /* zalloc memsets the saved regs */ + frame_saved_regs_zalloc (fi); + if (fi->pc) + { + quick = (fi->extra_info && fi->extra_info->initialised + && fi->extra_info->good_prologue); + s390_get_frame_info (quick ? fi->extra_info->function_start : + s390_sniff_pc_function_start (fi->pc, fi), + fi->extra_info, fi, !quick); + } + } +} + + + +CORE_ADDR +s390_frame_args_address (struct frame_info *fi) +{ + + /* Apparently gdb already knows gdb_args_offset itself */ + return fi->frame; +} + + +static CORE_ADDR +s390_frame_saved_pc_nofix (struct frame_info *fi) +{ + if (fi->extra_info && fi->extra_info->saved_pc_valid) + return fi->extra_info->saved_pc; + s390_frame_init_saved_regs (fi); + if (fi->extra_info) + { + fi->extra_info->saved_pc_valid = 1; + if (fi->extra_info->good_prologue) + { + if (fi->saved_regs[S390_RETADDR_REGNUM]) + { + return (fi->extra_info->saved_pc = + ADDR_BITS_REMOVE (read_memory_integer + (fi->saved_regs[S390_RETADDR_REGNUM], + S390_GPR_SIZE))); + } + } + } + return 0; +} + +CORE_ADDR +s390_frame_saved_pc (struct frame_info *fi) +{ + CORE_ADDR saved_pc = 0, sig_pc; + + if (fi->extra_info && fi->extra_info->sig_fixed_saved_pc_valid) + return fi->extra_info->sig_fixed_saved_pc; + saved_pc = s390_frame_saved_pc_nofix (fi); + + if (fi->extra_info) + { + fi->extra_info->sig_fixed_saved_pc_valid = 1; + if (saved_pc) + { + if (s390_is_sigreturn (saved_pc, fi, NULL, &sig_pc)) + saved_pc = sig_pc; + } + fi->extra_info->sig_fixed_saved_pc = saved_pc; + } + return saved_pc; +} + + + + +/* We want backtraces out of signal handlers so we don't + set thisframe->signal_handler_caller to 1 */ + +CORE_ADDR +s390_frame_chain (struct frame_info *thisframe) +{ + CORE_ADDR prev_fp = 0; + + if (thisframe->prev && thisframe->prev->frame) + prev_fp = thisframe->prev->frame; + else + { + int sigreturn = 0; + CORE_ADDR sregs = 0; + struct frame_extra_info prev_fextra_info; + + memset (&prev_fextra_info, 0, sizeof (prev_fextra_info)); + if (thisframe->pc) + { + CORE_ADDR saved_pc, sig_pc; + + saved_pc = s390_frame_saved_pc_nofix (thisframe); + if (saved_pc) + { + if ((sigreturn = + s390_is_sigreturn (saved_pc, thisframe, &sregs, &sig_pc))) + saved_pc = sig_pc; + s390_get_frame_info (s390_sniff_pc_function_start + (saved_pc, NULL), &prev_fextra_info, NULL, + 1); + } + } + if (sigreturn) + { + /* read sigregs,regs.gprs[11 or 15] */ + prev_fp = read_memory_integer (sregs + + REGISTER_BYTE (S390_GP0_REGNUM + + (prev_fextra_info. + frame_pointer_saved_pc + ? 11 : 15)), + S390_GPR_SIZE); + thisframe->extra_info->sigcontext = sregs; + } + else + { + if (thisframe->saved_regs) + { + + int regno; + + regno = + ((prev_fextra_info.frame_pointer_saved_pc + && thisframe-> + saved_regs[S390_FRAME_REGNUM]) ? S390_FRAME_REGNUM : + S390_SP_REGNUM); + if (thisframe->saved_regs[regno]) + prev_fp = + read_memory_integer (thisframe->saved_regs[regno], + S390_GPR_SIZE); + } + } + } + return ADDR_BITS_REMOVE (prev_fp); +} + +/* + Whether struct frame_extra_info is actually needed I'll have to figure + out as our frames are similar to rs6000 there is a possibility + i386 dosen't need it. */ + + + +/* a given return value in `regbuf' with a type `valtype', extract and copy its + value into `valbuf' */ +void +s390_extract_return_value (struct type *valtype, char *regbuf, char *valbuf) +{ + /* floats and doubles are returned in fpr0. fpr's have a size of 8 bytes. + We need to truncate the return value into float size (4 byte) if + necessary. */ + int len = TYPE_LENGTH (valtype); + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + if (len > (TARGET_FLOAT_BIT >> 3)) + memcpy (valbuf, ®buf[REGISTER_BYTE (S390_FP0_REGNUM)], len); + else + { + /* float */ + DOUBLEST val; + + floatformat_to_doublest (&floatformat_ieee_double_big, + ®buf[REGISTER_BYTE (S390_FP0_REGNUM)], + &val); + store_floating (valbuf, len, val); + } + } + else + { + int offset = 0; + /* return value is copied starting from r2. */ + if (TYPE_LENGTH (valtype) < S390_GPR_SIZE) + offset = S390_GPR_SIZE - TYPE_LENGTH (valtype); + memcpy (valbuf, + regbuf + REGISTER_BYTE (S390_GP0_REGNUM + 2) + offset, + TYPE_LENGTH (valtype)); + } +} + + +static char * +s390_promote_integer_argument (struct type *valtype, char *valbuf, + char *reg_buff, int *arglen) +{ + char *value = valbuf; + int len = TYPE_LENGTH (valtype); + + if (len < S390_GPR_SIZE) + { + /* We need to upgrade this value to a register to pass it correctly */ + int idx, diff = S390_GPR_SIZE - len, negative = + (!TYPE_UNSIGNED (valtype) && value[0] & 0x80); + for (idx = 0; idx < S390_GPR_SIZE; idx++) + { + reg_buff[idx] = (idx < diff ? (negative ? 0xff : 0x0) : + value[idx - diff]); + } + value = reg_buff; + *arglen = S390_GPR_SIZE; + } + else + { + if (len & (S390_GPR_SIZE - 1)) + { + fprintf_unfiltered (gdb_stderr, + "s390_promote_integer_argument detected an argument not " + "a multiple of S390_GPR_SIZE & greater than S390_GPR_SIZE " + "we might not deal with this correctly.\n"); + } + *arglen = len; + } + + return (value); +} + +void +s390_store_return_value (struct type *valtype, char *valbuf) +{ + int arglen; + char *reg_buff = alloca (max (S390_FPR_SIZE, REGISTER_SIZE)), *value; + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + DOUBLEST tempfloat = extract_floating (valbuf, TYPE_LENGTH (valtype)); + + floatformat_from_doublest (&floatformat_ieee_double_big, &tempfloat, + reg_buff); + write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM), reg_buff, + S390_FPR_SIZE); + } + else + { + value = + s390_promote_integer_argument (valtype, valbuf, reg_buff, &arglen); + /* Everything else is returned in GPR2 and up. */ + write_register_bytes (REGISTER_BYTE (S390_GP0_REGNUM + 2), value, + arglen); + } +} +static int +gdb_print_insn_s390 (bfd_vma memaddr, disassemble_info * info) +{ + bfd_byte instrbuff[S390_MAX_INSTR_SIZE]; + int instrlen, cnt; + + instrlen = s390_readinstruction (instrbuff, (CORE_ADDR) memaddr, info); + if (instrlen < 0) + { + (*info->memory_error_func) (instrlen, memaddr, info); + return -1; + } + for (cnt = 0; cnt < instrlen; cnt++) + info->fprintf_func (info->stream, "%02X ", instrbuff[cnt]); + for (cnt = instrlen; cnt < S390_MAX_INSTR_SIZE; cnt++) + info->fprintf_func (info->stream, " "); + instrlen = print_insn_s390 (memaddr, info); + return instrlen; +} + + + +/* Not the most efficent code in the world */ +int +s390_fp_regnum () +{ + int regno = S390_SP_REGNUM; + struct frame_extra_info fextra_info; + + CORE_ADDR pc = ADDR_BITS_REMOVE (read_register (S390_PC_REGNUM)); + + s390_get_frame_info (s390_sniff_pc_function_start (pc, NULL), &fextra_info, + NULL, 1); + if (fextra_info.frame_pointer_saved_pc) + regno = S390_FRAME_REGNUM; + return regno; +} + +CORE_ADDR +s390_read_fp () +{ + return read_register (s390_fp_regnum ()); +} + + +void +s390_write_fp (CORE_ADDR val) +{ + write_register (s390_fp_regnum (), val); +} + + +void +s390_push_dummy_frame () +{ + CORE_ADDR orig_sp = read_register (S390_SP_REGNUM), new_sp; + void *saved_regs = alloca (REGISTER_BYTES); + + new_sp = (orig_sp - (REGISTER_BYTES + S390_GPR_SIZE)); + read_register_bytes (0, (char *) saved_regs, REGISTER_BYTES); + /* Use saved copy instead of orig_sp as this will have the correct endianness */ + write_memory (new_sp, (char *) saved_regs + REGISTER_BYTE (S390_SP_REGNUM), + S390_GPR_SIZE); + write_memory (new_sp + S390_GPR_SIZE, (char *) &saved_regs, REGISTER_BYTES); + write_register (S390_SP_REGNUM, new_sp); +} + +/* pop the innermost frame, go back to the caller. + Used in `call_function_by_hand' to remove an artificial stack + frame. */ +void +s390_pop_frame () +{ + CORE_ADDR new_sp = read_register (S390_SP_REGNUM), orig_sp; + void *saved_regs = alloca (REGISTER_BYTES); + + + read_memory (new_sp + S390_GPR_SIZE, (char *) saved_regs, REGISTER_BYTES); + write_register_bytes (0, (char *) &saved_regs, REGISTER_BYTES); +} + +/* used by call function by hand + struct_return indicates that this function returns a structure & + therefore gpr2 stores a pointer to the structure to be returned as + opposed to the first argument. + Currently I haven't seen a TYPE_CODE_INT whose size wasn't 2^n or less + than S390_GPR_SIZE this is good because I don't seem to have to worry + about sign extending pushed arguments (i.e. a signed char currently + comes into this code with a size of 4 ). */ + +CORE_ADDR +s390_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + int num_float_args, num_gpr_args, orig_num_gpr_args, argno; + int second_pass, len, arglen, gprs_required; + CORE_ADDR outgoing_args_ptr, outgoing_args_space; + value_ptr arg; + struct type *type; + int max_num_gpr_args = 5 - (struct_return ? 1 : 0); + int arg0_regnum = S390_GP0_REGNUM + 2 + (struct_return ? 1 : 0); + char *reg_buff = alloca (max (S390_FPR_SIZE, REGISTER_SIZE)), *value; + + for (second_pass = 0; second_pass <= 1; second_pass++) + { + if (second_pass) + outgoing_args_ptr = sp + S390_STACK_FRAME_OVERHEAD; + else + outgoing_args_ptr = 0; + num_float_args = 0; + num_gpr_args = 0; + for (argno = 0; argno < nargs; argno++) + { + arg = args[argno]; + type = check_typedef (VALUE_TYPE (arg)); + len = TYPE_LENGTH (type); + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + int all_float_registers_used = + num_float_args > (GDB_TARGET_IS_ESAME ? 3 : 1); + + if (second_pass) + { + DOUBLEST tempfloat = + extract_floating (VALUE_CONTENTS (arg), len); + + + floatformat_from_doublest (all_float_registers_used && + len == (TARGET_FLOAT_BIT >> 3) + ? &floatformat_ieee_single_big + : &floatformat_ieee_double_big, + &tempfloat, reg_buff); + if (all_float_registers_used) + write_memory (outgoing_args_ptr, reg_buff, len); + else + write_register_bytes (REGISTER_BYTE ((S390_FP0_REGNUM) + + + (2 * + num_float_args)), + reg_buff, S390_FPR_SIZE); + } + if (all_float_registers_used) + outgoing_args_ptr += len; + num_float_args++; + } + else + { + gprs_required = ((len + (S390_GPR_SIZE - 1)) / S390_GPR_SIZE); + + value = + s390_promote_integer_argument (type, VALUE_CONTENTS (arg), + reg_buff, &arglen); + + orig_num_gpr_args = num_gpr_args; + num_gpr_args += gprs_required; + if (num_gpr_args > max_num_gpr_args) + { + if (second_pass) + write_memory (outgoing_args_ptr, value, arglen); + outgoing_args_ptr += arglen; + } + else + { + if (second_pass) + write_register_bytes (REGISTER_BYTE (arg0_regnum) + + + (orig_num_gpr_args * S390_GPR_SIZE), + value, arglen); + } + } + } + if (!second_pass) + { + outgoing_args_space = outgoing_args_ptr; + /* Align to 16 bytes because because I like alignment & + some of the kernel code requires 8 byte stack alignment at least. */ + sp = (sp - (S390_STACK_FRAME_OVERHEAD + outgoing_args_ptr)) & (-16); + } + + } + return sp; + +} + +void +s390_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, + struct value **args, struct type *value_type, + int using_gcc) +{ + store_unsigned_integer (dummy + 4, REGISTER_SIZE, fun); +} + + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +struct type * +s390_register_virtual_type (int regno) +{ + return ((unsigned) regno - S390_FPC_REGNUM) < + S390_NUM_FPRS ? builtin_type_double : builtin_type_int; +} + + +struct type * +s390x_register_virtual_type (int regno) +{ + return (regno == S390_FPC_REGNUM) || + (regno >= S390_FIRST_ACR && regno <= S390_LAST_ACR) ? builtin_type_int : + (regno >= S390_FP0_REGNUM) ? builtin_type_double : builtin_type_long; +} + + + +void +s390_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +{ + write_register (S390_GP0_REGNUM + 2, addr); +} + + + +static unsigned char * +s390_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) +{ + static unsigned char breakpoint[] = { 0x0, 0x1 }; + + *lenptr = sizeof (breakpoint); + return breakpoint; +} + +/* Advance PC across any function entry prologue instructions to reach some + "real" code. */ +CORE_ADDR +s390_skip_prologue (CORE_ADDR pc) +{ + struct frame_extra_info fextra_info; + + s390_get_frame_info (pc, &fextra_info, NULL, 1); + return fextra_info.skip_prologue_function_start; +} + +/* pc_in_call_dummy_on stack may work for us must test this */ +int +s390_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address) +{ + return pc > sp && pc < (sp + 4096); +} + +/* Immediately after a function call, return the saved pc. + Can't go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ +CORE_ADDR +s390_saved_pc_after_call (struct frame_info *frame) +{ + return ADDR_BITS_REMOVE (read_register (S390_RETADDR_REGNUM)); +} + +static CORE_ADDR +s390_addr_bits_remove (CORE_ADDR addr) +{ + return (addr) & 0x7fffffff; +} + + +static CORE_ADDR +s390_push_return_address (CORE_ADDR pc, CORE_ADDR sp) +{ + return sp; +} + +struct gdbarch * +s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + + /* instruction sequence for s390 call dummy is as follows + bras %r1,.+8 ; 0xA7150004 + long basraddr ; 0x00000000 + l %r1,0(%r1) ; 0x58101000 + basr %r14,%r1 ; 0x0DE1 + breakpoint ; 0x0001 */ + static LONGEST s390_call_dummy_words[] = { 0xA7150004, 0x00000000, + 0x58101000, 0x0DE10001 + }; + /* instruction sequence for esame call dummy is as follows + bras %r1,.+12 ; 0xA7150006 + long basraddr ; 0x0000000000000000 + lg %r1,0(%r1) ; 0xE31010000004 + basr %r14,%r1 ; 0x0DE1 + breakpoint ; 0x0001 */ + static LONGEST s390x_call_dummy_words[] = { 0xA715000600000000, + 0x00000000E3101000, + 0x00040DE100010000 + }; + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + int elf_flags; + + /* First see if there is already a gdbarch that can satisfy the request. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; + + /* None found: is the request for a s390 architecture? */ + if (info.bfd_arch_info->arch != bfd_arch_s390) + return NULL; /* No; then it's not for us. */ + + /* Yes: create a new gdbarch for the specified machine type. */ + gdbarch = gdbarch_alloc (&info, NULL); + + set_gdbarch_believe_pcc_promotion (gdbarch, 0); + + /* We don't define set_gdbarch_call_dummy_breakpoint_offset + as we already have a breakpoint inserted. */ + set_gdbarch_use_generic_dummy_frames (gdbarch, 0); + + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + set_gdbarch_call_dummy_start_offset (gdbarch, 0); + set_gdbarch_pc_in_call_dummy (gdbarch, s390_pc_in_call_dummy); + set_gdbarch_frame_args_skip (gdbarch, 0); + set_gdbarch_frame_args_address (gdbarch, s390_frame_args_address); + set_gdbarch_frame_chain (gdbarch, s390_frame_chain); + set_gdbarch_frame_init_saved_regs (gdbarch, s390_frame_init_saved_regs); + set_gdbarch_frame_locals_address (gdbarch, s390_frame_args_address); + /* We can't do this */ + set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); + set_gdbarch_store_struct_return (gdbarch, s390_store_struct_return); + set_gdbarch_extract_return_value (gdbarch, s390_extract_return_value); + set_gdbarch_store_return_value (gdbarch, s390_store_return_value); + /* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + set_gdbarch_decr_pc_after_break (gdbarch, 2); + set_gdbarch_pop_frame (gdbarch, s390_pop_frame); + set_gdbarch_push_dummy_frame (gdbarch, s390_push_dummy_frame); + set_gdbarch_push_arguments (gdbarch, s390_push_arguments); + set_gdbarch_ieee_float (gdbarch, 1); + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + /* Offset from address of function to start of its code. + Zero on most machines. */ + set_gdbarch_function_start_offset (gdbarch, 0); + set_gdbarch_max_register_raw_size (gdbarch, 8); + set_gdbarch_max_register_virtual_size (gdbarch, 8); + set_gdbarch_breakpoint_from_pc (gdbarch, s390_breakpoint_from_pc); + set_gdbarch_skip_prologue (gdbarch, s390_skip_prologue); + set_gdbarch_init_extra_frame_info (gdbarch, s390_init_extra_frame_info); + set_gdbarch_init_frame_pc_first (gdbarch, s390_init_frame_pc_first); + set_gdbarch_read_fp (gdbarch, s390_read_fp); + set_gdbarch_write_fp (gdbarch, s390_write_fp); + /* This function that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + set_gdbarch_frameless_function_invocation (gdbarch, + s390_frameless_function_invocation); + /* Return saved PC from a frame */ + set_gdbarch_frame_saved_pc (gdbarch, s390_frame_saved_pc); + /* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. */ + set_gdbarch_frame_chain (gdbarch, s390_frame_chain); + set_gdbarch_saved_pc_after_call (gdbarch, s390_saved_pc_after_call); + set_gdbarch_register_byte (gdbarch, s390_register_byte); + set_gdbarch_pc_regnum (gdbarch, S390_PC_REGNUM); + set_gdbarch_sp_regnum (gdbarch, S390_SP_REGNUM); + set_gdbarch_fp_regnum (gdbarch, S390_FP_REGNUM); + set_gdbarch_fp0_regnum (gdbarch, S390_FP0_REGNUM); + set_gdbarch_num_regs (gdbarch, S390_NUM_REGS); + set_gdbarch_cannot_fetch_register (gdbarch, s390_cannot_fetch_register); + set_gdbarch_cannot_store_register (gdbarch, s390_cannot_fetch_register); + set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register); + set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention); + set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid); + set_gdbarch_register_name (gdbarch, s390_register_name); + set_gdbarch_stab_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum); + set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum); + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + + /* Stuff below here wouldn't be required if gdbarch.sh was a little */ + /* more intelligent */ + set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 0); + set_gdbarch_call_dummy_p (gdbarch, 1); + set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); + set_gdbarch_extract_struct_value_address (gdbarch, 0); + set_gdbarch_fix_call_dummy (gdbarch, s390_fix_call_dummy); +#ifdef GDB_NM_FILE + set_gdbarch_prepare_to_proceed (gdbarch, linuxthreads_prepare_to_proceed); +#endif + set_gdbarch_push_return_address (gdbarch, s390_push_return_address); + + switch (info.bfd_arch_info->mach) + { + case bfd_mach_s390_esa: + set_gdbarch_register_size (gdbarch, 4); + set_gdbarch_call_dummy_length (gdbarch, 16); + set_gdbarch_register_raw_size (gdbarch, s390_register_raw_size); + set_gdbarch_register_virtual_size (gdbarch, s390_register_raw_size); + set_gdbarch_register_virtual_type (gdbarch, s390_register_virtual_type); + + set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove); + + set_gdbarch_sizeof_call_dummy_words (gdbarch, + sizeof (s390_call_dummy_words)); + set_gdbarch_call_dummy_words (gdbarch, s390_call_dummy_words); + set_gdbarch_register_bytes (gdbarch, S390_REGISTER_BYTES); + break; + case bfd_mach_s390_esame: + set_gdbarch_register_size (gdbarch, 8); + set_gdbarch_call_dummy_length (gdbarch, 22); + set_gdbarch_register_raw_size (gdbarch, s390x_register_raw_size); + set_gdbarch_register_virtual_size (gdbarch, s390x_register_raw_size); + set_gdbarch_register_virtual_type (gdbarch, + s390x_register_virtual_type); + + set_gdbarch_long_bit (gdbarch, 64); + set_gdbarch_long_long_bit (gdbarch, 64); + set_gdbarch_ptr_bit (gdbarch, 64); + set_gdbarch_sizeof_call_dummy_words (gdbarch, + sizeof (s390x_call_dummy_words)); + set_gdbarch_call_dummy_words (gdbarch, s390x_call_dummy_words); + set_gdbarch_register_bytes (gdbarch, S390X_REGISTER_BYTES); + break; + } + + return gdbarch; +} + + + +void +_initialize_s390_tdep () +{ + + /* Hook us into the gdbarch mechanism. */ + register_gdbarch_init (bfd_arch_s390, s390_gdbarch_init); + if (!tm_print_insn) /* Someone may have already set it */ + tm_print_insn = gdb_print_insn_s390; +} + +#endif /* GDBSERVER */ diff --git a/gdb/signals.c b/gdb/signals.c index abbd7a56c92..8a959e5784c 100644 --- a/gdb/signals.c +++ b/gdb/signals.c @@ -24,6 +24,7 @@ #include "target.h" #include <signal.h> +#ifndef GDBSERVER /* This table must match in order and size the signals in enum target_signal in target.h. */ /* *INDENT-OFF* */ @@ -230,13 +231,13 @@ target_signal_from_name (char *name) /* This ugly cast brought to you by the native VAX compiler. */ for (sig = TARGET_SIGNAL_HUP; - signals[sig].name != NULL; - sig = (enum target_signal) ((int) sig + 1)) + signals[sig].name != NULL; sig = (enum target_signal) ((int) sig + 1)) if (STREQ (name, signals[sig].name)) return sig; return TARGET_SIGNAL_UNKNOWN; } - +#endif /* GDBSERVER */ + /* The following functions are to help certain targets deal with the signal/waitstatus stuff. They could just as well be in a file called native-utils.c or unixwaitstatus-utils.c or whatever. */ @@ -480,7 +481,8 @@ target_signal_from_host (int hostsig) return (enum target_signal) (hostsig - 64 + (int) TARGET_SIGNAL_REALTIME_64); else - error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); + error + ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); } #endif @@ -494,7 +496,8 @@ target_signal_from_host (int hostsig) else if (hostsig == 64) return TARGET_SIGNAL_REALTIME_64; else - error ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); + error + ("GDB bug: target.c (target_signal_from_host): unrecognized real-time signal"); } #endif return TARGET_SIGNAL_UNKNOWN; @@ -506,8 +509,7 @@ target_signal_from_host (int hostsig) accordingly. */ static int -do_target_signal_to_host (enum target_signal oursig, - int *oursig_ok) +do_target_signal_to_host (enum target_signal oursig, int *oursig_ok) { *oursig_ok = 1; switch (oursig) @@ -737,9 +739,8 @@ do_target_signal_to_host (enum target_signal oursig, && oursig <= TARGET_SIGNAL_REALTIME_63) { /* This block of signals is continuous, and - TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ - int retsig = - (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; + TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ + int retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; if (retsig >= REALTIME_LO && retsig < REALTIME_HI) return retsig; } @@ -747,7 +748,7 @@ do_target_signal_to_host (enum target_signal oursig, else if (oursig == TARGET_SIGNAL_REALTIME_32) { /* TARGET_SIGNAL_REALTIME_32 isn't contiguous with - TARGET_SIGNAL_REALTIME_33. It is 32 by definition. */ + TARGET_SIGNAL_REALTIME_33. It is 32 by definition. */ return 32; } #endif @@ -756,13 +757,12 @@ do_target_signal_to_host (enum target_signal oursig, && oursig <= TARGET_SIGNAL_REALTIME_127) { /* This block of signals is continuous, and - TARGET_SIGNAL_REALTIME_64 is 64 by definition. */ - int retsig = - (int) oursig - (int) TARGET_SIGNAL_REALTIME_64 + 64; + TARGET_SIGNAL_REALTIME_64 is 64 by definition. */ + int retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_64 + 64; if (retsig >= REALTIME_LO && retsig < REALTIME_HI) return retsig; } - + #endif #endif @@ -771,9 +771,8 @@ do_target_signal_to_host (enum target_signal oursig, && oursig <= TARGET_SIGNAL_REALTIME_63) { /* This block of signals is continuous, and - TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ - int retsig = - (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; + TARGET_SIGNAL_REALTIME_33 is 33 by definition. */ + int retsig = (int) oursig - (int) TARGET_SIGNAL_REALTIME_33 + 33; if (retsig >= SIGRTMIN && retsig <= SIGRTMAX) return retsig; } @@ -785,6 +784,7 @@ do_target_signal_to_host (enum target_signal oursig, } } +#ifndef GDBSERVER int target_signal_to_host_p (enum target_signal oursig) { @@ -792,6 +792,7 @@ target_signal_to_host_p (enum target_signal oursig) do_target_signal_to_host (oursig, &oursig_ok); return oursig_ok; } +#endif /* GDBSERVER */ int target_signal_to_host (enum target_signal oursig) @@ -802,14 +803,21 @@ target_signal_to_host (enum target_signal oursig) { /* The user might be trying to do "signal SIGSAK" where this system doesn't have SIGSAK. */ +#ifdef GDBSERVER + fprintf (stderr, "Target signal %d does not exist on this system.\n", + oursig); +#else warning ("Signal %s does not exist on this system.\n", target_signal_to_name (oursig)); +#endif + return 0; } else return targ_signo; } +#ifndef GDBSERVER /* In some circumstances we allow a command to specify a numeric signal. The idea is to keep these circumstances limited so that users (and scripts) develop portable habits. For comparison, @@ -833,3 +841,4 @@ _initialize_signals (void) if (!STREQ (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC")) internal_error (__FILE__, __LINE__, "failed internal consistency check"); } +#endif /* GDBSERVER */ |