diff options
-rw-r--r-- | gdb/ChangeLog | 41 | ||||
-rw-r--r-- | gdb/Makefile.in | 22 | ||||
-rw-r--r-- | gdb/config/djgpp/fnchange.lst | 2 | ||||
-rw-r--r-- | gdb/config/ia64/hpux.mh | 3 | ||||
-rw-r--r-- | gdb/config/pa/hpux.mh | 3 | ||||
-rwxr-xr-x | gdb/configure | 106 | ||||
-rw-r--r-- | gdb/configure.ac | 10 | ||||
-rw-r--r-- | gdb/configure.host | 10 | ||||
-rw-r--r-- | gdb/configure.tgt | 10 | ||||
-rw-r--r-- | gdb/hppa-hpux-nat.c | 273 | ||||
-rw-r--r-- | gdb/hppa-hpux-tdep.c | 1572 | ||||
-rw-r--r-- | gdb/hppa-tdep.c | 43 | ||||
-rw-r--r-- | gdb/hppa-tdep.h | 35 | ||||
-rw-r--r-- | gdb/ia64-hpux-nat.c | 756 | ||||
-rw-r--r-- | gdb/ia64-hpux-tdep.c | 434 | ||||
-rw-r--r-- | gdb/ia64-hpux-tdep.h | 24 | ||||
-rw-r--r-- | gdb/inf-ttrace.c | 1224 | ||||
-rw-r--r-- | gdb/inf-ttrace.h | 28 | ||||
-rw-r--r-- | gdb/solib-ia64-hpux.c | 705 | ||||
-rw-r--r-- | gdb/solib-ia64-hpux.h | 25 | ||||
-rw-r--r-- | gdb/solib-pa64.c | 654 | ||||
-rw-r--r-- | gdb/solib-pa64.h | 25 | ||||
-rw-r--r-- | gdb/solib-som.c | 891 | ||||
-rw-r--r-- | gdb/solib-som.h | 35 | ||||
-rw-r--r-- | gdb/somread.c | 547 |
25 files changed, 88 insertions, 7390 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index dd9d9e2..65a0051 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,44 @@ +2014-10-16 Jan Kratochvil <jan.kratochvil@redhat.com> + + Remove HPUX. + * Makefile.in (ALL_64_TARGET_OBS): Remove ia64-hpux-tdep.o. + (ALL_TARGET_OBS): Remove hppa-hpux-tdep.o, solib-som.o and solib-pa64.o. + (HFILES_NO_SRCDIR): Remove solib-som.h, inf-ttrace.h, solib-pa64.h and + ia64-hpux-tdep.h, solib-ia64-hpux.h. + (ALLDEPFILES): Remove hppa-hpux-tdep.c, hppa-hpux-nat.c, + ia64-hpux-nat.c, ia64-hpux-tdep.c, somread.c and solib-som.c. + * config/djgpp/fnchange.lst: Remove hppa-hpux-nat.c and + hppa-hpux-tdep.c. + * config/ia64/hpux.mh: Remove file. + * config/pa/hpux.mh: Remove file. + * configure: Rebuilt. + * configure.ac (dlgetmodinfo, somread.o): Remove. + * configure.host (hppa*-*-hpux*, ia64-*-hpux*): Make them obsolete. + (ia64-*-hpux*): Remove its float format exception. + * configure.tgt (hppa*-*-hpux*, ia64-*-hpux*): Make them obsolete. + * hppa-hpux-nat.c: Remove file. + * hppa-hpux-tdep.c: Remove file. + * hppa-tdep.c (struct hppa_unwind_info, struct hppa_objfile_private): + Move them here from hppa-tdep.h + (hppa_objfile_priv_data, hppa_init_objfile_priv_data): Make it static. + (hppa_frame_prev_register_helper): Remove HPPA_FLAGS_REGNUM exception. + * hppa-tdep.h (struct hppa_unwind_info, struct hppa_objfile_private): + Move them to hppa-tdep.c. + (hppa_objfile_priv_data, hppa_init_objfile_priv_data): Remove + declarations. + * ia64-hpux-nat.c: Remove file. + * ia64-hpux-tdep.c: Remove file. + * ia64-hpux-tdep.h: Remove file. + * inf-ttrace.c: Remove file. + * inf-ttrace.h: Remove file. + * solib-ia64-hpux.c: Remove file. + * solib-ia64-hpux.h: Remove file. + * solib-pa64.c: Remove file. + * solib-pa64.h: Remove file. + * solib-som.c: Remove file. + * solib-som.h: Remove file. + * somread.c: Remove file. + 2015-03-13 John Baldwin <jhb@FreeBSD.org> * configure.ac: AC_SEARCH_LIBS(kinfo_getvmmap, util). diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7eefa5b..dbace2d 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -635,7 +635,7 @@ ALL_64_TARGET_OBS = \ amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \ amd64-linux-tdep.o amd64nbsd-tdep.o \ amd64obsd-tdep.o amd64-sol2-tdep.o amd64-tdep.o amd64-windows-tdep.o \ - ia64-hpux-tdep.o ia64-linux-tdep.o ia64-vms-tdep.o ia64-tdep.o \ + ia64-linux-tdep.o ia64-vms-tdep.o ia64-tdep.o \ mips64obsd-tdep.o \ sparc64fbsd-tdep.o sparc64-linux-tdep.o sparc64nbsd-tdep.o \ sparc64obsd-tdep.o sparc64-sol2-tdep.o sparc64-tdep.o @@ -653,7 +653,7 @@ ALL_TARGET_OBS = \ frv-linux-tdep.o frv-tdep.o \ h8300-tdep.o \ hppabsd-tdep.o hppanbsd-tdep.o hppaobsd-tdep.o \ - hppa-hpux-tdep.o hppa-linux-tdep.o hppa-tdep.o \ + hppa-linux-tdep.o hppa-tdep.o \ i386bsd-tdep.o i386-cygwin-tdep.o i386fbsd-tdep.o i386gnu-tdep.o \ i386-linux-tdep.o i386nbsd-tdep.o i386-nto-tdep.o i386obsd-tdep.o \ i386-sol2-tdep.o i386-tdep.o i387-tdep.o \ @@ -698,7 +698,7 @@ ALL_TARGET_OBS = \ nbsd-tdep.o obsd-tdep.o \ sol2-tdep.o \ solib-frv.o solib-svr4.o \ - solib-som.o solib-pa64.o solib-darwin.o solib-dsbt.o \ + solib-darwin.o solib-dsbt.o \ dbug-rom.o dink32-rom.o ppcbug-rom.o m32r-rom.o dsrec.o monitor.o \ remote-m32r-sdi.o remote-mips.o \ xcoffread.o \ @@ -894,7 +894,7 @@ common/gdb_signals.h nat/gdb_thread_db.h common/gdb_vecs.h \ common/x86-xstate.h nat/linux-ptrace.h nat/mips-linux-watch.h \ proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \ ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \ -exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \ +exec.h m32r-tdep.h osabi.h gdbcore.h amd64bsd-nat.h \ i386bsd-nat.h xml-support.h xml-tdesc.h alphabsd-tdep.h gdb_obstack.h \ ia64-tdep.h ada-lang.h varobj.h varobj-iter.h frv-tdep.h \ nto-tdep.h serial.h \ @@ -911,7 +911,7 @@ ser-unix.h inf-ptrace.h terminal.h ui-out.h frame-base.h \ f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \ objfiles.h common/vec.h disasm.h mips-tdep.h ser-base.h \ gdb_curses.h bfd-target.h memattr.h inferior.h ax.h dummy-frame.h \ -inflow.h fbsd-nat.h ia64-libunwind-tdep.h completer.h inf-ttrace.h \ +inflow.h fbsd-nat.h ia64-libunwind-tdep.h completer.h \ solib-target.h gdb_vfork.h alpha-tdep.h dwarf2expr.h \ m2-lang.h stack.h charset.h addrmap.h command.h solist.h source.h \ target.h target-dcache.h prologue-value.h cp-abi.h tui/tui-hooks.h tui/tui.h \ @@ -928,7 +928,7 @@ complaints.h gdb_proc_service.h gdb_regex.h xtensa-tdep.h inf-loop.h \ common/gdb_wait.h common/gdb_assert.h solib.h ppc-tdep.h cp-support.h glibc-tdep.h \ interps.h auxv.h gdbcmd.h tramp-frame.h mipsnbsd-tdep.h \ amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \ -sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h solib-pa64.h \ +sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h \ coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \ m68k-tdep.h spu-tdep.h jv-lang.h environ.h amd64-tdep.h \ doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \ @@ -945,7 +945,7 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \ gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h \ -psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h \ +psymtab.h psympriv.h progspace.h bfin-tdep.h \ amd64-darwin-tdep.h charset-list.h \ config/djgpp/langinfo.h config/djgpp/nl_types.h darwin-nat.h \ dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \ @@ -953,7 +953,7 @@ i386-darwin-tdep.h x86-nat.h linux-record.h moxie-tdep.h nios2-tdep.h \ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \ python/python-internal.h python/python.h ravenscar-thread.h record.h \ record-full.h solib-aix.h \ -solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \ +solib-darwin.h solib-spu.h windows-nat.h xcoffread.h \ gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h \ gnulib/import/extra/snippet/warn-on-use.h \ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \ @@ -1657,7 +1657,7 @@ ALLDEPFILES = \ fork-child.c \ glibc-tdep.c \ go32-nat.c h8300-tdep.c \ - hppa-tdep.c hppa-hpux-tdep.c hppa-hpux-nat.c \ + hppa-tdep.c \ hppa-linux-tdep.c hppa-linux-nat.c \ hppabsd-tdep.c \ hppanbsd-nat.c hppanbsd-tdep.c \ @@ -1672,9 +1672,8 @@ ALLDEPFILES = \ i386-linux-tdep.c x86-nat.c \ i386-sol2-nat.c i386-sol2-tdep.c \ i386gnu-nat.c i386gnu-tdep.c \ - ia64-hpux-nat.c ia64-hpux-tdep.c \ ia64-linux-nat.c ia64-linux-tdep.c ia64-tdep.c ia64-vms-tdep.c \ - inf-ptrace.c inf-ttrace.c \ + inf-ptrace.c \ ia64-libunwind-tdep.c \ linux-fork.c \ linux-tdep.c \ @@ -1697,7 +1696,6 @@ ALLDEPFILES = \ msp430-tdep.c \ nios2-tdep.c nios2-linux-tdep.c \ nbsd-nat.c nbsd-tdep.c obsd-nat.c obsd-tdep.c \ - somread.c solib-som.c \ posix-hdep.c common/posix-strerror.c \ ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c ppc64-tdep.c \ ppcfbsd-nat.c ppcfbsd-tdep.c \ diff --git a/gdb/config/djgpp/fnchange.lst b/gdb/config/djgpp/fnchange.lst index d977870..c05eb2c 100644 --- a/gdb/config/djgpp/fnchange.lst +++ b/gdb/config/djgpp/fnchange.lst @@ -510,8 +510,6 @@ @V@/gdb/amd64-linux-nat.c @V@/gdb/amd64-lnat.c @V@/gdb/hppa-linux-tdep.c @V@/gdb/palnxtdep.c @V@/gdb/hppa-linux-nat.c @V@/gdb/palnxnat.c -@V@/gdb/hppa-hpux-nat.c @V@/gdb/pahpuxnat.c -@V@/gdb/hppa-hpux-tdep.c @V@/gdb/pahpuxtdep.c @V@/gdb/hppanbsd-nat.c @V@/gdb/panbsd-nat.c @V@/gdb/hppanbsd-tdep.c @V@/gdb/panbsd-tdep.c @V@/gdb/amd64-windows-nat.c @V@/gdb/amd64-wnat.c diff --git a/gdb/config/ia64/hpux.mh b/gdb/config/ia64/hpux.mh deleted file mode 100644 index 7bbfab4..0000000 --- a/gdb/config/ia64/hpux.mh +++ /dev/null @@ -1,3 +0,0 @@ -# Host: ia64 running HP-UX -NATDEPFILES= fork-child.o inf-ttrace.o ia64-hpux-nat.o \ - solib-ia64-hpux.o diff --git a/gdb/config/pa/hpux.mh b/gdb/config/pa/hpux.mh deleted file mode 100644 index 3151120..0000000 --- a/gdb/config/pa/hpux.mh +++ /dev/null @@ -1,3 +0,0 @@ -# Host: PA-RISC HP-UX -NATDEPFILES= fork-child.o inf-ptrace.o inf-ttrace.o \ - hppa-hpux-nat.o diff --git a/gdb/configure b/gdb/configure index 78d206b..db239b3 100755 --- a/gdb/configure +++ b/gdb/configure @@ -7101,64 +7101,6 @@ fi fi -# On HP/UX we may need libxpdl for dlgetmodinfo (used by solib-pa64.c). -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlgetmodinfo" >&5 -$as_echo_n "checking for library containing dlgetmodinfo... " >&6; } -if test "${ac_cv_search_dlgetmodinfo+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlgetmodinfo (); -int -main () -{ -return dlgetmodinfo (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dl xpdl; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_dlgetmodinfo=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if test "${ac_cv_search_dlgetmodinfo+set}" = set; then : - break -fi -done -if test "${ac_cv_search_dlgetmodinfo+set}" = set; then : - -else - ac_cv_search_dlgetmodinfo=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlgetmodinfo" >&5 -$as_echo "$ac_cv_search_dlgetmodinfo" >&6; } -ac_res=$ac_cv_search_dlgetmodinfo -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - # On FreeBSD we may need libutil for kinfo_getvmmap (used by fbsd-nat.c). { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing kinfo_getvmmap" >&5 $as_echo_n "checking for library containing kinfo_getvmmap... " >&6; } @@ -13803,54 +13745,6 @@ if test $gdb_cv_var_macho = yes; then CONFIG_OBS="$CONFIG_OBS machoread.o" fi -# Add SOM support to GDB, but only if BFD includes it. - - OLD_CFLAGS=$CFLAGS - OLD_LDFLAGS=$LDFLAGS - OLD_LIBS=$LIBS - # Put the old CFLAGS/LDFLAGS last, in case the user's (C|LD)FLAGS - # points somewhere with bfd, with -I/foo/lib and -L/foo/lib. We - # always want our bfd. - CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS" - LDFLAGS="-L../bfd -L../libiberty $LDFLAGS" - intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'` - LIBS="-lbfd -liberty $intl $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SOM support in BFD" >&5 -$as_echo_n "checking for SOM support in BFD... " >&6; } -if test "${gdb_cv_var_som+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <stdlib.h> - #include "bfd.h" - #include "som.h" - -int -main () -{ -return bfd_som_attach_aux_hdr (NULL, 0, NULL); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - gdb_cv_var_som=yes -else - gdb_cv_var_som=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_var_som" >&5 -$as_echo "$gdb_cv_var_som" >&6; } - CFLAGS=$OLD_CFLAGS - LDFLAGS=$OLD_LDFLAGS - LIBS=$OLD_LIBS -if test $gdb_cv_var_som = yes; then - CONFIG_OBS="$CONFIG_OBS somread.o" -fi - # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" diff --git a/gdb/configure.ac b/gdb/configure.ac index 38747e8..ace033e 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -534,9 +534,6 @@ AC_SEARCH_LIBS(socketpair, socket) # Link in zlib if we can. This allows us to read compressed debug sections. AM_ZLIB -# On HP/UX we may need libxpdl for dlgetmodinfo (used by solib-pa64.c). -AC_SEARCH_LIBS(dlgetmodinfo, [dl xpdl]) - # On FreeBSD we may need libutil for kinfo_getvmmap (used by fbsd-nat.c). AC_SEARCH_LIBS(kinfo_getvmmap, util, [AC_DEFINE(HAVE_KINFO_GETVMMAP, 1, @@ -2134,13 +2131,6 @@ if test $gdb_cv_var_macho = yes; then CONFIG_OBS="$CONFIG_OBS machoread.o" fi -# Add SOM support to GDB, but only if BFD includes it. -GDB_AC_CHECK_BFD([for SOM support in BFD], gdb_cv_var_som, - [bfd_som_attach_aux_hdr (NULL, 0, NULL)], som.h) -if test $gdb_cv_var_som = yes; then - CONFIG_OBS="$CONFIG_OBS somread.o" -fi - # Add any host-specific objects to GDB. CONFIG_OBS="${CONFIG_OBS} ${gdb_host_obs}" diff --git a/gdb/configure.host b/gdb/configure.host index d07be4b..48714f4 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -44,6 +44,8 @@ case $host in vax-*-bsd* | \ vax-*-netbsd* | \ vax-*-ultrix* | \ + hppa*-*-hpux* | \ + ia64-*-hpux* | \ null) echo "*** Configuration $host is obsolete." >&2 echo "*** Support has been REMOVED." >&2 @@ -93,8 +95,6 @@ arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) gdb_host=nbsdelf ;; arm*-*-openbsd*) gdb_host=nbsdelf ;; -hppa*-*-hpux*) - gdb_host=hpux ;; hppa*-*-linux*) gdb_host=linux ;; hppa*-*-netbsd*) gdb_host=nbsd ;; hppa*-*-openbsd*) gdb_host=obsd ;; @@ -117,7 +117,6 @@ i[34567]86-*-solaris2.1[0-9]* | x86_64-*-solaris2.1[0-9]*) i[34567]86-*-solaris*) gdb_host=i386sol2 ;; i[34567]86-*-cygwin*) gdb_host=cygwin ;; -ia64-*-hpux*) gdb_host=hpux ;; ia64-*-linux*) gdb_host=linux ;; m68*-*-linux*) gdb_host=linux ;; @@ -211,11 +210,6 @@ m68*-*-*) gdb_host_double_format="&floatformat_ieee_double_big" gdb_host_long_double_format="&floatformat_m68881_ext" ;; -ia64-*-hpux*) - gdb_host_float_format="&floatformat_ieee_single_big" - gdb_host_double_format="&floatformat_ieee_double_big" - gdb_host_long_double_format="&floatformat_ia64_quad_big" - ;; *) gdb_host_float_format=0 gdb_host_double_format=0 diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 7fdd34e..c97ebdd 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -24,6 +24,8 @@ case $targ in mips*-*-pe | \ rs6000-*-lynxos* | \ sh*-*-pe | \ + hppa*-*-hpux* | \ + ia64-*-hpux* | \ null) echo "*** Configuration $targ is obsolete." >&2 echo "*** Support has been REMOVED." >&2 @@ -149,10 +151,6 @@ h8300-*-*) gdb_sim=../sim/h8300/libsim.a ;; -hppa*-*-hpux*) - # Target: HP PA-RISC running hpux - gdb_target_obs="hppa-tdep.o hppa-hpux-tdep.o solib-som.o solib-pa64.o" - ;; hppa*-*-linux*) # Target: HP PA-RISC running Linux gdb_target_obs="hppa-tdep.o hppa-linux-tdep.o glibc-tdep.o \ @@ -247,10 +245,6 @@ i[34567]86-*-*) gdb_target_obs="i386-tdep.o i387-tdep.o" ;; -ia64-*-hpux*) - # Target: Intel IA-64 running HP-UX - gdb_target_obs="ia64-tdep.o ia64-hpux-tdep.o" - ;; ia64-*-linux*) # Target: Intel IA-64 running GNU/Linux gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o linux-tdep.o \ diff --git a/gdb/hppa-hpux-nat.c b/gdb/hppa-hpux-nat.c deleted file mode 100644 index 0727568..0000000 --- a/gdb/hppa-hpux-nat.c +++ /dev/null @@ -1,273 +0,0 @@ -/* Native-dependent code for PA-RISC HP-UX. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "inferior.h" -#include "regcache.h" -#include "target.h" - -#include <sys/ptrace.h> -#include <sys/utsname.h> -#include <machine/save_state.h> - -#ifdef HAVE_TTRACE -#include <sys/ttrace.h> -#endif - -#include "hppa-tdep.h" -#include "solib-som.h" -#include "inf-ptrace.h" -#include "inf-ttrace.h" - -/* Return the offset of register REGNUM within `struct save_state'. - The offset returns depends on the flags in the "flags" register and - the register size (32-bit or 64-bit). These are taken from - REGCACHE. */ - -static LONGEST -hppa_hpux_save_state_offset (struct regcache *regcache, int regnum) -{ - LONGEST offset; - - if (regnum == HPPA_FLAGS_REGNUM) - return ssoff (ss_flags); - - if (HPPA_R0_REGNUM < regnum && regnum < HPPA_FP0_REGNUM) - { - struct gdbarch *arch = get_regcache_arch (regcache); - size_t size = register_size (arch, HPPA_R1_REGNUM); - ULONGEST flags; - - gdb_assert (size == 4 || size == 8); - - regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags); - if (flags & SS_WIDEREGS) - offset = ssoff (ss_wide) + (8 - size) + (regnum - HPPA_R0_REGNUM) * 8; - else - offset = ssoff (ss_narrow) + (regnum - HPPA_R1_REGNUM) * 4; - } - else - { - struct gdbarch *arch = get_regcache_arch (regcache); - size_t size = register_size (arch, HPPA_FP0_REGNUM); - - gdb_assert (size == 4 || size == 8); - gdb_assert (regnum >= HPPA_FP0_REGNUM); - offset = ssoff(ss_fpblock) + (regnum - HPPA_FP0_REGNUM) * size; - } - - gdb_assert (offset < sizeof (save_state_t)); - return offset; -} - -/* Just in case a future version of PA-RISC HP-UX won't have ptrace(2) - at all. */ -#ifndef PTRACE_TYPE_RET -#define PTRACE_TYPE_RET void -#endif - -static void -hppa_hpux_fetch_register (struct regcache *regcache, int regnum) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - CORE_ADDR addr; - size_t size; - PTRACE_TYPE_RET *buf; - pid_t pid; - int i; - - pid = ptid_get_pid (inferior_ptid); - - /* This isn't really an address, but ptrace thinks of it as one. */ - addr = hppa_hpux_save_state_offset (regcache, regnum); - size = register_size (gdbarch, regnum); - - gdb_assert (size == 4 || size == 8); - buf = alloca (size); - -#ifdef HAVE_TTRACE - { - lwpid_t lwp = ptid_get_lwp (inferior_ptid); - - if (ttrace (TT_LWP_RUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) - error (_("Couldn't read register %s (#%d): %s"), - gdbarch_register_name (gdbarch, regnum), - regnum, safe_strerror (errno)); - } -#else - { - int i; - - /* Read the register contents from the inferior a chuck at the time. */ - for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) - { - errno = 0; - buf[i] = ptrace (PT_RUREGS, pid, (PTRACE_TYPE_ARG3) addr, 0, 0); - if (errno != 0) - error (_("Couldn't read register %s (#%d): %s"), - gdbarch_register_name (gdbarch, regnum), - regnum, safe_strerror (errno)); - - addr += sizeof (PTRACE_TYPE_RET); - } - } -#endif - - /* Take care with the "flags" register. It's stored as an `int' in - `struct save_state', even for 64-bit code. */ - if (regnum == HPPA_FLAGS_REGNUM && size == 8) - { - ULONGEST flags; - flags = extract_unsigned_integer ((gdb_byte *)buf, 4, byte_order); - store_unsigned_integer ((gdb_byte *)buf, 8, byte_order, flags); - } - - regcache_raw_supply (regcache, regnum, buf); -} - -static void -hppa_hpux_fetch_inferior_registers (struct target_ops *ops, - struct regcache *regcache, int regnum) -{ - if (regnum == -1) - for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); - regnum++) - hppa_hpux_fetch_register (regcache, regnum); - else - hppa_hpux_fetch_register (regcache, regnum); -} - -/* Store register REGNUM into the inferior. */ - -static void -hppa_hpux_store_register (struct regcache *regcache, int regnum) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - CORE_ADDR addr; - size_t size; - PTRACE_TYPE_RET *buf; - pid_t pid; - - pid = ptid_get_pid (inferior_ptid); - - /* This isn't really an address, but ptrace thinks of it as one. */ - addr = hppa_hpux_save_state_offset (regcache, regnum); - size = register_size (gdbarch, regnum); - - gdb_assert (size == 4 || size == 8); - buf = alloca (size); - - regcache_raw_collect (regcache, regnum, buf); - - /* Take care with the "flags" register. It's stored as an `int' in - `struct save_state', even for 64-bit code. */ - if (regnum == HPPA_FLAGS_REGNUM && size == 8) - { - ULONGEST flags; - flags = extract_unsigned_integer ((gdb_byte *)buf, 8, byte_order); - store_unsigned_integer ((gdb_byte *)buf, 4, byte_order, flags); - size = 4; - } - -#ifdef HAVE_TTRACE - { - lwpid_t lwp = ptid_get_lwp (inferior_ptid); - - if (ttrace (TT_LWP_WUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) - error (_("Couldn't write register %s (#%d): %s"), - gdbarch_register_name (gdbarch, regnum), - regnum, safe_strerror (errno)); - } -#else - { - int i; - - /* Write the register contents into the inferior a chunk at the time. */ - for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) - { - errno = 0; - ptrace (PT_WUREGS, pid, (PTRACE_TYPE_ARG3) addr, buf[i], 0); - if (errno != 0) - error (_("Couldn't write register %s (#%d): %s"), - gdbarch_register_name (gdbarch, regnum), - regnum, safe_strerror (errno)); - - addr += sizeof (PTRACE_TYPE_RET); - } - } -#endif -} - -/* Store register REGNUM back into the inferior. If REGNUM is -1, do - this for all registers (including the floating point registers). */ - -static void -hppa_hpux_store_inferior_registers (struct target_ops *ops, - struct regcache *regcache, int regnum) -{ - if (regnum == -1) - for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); - regnum++) - hppa_hpux_store_register (regcache, regnum); - else - hppa_hpux_store_register (regcache, regnum); -} - -/* Set hpux_major_release variable to the value retrieved from a call to - uname function. */ - -static void -set_hpux_major_release (void) -{ - struct utsname x; - char *p; - - uname (&x); - p = strchr (x.release, '.'); - if (p) - hpux_major_release = atoi (p + 1); -} - - - -/* Prevent warning from -Wmissing-prototypes. */ -void _initialize_hppa_hpux_nat (void); - -void -_initialize_hppa_hpux_nat (void) -{ - struct target_ops *t; - - set_hpux_major_release (); - -#ifdef HAVE_TTRACE - t = inf_ttrace_target (); -#else - t = inf_ptrace_target (); -#endif - - t->to_fetch_registers = hppa_hpux_fetch_inferior_registers; - t->to_store_registers = hppa_hpux_store_inferior_registers; - - add_target (t); -} diff --git a/gdb/hppa-hpux-tdep.c b/gdb/hppa-hpux-tdep.c deleted file mode 100644 index 3c0f390..0000000 --- a/gdb/hppa-hpux-tdep.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* Target-dependent code for HP-UX on PA-RISC. - - Copyright (C) 2002-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "arch-utils.h" -#include "gdbcore.h" -#include "osabi.h" -#include "frame.h" -#include "frame-unwind.h" -#include "trad-frame.h" -#include "symtab.h" -#include "objfiles.h" -#include "inferior.h" -#include "infcall.h" -#include "observer.h" -#include "hppa-tdep.h" -#include "solib-som.h" -#include "solib-pa64.h" -#include "regset.h" -#include "regcache.h" - -#define IS_32BIT_TARGET(_gdbarch) \ - ((gdbarch_tdep (_gdbarch))->bytes_per_address == 4) - -/* Bit in the `ss_flag' member of `struct save_state' that indicates - that the 64-bit register values are live. From - <machine/save_state.h>. */ -#define HPPA_HPUX_SS_WIDEREGS 0x40 - -/* Offsets of various parts of `struct save_state'. From - <machine/save_state.h>. */ -#define HPPA_HPUX_SS_FLAGS_OFFSET 0 -#define HPPA_HPUX_SS_NARROW_OFFSET 4 -#define HPPA_HPUX_SS_FPBLOCK_OFFSET 256 -#define HPPA_HPUX_SS_WIDE_OFFSET 640 - -/* The size of `struct save_state. */ -#define HPPA_HPUX_SAVE_STATE_SIZE 1152 - -/* The size of `struct pa89_save_state', which corresponds to PA-RISC - 1.1, the lowest common denominator that we support. */ -#define HPPA_HPUX_PA89_SAVE_STATE_SIZE 512 - - -/* Forward declarations. */ -extern void _initialize_hppa_hpux_tdep (void); -extern initialize_file_ftype _initialize_hppa_hpux_tdep; - -/* Return one if PC is in the call path of a trampoline, else return zero. - - Note we return one for *any* call trampoline (long-call, arg-reloc), not - just shared library trampolines (import, export). */ - -static int -hppa32_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct bound_minimal_symbol minsym; - struct unwind_table_entry *u; - - /* First see if PC is in one of the two C-library trampolines. */ - if (pc == hppa_symbol_address("$$dyncall") - || pc == hppa_symbol_address("_sr4export")) - return 1; - - minsym = lookup_minimal_symbol_by_pc (pc); - if (minsym.minsym - && strcmp (MSYMBOL_LINKAGE_NAME (minsym.minsym), ".stub") == 0) - return 1; - - /* Get the unwind descriptor corresponding to PC, return zero - if no unwind was found. */ - u = find_unwind_entry (pc); - if (!u) - return 0; - - /* If this isn't a linker stub, then return now. */ - if (u->stub_unwind.stub_type == 0) - return 0; - - /* By definition a long-branch stub is a call stub. */ - if (u->stub_unwind.stub_type == LONG_BRANCH) - return 1; - - /* The call and return path execute the same instructions within - an IMPORT stub! So an IMPORT stub is both a call and return - trampoline. */ - if (u->stub_unwind.stub_type == IMPORT) - return 1; - - /* Parameter relocation stubs always have a call path and may have a - return path. */ - if (u->stub_unwind.stub_type == PARAMETER_RELOCATION - || u->stub_unwind.stub_type == EXPORT) - { - CORE_ADDR addr; - - /* Search forward from the current PC until we hit a branch - or the end of the stub. */ - for (addr = pc; addr <= u->region_end; addr += 4) - { - unsigned long insn; - - insn = read_memory_integer (addr, 4, byte_order); - - /* Does it look like a bl? If so then it's the call path, if - we find a bv or be first, then we're on the return path. */ - if ((insn & 0xfc00e000) == 0xe8000000) - return 1; - else if ((insn & 0xfc00e001) == 0xe800c000 - || (insn & 0xfc000000) == 0xe0000000) - return 0; - } - - /* Should never happen. */ - warning (_("Unable to find branch in parameter relocation stub.")); - return 0; - } - - /* Unknown stub type. For now, just return zero. */ - return 0; -} - -static int -hppa64_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - - /* PA64 has a completely different stub/trampoline scheme. Is it - better? Maybe. It's certainly harder to determine with any - certainty that we are in a stub because we can not refer to the - unwinders to help. - - The heuristic is simple. Try to lookup the current PC value in th - minimal symbol table. If that fails, then assume we are not in a - stub and return. - - Then see if the PC value falls within the section bounds for the - section containing the minimal symbol we found in the first - step. If it does, then assume we are not in a stub and return. - - Finally peek at the instructions to see if they look like a stub. */ - struct bound_minimal_symbol minsym; - asection *sec; - CORE_ADDR addr; - int insn; - - minsym = lookup_minimal_symbol_by_pc (pc); - if (! minsym.minsym) - return 0; - - sec = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym)->the_bfd_section; - - if (bfd_get_section_vma (sec->owner, sec) <= pc - && pc < (bfd_get_section_vma (sec->owner, sec) - + bfd_section_size (sec->owner, sec))) - return 0; - - /* We might be in a stub. Peek at the instructions. Stubs are 3 - instructions long. */ - insn = read_memory_integer (pc, 4, byte_order); - - /* Find out where we think we are within the stub. */ - if ((insn & 0xffffc00e) == 0x53610000) - addr = pc; - else if ((insn & 0xffffffff) == 0xe820d000) - addr = pc - 4; - else if ((insn & 0xffffc00e) == 0x537b0000) - addr = pc - 8; - else - return 0; - - /* Now verify each insn in the range looks like a stub instruction. */ - insn = read_memory_integer (addr, 4, byte_order); - if ((insn & 0xffffc00e) != 0x53610000) - return 0; - - /* Now verify each insn in the range looks like a stub instruction. */ - insn = read_memory_integer (addr + 4, 4, byte_order); - if ((insn & 0xffffffff) != 0xe820d000) - return 0; - - /* Now verify each insn in the range looks like a stub instruction. */ - insn = read_memory_integer (addr + 8, 4, byte_order); - if ((insn & 0xffffc00e) != 0x537b0000) - return 0; - - /* Looks like a stub. */ - return 1; -} - -/* Return one if PC is in the return path of a trampoline, else return zero. - - Note we return one for *any* call trampoline (long-call, arg-reloc), not - just shared library trampolines (import, export). */ - -static int -hppa_hpux_in_solib_return_trampoline (struct gdbarch *gdbarch, - CORE_ADDR pc, const char *name) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct unwind_table_entry *u; - - /* Get the unwind descriptor corresponding to PC, return zero - if no unwind was found. */ - u = find_unwind_entry (pc); - if (!u) - return 0; - - /* If this isn't a linker stub or it's just a long branch stub, then - return zero. */ - if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH) - return 0; - - /* The call and return path execute the same instructions within - an IMPORT stub! So an IMPORT stub is both a call and return - trampoline. */ - if (u->stub_unwind.stub_type == IMPORT) - return 1; - - /* Parameter relocation stubs always have a call path and may have a - return path. */ - if (u->stub_unwind.stub_type == PARAMETER_RELOCATION - || u->stub_unwind.stub_type == EXPORT) - { - CORE_ADDR addr; - - /* Search forward from the current PC until we hit a branch - or the end of the stub. */ - for (addr = pc; addr <= u->region_end; addr += 4) - { - unsigned long insn; - - insn = read_memory_integer (addr, 4, byte_order); - - /* Does it look like a bl? If so then it's the call path, if - we find a bv or be first, then we're on the return path. */ - if ((insn & 0xfc00e000) == 0xe8000000) - return 0; - else if ((insn & 0xfc00e001) == 0xe800c000 - || (insn & 0xfc000000) == 0xe0000000) - return 1; - } - - /* Should never happen. */ - warning (_("Unable to find branch in parameter relocation stub.")); - return 0; - } - - /* Unknown stub type. For now, just return zero. */ - return 0; - -} - -/* Figure out if PC is in a trampoline, and if so find out where - the trampoline will jump to. If not in a trampoline, return zero. - - Simple code examination probably is not a good idea since the code - sequences in trampolines can also appear in user code. - - We use unwinds and information from the minimal symbol table to - determine when we're in a trampoline. This won't work for ELF - (yet) since it doesn't create stub unwind entries. Whether or - not ELF will create stub unwinds or normal unwinds for linker - stubs is still being debated. - - This should handle simple calls through dyncall or sr4export, - long calls, argument relocation stubs, and dyncall/sr4export - calling an argument relocation stub. It even handles some stubs - used in dynamic executables. */ - -static CORE_ADDR -hppa_hpux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int word_size = gdbarch_ptr_bit (gdbarch) / 8; - long orig_pc = pc; - long prev_inst, curr_inst, loc; - struct bound_minimal_symbol msym; - struct unwind_table_entry *u; - - /* Addresses passed to dyncall may *NOT* be the actual address - of the function. So we may have to do something special. */ - if (pc == hppa_symbol_address("$$dyncall")) - { - pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22); - - /* If bit 30 (counting from the left) is on, then pc is the address of - the PLT entry for this function, not the address of the function - itself. Bit 31 has meaning too, but only for MPE. */ - if (pc & 0x2) - pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, word_size, - byte_order); - } - if (pc == hppa_symbol_address("$$dyncall_external")) - { - pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22); - pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, word_size, byte_order); - } - else if (pc == hppa_symbol_address("_sr4export")) - pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22); - - /* Get the unwind descriptor corresponding to PC, return zero - if no unwind was found. */ - u = find_unwind_entry (pc); - if (!u) - return 0; - - /* If this isn't a linker stub, then return now. */ - /* elz: attention here! (FIXME) because of a compiler/linker - error, some stubs which should have a non zero stub_unwind.stub_type - have unfortunately a value of zero. So this function would return here - as if we were not in a trampoline. To fix this, we go look at the partial - symbol information, which reports this guy as a stub. - (FIXME): Unfortunately, we are not that lucky: it turns out that the - partial symbol information is also wrong sometimes. This is because - when it is entered (somread.c::som_symtab_read()) it can happen that - if the type of the symbol (from the som) is Entry, and the symbol is - in a shared library, then it can also be a trampoline. This would be OK, - except that I believe the way they decide if we are ina shared library - does not work. SOOOO..., even if we have a regular function w/o - trampolines its minimal symbol can be assigned type mst_solib_trampoline. - Also, if we find that the symbol is a real stub, then we fix the unwind - descriptor, and define the stub type to be EXPORT. - Hopefully this is correct most of the times. */ - if (u->stub_unwind.stub_type == 0) - { - -/* elz: NOTE (FIXME!) once the problem with the unwind information is fixed - we can delete all the code which appears between the lines. */ -/*--------------------------------------------------------------------------*/ - msym = lookup_minimal_symbol_by_pc (pc); - - if (msym.minsym == NULL - || MSYMBOL_TYPE (msym.minsym) != mst_solib_trampoline) - return orig_pc == pc ? 0 : pc & ~0x3; - - else if (msym.minsym != NULL - && MSYMBOL_TYPE (msym.minsym) == mst_solib_trampoline) - { - struct objfile *objfile; - struct minimal_symbol *msymbol; - int function_found = 0; - - /* Go look if there is another minimal symbol with the same name as - this one, but with type mst_text. This would happen if the msym - is an actual trampoline, in which case there would be another - symbol with the same name corresponding to the real function. */ - - ALL_MSYMBOLS (objfile, msymbol) - { - if (MSYMBOL_TYPE (msymbol) == mst_text - && strcmp (MSYMBOL_LINKAGE_NAME (msymbol), - MSYMBOL_LINKAGE_NAME (msym.minsym)) == 0) - { - function_found = 1; - break; - } - } - - if (function_found) - /* The type of msym is correct (mst_solib_trampoline), but - the unwind info is wrong, so set it to the correct value. */ - u->stub_unwind.stub_type = EXPORT; - else - /* The stub type info in the unwind is correct (this is not a - trampoline), but the msym type information is wrong, it - should be mst_text. So we need to fix the msym, and also - get out of this function. */ - { - MSYMBOL_TYPE (msym.minsym) = mst_text; - return orig_pc == pc ? 0 : pc & ~0x3; - } - } - -/*--------------------------------------------------------------------------*/ - } - - /* It's a stub. Search for a branch and figure out where it goes. - Note we have to handle multi insn branch sequences like ldil;ble. - Most (all?) other branches can be determined by examining the contents - of certain registers and the stack. */ - - loc = pc; - curr_inst = 0; - prev_inst = 0; - while (1) - { - /* Make sure we haven't walked outside the range of this stub. */ - if (u != find_unwind_entry (loc)) - { - warning (_("Unable to find branch in linker stub")); - return orig_pc == pc ? 0 : pc & ~0x3; - } - - prev_inst = curr_inst; - curr_inst = read_memory_integer (loc, 4, byte_order); - - /* Does it look like a branch external using %r1? Then it's the - branch from the stub to the actual function. */ - if ((curr_inst & 0xffe0e000) == 0xe0202000) - { - /* Yup. See if the previous instruction loaded - a value into %r1. If so compute and return the jump address. */ - if ((prev_inst & 0xffe00000) == 0x20200000) - return (hppa_extract_21 (prev_inst) - + hppa_extract_17 (curr_inst)) & ~0x3; - else - { - warning (_("Unable to find ldil X,%%r1 " - "before ble Y(%%sr4,%%r1).")); - return orig_pc == pc ? 0 : pc & ~0x3; - } - } - - /* Does it look like a be 0(sr0,%r21)? OR - Does it look like a be, n 0(sr0,%r21)? OR - Does it look like a bve (r21)? (this is on PA2.0) - Does it look like a bve, n(r21)? (this is also on PA2.0) - That's the branch from an - import stub to an export stub. - - It is impossible to determine the target of the branch via - simple examination of instructions and/or data (consider - that the address in the plabel may be the address of the - bind-on-reference routine in the dynamic loader). - - So we have try an alternative approach. - - Get the name of the symbol at our current location; it should - be a stub symbol with the same name as the symbol in the - shared library. - - Then lookup a minimal symbol with the same name; we should - get the minimal symbol for the target routine in the shared - library as those take precedence of import/export stubs. */ - if ((curr_inst == 0xe2a00000) || - (curr_inst == 0xe2a00002) || - (curr_inst == 0xeaa0d000) || - (curr_inst == 0xeaa0d002)) - { - struct bound_minimal_symbol stubsym; - struct bound_minimal_symbol libsym; - - stubsym = lookup_minimal_symbol_by_pc (loc); - if (stubsym.minsym == NULL) - { - warning (_("Unable to find symbol for 0x%lx"), loc); - return orig_pc == pc ? 0 : pc & ~0x3; - } - - libsym = lookup_minimal_symbol (MSYMBOL_LINKAGE_NAME (stubsym.minsym), - NULL, NULL); - if (libsym.minsym == NULL) - { - warning (_("Unable to find library symbol for %s."), - MSYMBOL_PRINT_NAME (stubsym.minsym)); - return orig_pc == pc ? 0 : pc & ~0x3; - } - - return MSYMBOL_VALUE (libsym.minsym); - } - - /* Does it look like bl X,%rp or bl X,%r0? Another way to do a - branch from the stub to the actual function. */ - /*elz */ - else if ((curr_inst & 0xffe0e000) == 0xe8400000 - || (curr_inst & 0xffe0e000) == 0xe8000000 - || (curr_inst & 0xffe0e000) == 0xe800A000) - return (loc + hppa_extract_17 (curr_inst) + 8) & ~0x3; - - /* Does it look like bv (rp)? Note this depends on the - current stack pointer being the same as the stack - pointer in the stub itself! This is a branch on from the - stub back to the original caller. */ - /*else if ((curr_inst & 0xffe0e000) == 0xe840c000) */ - else if ((curr_inst & 0xffe0f000) == 0xe840c000) - { - /* Yup. See if the previous instruction loaded - rp from sp - 8. */ - if (prev_inst == 0x4bc23ff1) - { - CORE_ADDR sp; - sp = get_frame_register_unsigned (frame, HPPA_SP_REGNUM); - return read_memory_integer (sp - 8, 4, byte_order) & ~0x3; - } - else - { - warning (_("Unable to find restore of %%rp before bv (%%rp).")); - return orig_pc == pc ? 0 : pc & ~0x3; - } - } - - /* elz: added this case to capture the new instruction - at the end of the return part of an export stub used by - the PA2.0: BVE, n (rp) */ - else if ((curr_inst & 0xffe0f000) == 0xe840d000) - { - return (read_memory_integer - (get_frame_register_unsigned (frame, HPPA_SP_REGNUM) - 24, - word_size, byte_order)) & ~0x3; - } - - /* What about be,n 0(sr0,%rp)? It's just another way we return to - the original caller from the stub. Used in dynamic executables. */ - else if (curr_inst == 0xe0400002) - { - /* The value we jump to is sitting in sp - 24. But that's - loaded several instructions before the be instruction. - I guess we could check for the previous instruction being - mtsp %r1,%sr0 if we want to do sanity checking. */ - return (read_memory_integer - (get_frame_register_unsigned (frame, HPPA_SP_REGNUM) - 24, - word_size, byte_order)) & ~0x3; - } - - /* Haven't found the branch yet, but we're still in the stub. - Keep looking. */ - loc += 4; - } -} - -static void -hppa_skip_permanent_breakpoint (struct regcache *regcache) -{ - /* To step over a breakpoint instruction on the PA takes some - fiddling with the instruction address queue. - - When we stop at a breakpoint, the IA queue front (the instruction - we're executing now) points at the breakpoint instruction, and - the IA queue back (the next instruction to execute) points to - whatever instruction we would execute after the breakpoint, if it - were an ordinary instruction. This is the case even if the - breakpoint is in the delay slot of a branch instruction. - - Clearly, to step past the breakpoint, we need to set the queue - front to the back. But what do we put in the back? What - instruction comes after that one? Because of the branch delay - slot, the next insn is always at the back + 4. */ - - ULONGEST pcoq_tail, pcsq_tail; - regcache_cooked_read_unsigned (regcache, HPPA_PCOQ_TAIL_REGNUM, &pcoq_tail); - regcache_cooked_read_unsigned (regcache, HPPA_PCSQ_TAIL_REGNUM, &pcsq_tail); - - regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, pcoq_tail); - regcache_cooked_write_unsigned (regcache, HPPA_PCSQ_HEAD_REGNUM, pcsq_tail); - - regcache_cooked_write_unsigned (regcache, - HPPA_PCOQ_TAIL_REGNUM, pcoq_tail + 4); - /* We can leave the tail's space the same, since there's no jump. */ -} - - -/* Signal frames. */ -struct hppa_hpux_sigtramp_unwind_cache -{ - CORE_ADDR base; - struct trad_frame_saved_reg *saved_regs; -}; - -static int hppa_hpux_tramp_reg[] = { - HPPA_SAR_REGNUM, - HPPA_PCOQ_HEAD_REGNUM, - HPPA_PCSQ_HEAD_REGNUM, - HPPA_PCOQ_TAIL_REGNUM, - HPPA_PCSQ_TAIL_REGNUM, - HPPA_EIEM_REGNUM, - HPPA_IIR_REGNUM, - HPPA_ISR_REGNUM, - HPPA_IOR_REGNUM, - HPPA_IPSW_REGNUM, - -1, - HPPA_SR4_REGNUM, - HPPA_SR4_REGNUM + 1, - HPPA_SR4_REGNUM + 2, - HPPA_SR4_REGNUM + 3, - HPPA_SR4_REGNUM + 4, - HPPA_SR4_REGNUM + 5, - HPPA_SR4_REGNUM + 6, - HPPA_SR4_REGNUM + 7, - HPPA_RCR_REGNUM, - HPPA_PID0_REGNUM, - HPPA_PID1_REGNUM, - HPPA_CCR_REGNUM, - HPPA_PID2_REGNUM, - HPPA_PID3_REGNUM, - HPPA_TR0_REGNUM, - HPPA_TR0_REGNUM + 1, - HPPA_TR0_REGNUM + 2, - HPPA_CR27_REGNUM -}; - -static struct hppa_hpux_sigtramp_unwind_cache * -hppa_hpux_sigtramp_frame_unwind_cache (struct frame_info *this_frame, - void **this_cache) - -{ - struct gdbarch *gdbarch = get_frame_arch (this_frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct hppa_hpux_sigtramp_unwind_cache *info; - unsigned int flag; - CORE_ADDR sp, scptr, off; - int i, incr, szoff; - - if (*this_cache) - return *this_cache; - - info = FRAME_OBSTACK_ZALLOC (struct hppa_hpux_sigtramp_unwind_cache); - *this_cache = info; - info->saved_regs = trad_frame_alloc_saved_regs (this_frame); - - sp = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM); - - if (IS_32BIT_TARGET (gdbarch)) - scptr = sp - 1352; - else - scptr = sp - 1520; - - off = scptr; - - /* See /usr/include/machine/save_state.h for the structure of the - save_state_t structure. */ - - flag = read_memory_unsigned_integer (scptr + HPPA_HPUX_SS_FLAGS_OFFSET, - 4, byte_order); - - if (!(flag & HPPA_HPUX_SS_WIDEREGS)) - { - /* Narrow registers. */ - off = scptr + HPPA_HPUX_SS_NARROW_OFFSET; - incr = 4; - szoff = 0; - } - else - { - /* Wide registers. */ - off = scptr + HPPA_HPUX_SS_WIDE_OFFSET + 8; - incr = 8; - szoff = (tdep->bytes_per_address == 4 ? 4 : 0); - } - - for (i = 1; i < 32; i++) - { - info->saved_regs[HPPA_R0_REGNUM + i].addr = off + szoff; - off += incr; - } - - for (i = 0; i < ARRAY_SIZE (hppa_hpux_tramp_reg); i++) - { - if (hppa_hpux_tramp_reg[i] > 0) - info->saved_regs[hppa_hpux_tramp_reg[i]].addr = off + szoff; - - off += incr; - } - - /* TODO: fp regs */ - - info->base = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM); - - return info; -} - -static void -hppa_hpux_sigtramp_frame_this_id (struct frame_info *this_frame, - void **this_prologue_cache, - struct frame_id *this_id) -{ - struct hppa_hpux_sigtramp_unwind_cache *info - = hppa_hpux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache); - - *this_id = frame_id_build (info->base, get_frame_pc (this_frame)); -} - -static struct value * -hppa_hpux_sigtramp_frame_prev_register (struct frame_info *this_frame, - void **this_prologue_cache, - int regnum) -{ - struct hppa_hpux_sigtramp_unwind_cache *info - = hppa_hpux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache); - - return hppa_frame_prev_register_helper (this_frame, - info->saved_regs, regnum); -} - -static int -hppa_hpux_sigtramp_unwind_sniffer (const struct frame_unwind *self, - struct frame_info *this_frame, - void **this_cache) -{ - struct gdbarch *gdbarch = get_frame_arch (this_frame); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct unwind_table_entry *u; - CORE_ADDR pc = get_frame_pc (this_frame); - - u = find_unwind_entry (pc); - - /* If this is an export stub, try to get the unwind descriptor for - the actual function itself. */ - if (u && u->stub_unwind.stub_type == EXPORT) - { - gdb_byte buf[HPPA_INSN_SIZE]; - unsigned long insn; - - if (!safe_frame_unwind_memory (this_frame, u->region_start, - buf, sizeof buf)) - return 0; - - insn = extract_unsigned_integer (buf, sizeof buf, byte_order); - if ((insn & 0xffe0e000) == 0xe8400000) - u = find_unwind_entry(u->region_start + hppa_extract_17 (insn) + 8); - } - - if (u && u->HP_UX_interrupt_marker) - return 1; - - return 0; -} - -static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = { - SIGTRAMP_FRAME, - default_frame_unwind_stop_reason, - hppa_hpux_sigtramp_frame_this_id, - hppa_hpux_sigtramp_frame_prev_register, - NULL, - hppa_hpux_sigtramp_unwind_sniffer -}; - -static CORE_ADDR -hppa32_hpux_find_global_pointer (struct gdbarch *gdbarch, - struct value *function) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - CORE_ADDR faddr; - - faddr = value_as_address (function); - - /* Is this a plabel? If so, dereference it to get the gp value. */ - if (faddr & 2) - { - int status; - gdb_byte buf[4]; - - faddr &= ~3; - - status = target_read_memory (faddr + 4, buf, sizeof (buf)); - if (status == 0) - return extract_unsigned_integer (buf, sizeof (buf), byte_order); - } - - return gdbarch_tdep (gdbarch)->solib_get_got_by_pc (faddr); -} - -static CORE_ADDR -hppa64_hpux_find_global_pointer (struct gdbarch *gdbarch, - struct value *function) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - CORE_ADDR faddr; - gdb_byte buf[32]; - - faddr = value_as_address (function); - - if (pc_in_section (faddr, ".opd")) - { - target_read_memory (faddr, buf, sizeof (buf)); - return extract_unsigned_integer (&buf[24], 8, byte_order); - } - else - { - return gdbarch_tdep (gdbarch)->solib_get_got_by_pc (faddr); - } -} - -static unsigned int ldsid_pattern[] = { - 0x000010a0, /* ldsid (rX),rY */ - 0x00001820, /* mtsp rY,sr0 */ - 0xe0000000 /* be,n (sr0,rX) */ -}; - -static CORE_ADDR -hppa_hpux_search_pattern (struct gdbarch *gdbarch, - CORE_ADDR start, CORE_ADDR end, - unsigned int *patterns, int count) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int num_insns = (end - start + HPPA_INSN_SIZE) / HPPA_INSN_SIZE; - unsigned int *insns; - gdb_byte *buf; - int offset, i; - - buf = alloca (num_insns * HPPA_INSN_SIZE); - insns = alloca (num_insns * sizeof (unsigned int)); - - read_memory (start, buf, num_insns * HPPA_INSN_SIZE); - for (i = 0; i < num_insns; i++, buf += HPPA_INSN_SIZE) - insns[i] = extract_unsigned_integer (buf, HPPA_INSN_SIZE, byte_order); - - for (offset = 0; offset <= num_insns - count; offset++) - { - for (i = 0; i < count; i++) - { - if ((insns[offset + i] & patterns[i]) != patterns[i]) - break; - } - if (i == count) - break; - } - - if (offset <= num_insns - count) - return start + offset * HPPA_INSN_SIZE; - else - return 0; -} - -static CORE_ADDR -hppa32_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc, - int *argreg) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct objfile *obj; - struct obj_section *sec; - struct hppa_objfile_private *priv; - struct frame_info *frame; - struct unwind_table_entry *u; - CORE_ADDR addr, rp; - gdb_byte buf[4]; - unsigned int insn; - - sec = find_pc_section (pc); - obj = sec->objfile; - priv = objfile_data (obj, hppa_objfile_priv_data); - - if (!priv) - priv = hppa_init_objfile_priv_data (obj); - if (!priv) - error (_("Internal error creating objfile private data.")); - - /* Use the cached value if we have one. */ - if (priv->dummy_call_sequence_addr != 0) - { - *argreg = priv->dummy_call_sequence_reg; - return priv->dummy_call_sequence_addr; - } - - /* First try a heuristic; if we are in a shared library call, our return - pointer is likely to point at an export stub. */ - frame = get_current_frame (); - rp = frame_unwind_register_unsigned (frame, 2); - u = find_unwind_entry (rp); - if (u && u->stub_unwind.stub_type == EXPORT) - { - addr = hppa_hpux_search_pattern (gdbarch, - u->region_start, u->region_end, - ldsid_pattern, - ARRAY_SIZE (ldsid_pattern)); - if (addr) - goto found_pattern; - } - - /* Next thing to try is to look for an export stub. */ - if (priv->unwind_info) - { - int i; - - for (i = 0; i < priv->unwind_info->last; i++) - { - struct unwind_table_entry *u; - u = &priv->unwind_info->table[i]; - if (u->stub_unwind.stub_type == EXPORT) - { - addr = hppa_hpux_search_pattern (gdbarch, - u->region_start, u->region_end, - ldsid_pattern, - ARRAY_SIZE (ldsid_pattern)); - if (addr) - { - goto found_pattern; - } - } - } - } - - /* Finally, if this is the main executable, try to locate a sequence - from noshlibs */ - addr = hppa_symbol_address ("noshlibs"); - sec = find_pc_section (addr); - - if (sec && sec->objfile == obj) - { - CORE_ADDR start, end; - - find_pc_partial_function (addr, NULL, &start, &end); - if (start != 0 && end != 0) - { - addr = hppa_hpux_search_pattern (gdbarch, start, end, ldsid_pattern, - ARRAY_SIZE (ldsid_pattern)); - if (addr) - goto found_pattern; - } - } - - /* Can't find a suitable sequence. */ - return 0; - -found_pattern: - target_read_memory (addr, buf, sizeof (buf)); - insn = extract_unsigned_integer (buf, sizeof (buf), byte_order); - priv->dummy_call_sequence_addr = addr; - priv->dummy_call_sequence_reg = (insn >> 21) & 0x1f; - - *argreg = priv->dummy_call_sequence_reg; - return priv->dummy_call_sequence_addr; -} - -static CORE_ADDR -hppa64_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc, - int *argreg) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct objfile *obj; - struct obj_section *sec; - struct hppa_objfile_private *priv; - CORE_ADDR addr; - struct minimal_symbol *msym; - - sec = find_pc_section (pc); - obj = sec->objfile; - priv = objfile_data (obj, hppa_objfile_priv_data); - - if (!priv) - priv = hppa_init_objfile_priv_data (obj); - if (!priv) - error (_("Internal error creating objfile private data.")); - - /* Use the cached value if we have one. */ - if (priv->dummy_call_sequence_addr != 0) - { - *argreg = priv->dummy_call_sequence_reg; - return priv->dummy_call_sequence_addr; - } - - /* FIXME: Without stub unwind information, locating a suitable sequence is - fairly difficult. For now, we implement a very naive and inefficient - scheme; try to read in blocks of code, and look for a "bve,n (rp)" - instruction. These are likely to occur at the end of functions, so - we only look at the last two instructions of each function. */ - ALL_OBJFILE_MSYMBOLS (obj, msym) - { - CORE_ADDR begin, end; - const char *name; - gdb_byte buf[2 * HPPA_INSN_SIZE]; - int offset; - - find_pc_partial_function (MSYMBOL_VALUE_ADDRESS (obj, msym), &name, - &begin, &end); - - if (name == NULL || begin == 0 || end == 0) - continue; - - if (target_read_memory (end - sizeof (buf), buf, sizeof (buf)) == 0) - { - for (offset = 0; offset < sizeof (buf); offset++) - { - unsigned int insn; - - insn = extract_unsigned_integer (buf + offset, - HPPA_INSN_SIZE, byte_order); - if (insn == 0xe840d002) /* bve,n (rp) */ - { - addr = (end - sizeof (buf)) + offset; - goto found_pattern; - } - } - } - } - - /* Can't find a suitable sequence. */ - return 0; - -found_pattern: - priv->dummy_call_sequence_addr = addr; - /* Right now we only look for a "bve,l (rp)" sequence, so the register is - always HPPA_RP_REGNUM. */ - priv->dummy_call_sequence_reg = HPPA_RP_REGNUM; - - *argreg = priv->dummy_call_sequence_reg; - return priv->dummy_call_sequence_addr; -} - -static CORE_ADDR -hppa_hpux_find_import_stub_for_addr (CORE_ADDR funcaddr) -{ - struct objfile *objfile; - struct bound_minimal_symbol funsym; - struct bound_minimal_symbol stubsym; - CORE_ADDR stubaddr; - - funsym = lookup_minimal_symbol_by_pc (funcaddr); - stubaddr = 0; - - ALL_OBJFILES (objfile) - { - stubsym = lookup_minimal_symbol_solib_trampoline - (MSYMBOL_LINKAGE_NAME (funsym.minsym), objfile); - - if (stubsym.minsym) - { - struct unwind_table_entry *u; - - u = find_unwind_entry (MSYMBOL_VALUE (stubsym.minsym)); - if (u == NULL - || (u->stub_unwind.stub_type != IMPORT - && u->stub_unwind.stub_type != IMPORT_SHLIB)) - continue; - - stubaddr = MSYMBOL_VALUE (stubsym.minsym); - - /* If we found an IMPORT stub, then we can stop searching; - if we found an IMPORT_SHLIB, we want to continue the search - in the hopes that we will find an IMPORT stub. */ - if (u->stub_unwind.stub_type == IMPORT) - break; - } - } - - return stubaddr; -} - -static int -hppa_hpux_sr_for_addr (struct gdbarch *gdbarch, CORE_ADDR addr) -{ - int sr; - /* The space register to use is encoded in the top 2 bits of the address. */ - sr = addr >> (gdbarch_tdep (gdbarch)->bytes_per_address * 8 - 2); - return sr + 4; -} - -static CORE_ADDR -hppa_hpux_find_dummy_bpaddr (CORE_ADDR addr) -{ - /* In order for us to restore the space register to its starting state, - we need the dummy trampoline to return to an instruction address in - the same space as where we started the call. We used to place the - breakpoint near the current pc, however, this breaks nested dummy calls - as the nested call will hit the breakpoint address and terminate - prematurely. Instead, we try to look for an address in the same space to - put the breakpoint. - - This is similar in spirit to putting the breakpoint at the "entry point" - of an executable. */ - - struct obj_section *sec; - struct unwind_table_entry *u; - struct minimal_symbol *msym; - CORE_ADDR func; - - sec = find_pc_section (addr); - if (sec) - { - /* First try the lowest address in the section; we can use it as long - as it is "regular" code (i.e. not a stub). */ - u = find_unwind_entry (obj_section_addr (sec)); - if (!u || u->stub_unwind.stub_type == 0) - return obj_section_addr (sec); - - /* Otherwise, we need to find a symbol for a regular function. We - do this by walking the list of msymbols in the objfile. The symbol - we find should not be the same as the function that was passed in. */ - - /* FIXME: this is broken, because we can find a function that will be - called by the dummy call target function, which will still not - work. */ - - find_pc_partial_function (addr, NULL, &func, NULL); - ALL_OBJFILE_MSYMBOLS (sec->objfile, msym) - { - u = find_unwind_entry (MSYMBOL_VALUE_ADDRESS (sec->objfile, msym)); - if (func != MSYMBOL_VALUE_ADDRESS (sec->objfile, msym) - && (!u || u->stub_unwind.stub_type == 0)) - return MSYMBOL_VALUE_ADDRESS (sec->objfile, msym); - } - } - - warning (_("Cannot find suitable address to place dummy breakpoint; nested " - "calls may fail.")); - return addr - 4; -} - -static CORE_ADDR -hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, - CORE_ADDR funcaddr, - struct value **args, int nargs, - struct type *value_type, - CORE_ADDR *real_pc, CORE_ADDR *bp_addr, - struct regcache *regcache) -{ - CORE_ADDR pc, stubaddr; - int argreg = 0; - - pc = regcache_read_pc (regcache); - - /* Note: we don't want to pass a function descriptor here; push_dummy_call - fills in the PIC register for us. */ - funcaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funcaddr, NULL); - - /* The simple case is where we call a function in the same space that we are - currently in; in that case we don't really need to do anything. */ - if (hppa_hpux_sr_for_addr (gdbarch, pc) - == hppa_hpux_sr_for_addr (gdbarch, funcaddr)) - { - /* Intraspace call. */ - *bp_addr = hppa_hpux_find_dummy_bpaddr (pc); - *real_pc = funcaddr; - regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, *bp_addr); - - return sp; - } - - /* In order to make an interspace call, we need to go through a stub. - gcc supplies an appropriate stub called "__gcc_plt_call", however, if - an application is compiled with HP compilers then this stub is not - available. We used to fallback to "__d_plt_call", however that stub - is not entirely useful for us because it doesn't do an interspace - return back to the caller. Also, on hppa64-hpux, there is no - __gcc_plt_call available. In order to keep the code uniform, we - instead don't use either of these stubs, but instead write our own - onto the stack. - - A problem arises since the stack is located in a different space than - code, so in order to branch to a stack stub, we will need to do an - interspace branch. Previous versions of gdb did this by modifying code - at the current pc and doing single-stepping to set the pcsq. Since this - is highly undesirable, we use a different scheme: - - All we really need to do the branch to the stub is a short instruction - sequence like this: - - PA1.1: - ldsid (rX),r1 - mtsp r1,sr0 - be,n (sr0,rX) - - PA2.0: - bve,n (sr0,rX) - - Instead of writing these sequences ourselves, we can find it in - the instruction stream that belongs to the current space. While this - seems difficult at first, we are actually guaranteed to find the sequences - in several places: - - For 32-bit code: - - in export stubs for shared libraries - - in the "noshlibs" routine in the main module - - For 64-bit code: - - at the end of each "regular" function - - We cache the address of these sequences in the objfile's private data - since these operations can potentially be quite expensive. - - So, what we do is: - - write a stack trampoline - - look for a suitable instruction sequence in the current space - - point the sequence at the trampoline - - set the return address of the trampoline to the current space - (see hppa_hpux_find_dummy_call_bpaddr) - - set the continuing address of the "dummy code" as the sequence. */ - - if (IS_32BIT_TARGET (gdbarch)) - { -#define INSN(I1, I2, I3, I4) 0x ## I1, 0x ## I2, 0x ## I3, 0x ## I4 - static const gdb_byte hppa32_tramp[] = { - INSN(0f,df,12,91), /* stw r31,-8(,sp) */ - INSN(02,c0,10,a1), /* ldsid (,r22),r1 */ - INSN(00,01,18,20), /* mtsp r1,sr0 */ - INSN(e6,c0,00,00), /* be,l 0(sr0,r22),%sr0,%r31 */ - INSN(08,1f,02,42), /* copy r31,rp */ - INSN(0f,d1,10,82), /* ldw -8(,sp),rp */ - INSN(00,40,10,a1), /* ldsid (,rp),r1 */ - INSN(00,01,18,20), /* mtsp r1,sr0 */ - INSN(e0,40,00,00), /* be 0(sr0,rp) */ - INSN(08,00,02,40) /* nop */ - }; - - /* for hppa32, we must call the function through a stub so that on - return it can return to the space of our trampoline. */ - stubaddr = hppa_hpux_find_import_stub_for_addr (funcaddr); - if (stubaddr == 0) - error (_("Cannot call external function not referenced by application " - "(no import stub).\n")); - regcache_cooked_write_unsigned (regcache, 22, stubaddr); - - write_memory (sp, hppa32_tramp, sizeof (hppa32_tramp)); - - *bp_addr = hppa_hpux_find_dummy_bpaddr (pc); - regcache_cooked_write_unsigned (regcache, 31, *bp_addr); - - *real_pc = hppa32_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg); - if (*real_pc == 0) - error (_("Cannot make interspace call from here.")); - - regcache_cooked_write_unsigned (regcache, argreg, sp); - - sp += sizeof (hppa32_tramp); - } - else - { - static const gdb_byte hppa64_tramp[] = { - INSN(ea,c0,f0,00), /* bve,l (r22),%r2 */ - INSN(0f,df,12,d1), /* std r31,-8(,sp) */ - INSN(0f,d1,10,c2), /* ldd -8(,sp),rp */ - INSN(e8,40,d0,02), /* bve,n (rp) */ - INSN(08,00,02,40) /* nop */ - }; -#undef INSN - - /* for hppa64, we don't need to call through a stub; all functions - return via a bve. */ - regcache_cooked_write_unsigned (regcache, 22, funcaddr); - write_memory (sp, hppa64_tramp, sizeof (hppa64_tramp)); - - *bp_addr = pc - 4; - regcache_cooked_write_unsigned (regcache, 31, *bp_addr); - - *real_pc = hppa64_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg); - if (*real_pc == 0) - error (_("Cannot make interspace call from here.")); - - regcache_cooked_write_unsigned (regcache, argreg, sp); - - sp += sizeof (hppa64_tramp); - } - - sp = gdbarch_frame_align (gdbarch, sp); - - return sp; -} - - - -static void -hppa_hpux_supply_ss_narrow (struct regcache *regcache, - int regnum, const gdb_byte *save_state) -{ - const gdb_byte *ss_narrow = save_state + HPPA_HPUX_SS_NARROW_OFFSET; - int i, offset = 0; - - for (i = HPPA_R1_REGNUM; i < HPPA_FP0_REGNUM; i++) - { - if (regnum == i || regnum == -1) - regcache_raw_supply (regcache, i, ss_narrow + offset); - - offset += 4; - } -} - -static void -hppa_hpux_supply_ss_fpblock (struct regcache *regcache, - int regnum, const gdb_byte *save_state) -{ - const gdb_byte *ss_fpblock = save_state + HPPA_HPUX_SS_FPBLOCK_OFFSET; - int i, offset = 0; - - /* FIXME: We view the floating-point state as 64 single-precision - registers for 32-bit code, and 32 double-precision register for - 64-bit code. This distinction is artificial and should be - eliminated. If that ever happens, we should remove the if-clause - below. */ - - if (register_size (get_regcache_arch (regcache), HPPA_FP0_REGNUM) == 4) - { - for (i = HPPA_FP0_REGNUM; i < HPPA_FP0_REGNUM + 64; i++) - { - if (regnum == i || regnum == -1) - regcache_raw_supply (regcache, i, ss_fpblock + offset); - - offset += 4; - } - } - else - { - for (i = HPPA_FP0_REGNUM; i < HPPA_FP0_REGNUM + 32; i++) - { - if (regnum == i || regnum == -1) - regcache_raw_supply (regcache, i, ss_fpblock + offset); - - offset += 8; - } - } -} - -static void -hppa_hpux_supply_ss_wide (struct regcache *regcache, - int regnum, const gdb_byte *save_state) -{ - const gdb_byte *ss_wide = save_state + HPPA_HPUX_SS_WIDE_OFFSET; - int i, offset = 8; - - if (register_size (get_regcache_arch (regcache), HPPA_R1_REGNUM) == 4) - offset += 4; - - for (i = HPPA_R1_REGNUM; i < HPPA_FP0_REGNUM; i++) - { - if (regnum == i || regnum == -1) - regcache_raw_supply (regcache, i, ss_wide + offset); - - offset += 8; - } -} - -static void -hppa_hpux_supply_save_state (const struct regset *regset, - struct regcache *regcache, - int regnum, const void *regs, size_t len) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - const gdb_byte *proc_info = regs; - const gdb_byte *save_state = proc_info + 8; - ULONGEST flags; - - flags = extract_unsigned_integer (save_state + HPPA_HPUX_SS_FLAGS_OFFSET, - 4, byte_order); - if (regnum == -1 || regnum == HPPA_FLAGS_REGNUM) - { - size_t size = register_size (gdbarch, HPPA_FLAGS_REGNUM); - gdb_byte buf[8]; - - store_unsigned_integer (buf, size, byte_order, flags); - regcache_raw_supply (regcache, HPPA_FLAGS_REGNUM, buf); - } - - /* If the SS_WIDEREGS flag is set, we really do need the full - `struct save_state'. */ - if (flags & HPPA_HPUX_SS_WIDEREGS && len < HPPA_HPUX_SAVE_STATE_SIZE) - error (_("Register set contents too small")); - - if (flags & HPPA_HPUX_SS_WIDEREGS) - hppa_hpux_supply_ss_wide (regcache, regnum, save_state); - else - hppa_hpux_supply_ss_narrow (regcache, regnum, save_state); - - hppa_hpux_supply_ss_fpblock (regcache, regnum, save_state); -} - -/* HP-UX register set. */ - -static const struct regset hppa_hpux_regset = -{ - NULL, - hppa_hpux_supply_save_state, - NULL, - REGSET_VARIABLE_SIZE -}; - -static void -hppa_hpux_iterate_over_regset_sections (struct gdbarch *gdbarch, - iterate_over_regset_sections_cb *cb, - void *cb_data, - const struct regcache *regcache) -{ - cb (".reg", HPPA_HPUX_PA89_SAVE_STATE_SIZE + 8, &hppa_hpux_regset, - NULL, cb_data); -} - - -/* Bit in the `ss_flag' member of `struct save_state' that indicates - the state was saved from a system call. From - <machine/save_state.h>. */ -#define HPPA_HPUX_SS_INSYSCALL 0x02 - -static CORE_ADDR -hppa_hpux_read_pc (struct regcache *regcache) -{ - ULONGEST flags; - - /* If we're currently in a system call return the contents of %r31. */ - regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags); - if (flags & HPPA_HPUX_SS_INSYSCALL) - { - ULONGEST pc; - regcache_cooked_read_unsigned (regcache, HPPA_R31_REGNUM, &pc); - return pc & ~0x3; - } - - return hppa_read_pc (regcache); -} - -static void -hppa_hpux_write_pc (struct regcache *regcache, CORE_ADDR pc) -{ - ULONGEST flags; - - /* If we're currently in a system call also write PC into %r31. */ - regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags); - if (flags & HPPA_HPUX_SS_INSYSCALL) - regcache_cooked_write_unsigned (regcache, HPPA_R31_REGNUM, pc | 0x3); - - hppa_write_pc (regcache, pc); -} - -static CORE_ADDR -hppa_hpux_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - ULONGEST flags; - - /* If we're currently in a system call return the contents of %r31. */ - flags = frame_unwind_register_unsigned (next_frame, HPPA_FLAGS_REGNUM); - if (flags & HPPA_HPUX_SS_INSYSCALL) - return frame_unwind_register_unsigned (next_frame, HPPA_R31_REGNUM) & ~0x3; - - return hppa_unwind_pc (gdbarch, next_frame); -} - - -/* Given the current value of the pc, check to see if it is inside a stub, and - if so, change the value of the pc to point to the caller of the stub. - THIS_FRAME is the current frame in the current list of frames. - BASE contains to stack frame base of the current frame. - SAVE_REGS is the register file stored in the frame cache. */ -static void -hppa_hpux_unwind_adjust_stub (struct frame_info *this_frame, CORE_ADDR base, - struct trad_frame_saved_reg *saved_regs) -{ - struct gdbarch *gdbarch = get_frame_arch (this_frame); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int word_size = gdbarch_ptr_bit (gdbarch) / 8; - struct value *pcoq_head_val; - ULONGEST pcoq_head; - CORE_ADDR stubpc; - struct unwind_table_entry *u; - - pcoq_head_val = trad_frame_get_prev_register (this_frame, saved_regs, - HPPA_PCOQ_HEAD_REGNUM); - pcoq_head = - extract_unsigned_integer (value_contents_all (pcoq_head_val), - register_size (gdbarch, HPPA_PCOQ_HEAD_REGNUM), - byte_order); - - u = find_unwind_entry (pcoq_head); - if (u && u->stub_unwind.stub_type == EXPORT) - { - stubpc = read_memory_integer (base - 24, word_size, byte_order); - trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc); - } - else if (hppa_symbol_address ("__gcc_plt_call") - == get_pc_function_start (pcoq_head)) - { - stubpc = read_memory_integer (base - 8, word_size, byte_order); - trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc); - } -} - -static void -hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - if (IS_32BIT_TARGET (gdbarch)) - tdep->in_solib_call_trampoline = hppa32_hpux_in_solib_call_trampoline; - else - tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline; - - tdep->unwind_adjust_stub = hppa_hpux_unwind_adjust_stub; - - set_gdbarch_in_solib_return_trampoline - (gdbarch, hppa_hpux_in_solib_return_trampoline); - set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code); - - set_gdbarch_push_dummy_code (gdbarch, hppa_hpux_push_dummy_code); - set_gdbarch_call_dummy_location (gdbarch, ON_STACK); - - set_gdbarch_read_pc (gdbarch, hppa_hpux_read_pc); - set_gdbarch_write_pc (gdbarch, hppa_hpux_write_pc); - set_gdbarch_unwind_pc (gdbarch, hppa_hpux_unwind_pc); - set_gdbarch_skip_permanent_breakpoint - (gdbarch, hppa_skip_permanent_breakpoint); - - set_gdbarch_iterate_over_regset_sections - (gdbarch, hppa_hpux_iterate_over_regset_sections); - - frame_unwind_append_unwinder (gdbarch, &hppa_hpux_sigtramp_frame_unwind); -} - -static void -hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - tdep->is_elf = 0; - - tdep->find_global_pointer = hppa32_hpux_find_global_pointer; - - hppa_hpux_init_abi (info, gdbarch); - som_solib_select (gdbarch); -} - -static void -hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - tdep->is_elf = 1; - tdep->find_global_pointer = hppa64_hpux_find_global_pointer; - - hppa_hpux_init_abi (info, gdbarch); - pa64_solib_select (gdbarch); -} - -static enum gdb_osabi -hppa_hpux_core_osabi_sniffer (bfd *abfd) -{ - if (strcmp (bfd_get_target (abfd), "hpux-core") == 0) - return GDB_OSABI_HPUX_SOM; - else if (strcmp (bfd_get_target (abfd), "elf64-hppa") == 0) - { - asection *section; - - section = bfd_get_section_by_name (abfd, ".kernel"); - if (section) - { - bfd_size_type size; - char *contents; - - size = bfd_section_size (abfd, section); - contents = alloca (size); - if (bfd_get_section_contents (abfd, section, contents, - (file_ptr) 0, size) - && strcmp (contents, "HP-UX") == 0) - return GDB_OSABI_HPUX_ELF; - } - } - - return GDB_OSABI_UNKNOWN; -} - -void -_initialize_hppa_hpux_tdep (void) -{ - /* BFD doesn't set a flavour for HP-UX style core files. It doesn't - set the architecture either. */ - gdbarch_register_osabi_sniffer (bfd_arch_unknown, - bfd_target_unknown_flavour, - hppa_hpux_core_osabi_sniffer); - gdbarch_register_osabi_sniffer (bfd_arch_hppa, - bfd_target_elf_flavour, - hppa_hpux_core_osabi_sniffer); - - gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_SOM, - hppa_hpux_som_init_abi); - gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w, GDB_OSABI_HPUX_ELF, - hppa_hpux_elf_init_abi); -} diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index f9c1bf2..8964ec0 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -46,13 +46,44 @@ static int hppa_debug = 0; static const int hppa32_num_regs = 128; static const int hppa64_num_regs = 96; +/* We use the objfile->obj_private pointer for two things: + * 1. An unwind table; + * + * 2. A pointer to any associated shared library object. + * + * #defines are used to help refer to these objects. + */ + +/* Info about the unwind table associated with an object file. + * This is hung off of the "objfile->obj_private" pointer, and + * is allocated in the objfile's psymbol obstack. This allows + * us to have unique unwind info for each executable and shared + * library that we are debugging. + */ +struct hppa_unwind_info + { + struct unwind_table_entry *table; /* Pointer to unwind info */ + struct unwind_table_entry *cache; /* Pointer to last entry we found */ + int last; /* Index of last entry */ + }; + +struct hppa_objfile_private + { + struct hppa_unwind_info *unwind_info; /* a pointer */ + struct so_list *so_info; /* a pointer */ + CORE_ADDR dp; + + int dummy_call_sequence_reg; + CORE_ADDR dummy_call_sequence_addr; + }; + /* hppa-specific object data -- unwind and solib info. TODO/maybe: think about splitting this into two parts; the unwind data is common to all hppa targets, but is only used in this file; we can register that separately and make this static. The solib data is probably hpux- specific, so we can create a separate extern objfile_data that is registered by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c. */ -const struct objfile_data *hppa_objfile_priv_data = NULL; +static const struct objfile_data *hppa_objfile_priv_data = NULL; /* Get at various relevent fields of an instruction word. */ #define MASK_5 0x1f @@ -170,7 +201,7 @@ hppa_symbol_address(const char *sym) return (CORE_ADDR)-1; } -struct hppa_objfile_private * +static struct hppa_objfile_private * hppa_init_objfile_priv_data (struct objfile *objfile) { struct hppa_objfile_private *priv; @@ -2778,14 +2809,6 @@ hppa_frame_prev_register_helper (struct frame_info *this_frame, return frame_unwind_got_constant (this_frame, regnum, pc + 4); } - /* Make sure the "flags" register is zero in all unwound frames. - The "flags" registers is a HP-UX specific wart, and only the code - in hppa-hpux-tdep.c depends on it. However, it is easier to deal - with it here. This shouldn't affect other systems since those - should provide zero for the "flags" register anyway. */ - if (regnum == HPPA_FLAGS_REGNUM) - return frame_unwind_got_constant (this_frame, regnum, 0); - return trad_frame_get_prev_register (this_frame, saved_regs, regnum); } diff --git a/gdb/hppa-tdep.h b/gdb/hppa-tdep.h index edf076d..f73c7ca 100644 --- a/gdb/hppa-tdep.h +++ b/gdb/hppa-tdep.h @@ -188,39 +188,6 @@ enum unwind_stub_types struct unwind_table_entry *find_unwind_entry (CORE_ADDR); -/* We use the objfile->obj_private pointer for two things: - * 1. An unwind table; - * - * 2. A pointer to any associated shared library object. - * - * #defines are used to help refer to these objects. - */ - -/* Info about the unwind table associated with an object file. - * This is hung off of the "objfile->obj_private" pointer, and - * is allocated in the objfile's psymbol obstack. This allows - * us to have unique unwind info for each executable and shared - * library that we are debugging. - */ -struct hppa_unwind_info - { - struct unwind_table_entry *table; /* Pointer to unwind info */ - struct unwind_table_entry *cache; /* Pointer to last entry we found */ - int last; /* Index of last entry */ - }; - -struct hppa_objfile_private - { - struct hppa_unwind_info *unwind_info; /* a pointer */ - struct so_list *so_info; /* a pointer */ - CORE_ADDR dp; - - int dummy_call_sequence_reg; - CORE_ADDR dummy_call_sequence_addr; - }; - -extern const struct objfile_data *hppa_objfile_priv_data; - int hppa_get_field (unsigned word, int from, int to); int hppa_extract_5_load (unsigned int); unsigned hppa_extract_5R_store (unsigned int); @@ -244,8 +211,6 @@ extern struct bound_minimal_symbol hppa_lookup_stub_minimal_symbol (const char *name, enum unwind_stub_types stub_type); -extern struct hppa_objfile_private *hppa_init_objfile_priv_data (struct objfile *objfile); - extern int hppa_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc); extern CORE_ADDR hppa_skip_trampoline_code (struct frame_info *, CORE_ADDR pc); diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c deleted file mode 100644 index 67b5854..0000000 --- a/gdb/ia64-hpux-nat.c +++ /dev/null @@ -1,756 +0,0 @@ -/* Copyright (C) 2010-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "ia64-tdep.h" -#include "inferior.h" -#include "inf-ttrace.h" -#include "regcache.h" -#include "solib-ia64-hpux.h" - -#include <ia64/sys/uregs.h> -#include <sys/ttrace.h> - -/* The offsets used with ttrace to read the value of the raw registers. */ - -static int u_offsets[] = -{ /* Static General Registers. */ - -1, __r1, __r2, __r3, __r4, __r5, __r6, __r7, - __r8, __r9, __r10, __r11, __r12, __r13, __r14, __r15, - __r16, __r17, __r18, __r19, __r20, __r21, __r22, __r23, - __r24, __r25, __r26, __r27, __r28, __r29, __r30, __r31, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -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 Floating-Point Registers. */ - -1, -1, __f2, __f3, __f4, __f5, __f6, __f7, - __f8, __f9, __f10, __f11, __f12, __f13, __f14, __f15, - __f16, __f17, __f18, __f19, __f20, __f21, __f22, __f23, - __f24, __f25, __f26, __f27, __f28, __f29, __f30, __f31, - __f32, __f33, __f34, __f35, __f36, __f37, __f38, __f39, - __f40, __f41, __f42, __f43, __f44, __f45, __f46, __f47, - __f48, __f49, __f50, __f51, __f52, __f53, __f54, __f55, - __f56, __f57, __f58, __f59, __f60, __f61, __f62, __f63, - __f64, __f65, __f66, __f67, __f68, __f69, __f70, __f71, - __f72, __f73, __f74, __f75, __f76, __f77, __f78, __f79, - __f80, __f81, __f82, __f83, __f84, __f85, __f86, __f87, - __f88, __f89, __f90, __f91, __f92, __f93, __f94, __f95, - __f96, __f97, __f98, __f99, __f100, __f101, __f102, __f103, - __f104, __f105, __f106, __f107, __f108, __f109, __f110, __f111, - __f112, __f113, __f114, __f115, __f116, __f117, __f118, __f119, - __f120, __f121, __f122, __f123, __f124, __f125, __f126, __f127, - - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -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. */ - __b0, __b1, __b2, __b3, __b4, __b5, __b6, __b7, - - /* Virtual frame pointer and virtual return address pointer. */ - -1, -1, - - /* Other registers. */ - __pr, __ip, __cr_ipsr, __cfm, - - /* Kernel registers. */ - -1, -1, -1, -1, - -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, - - /* Some application registers. */ - __ar_rsc, __ar_bsp, __ar_bspstore, __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, - __ar_ccv, -1, -1, -1, __ar_unat, -1, -1, -1, - __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, - __ar_pfs, __ar_lc, __ar_ec, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1 - /* All following registers, starting with nat0, are handled as - pseudo registers, and hence are handled separately. */ -}; - -/* Some register have a fixed value and can not be modified. - Store their value in static constant buffers that can be used - later to fill the register cache. */ -static const char r0_value[8] = {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; -static const char f0_value[16] = {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; -static const char f1_value[16] = {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - -/* The "to_wait" routine from the "inf-ttrace" layer. */ - -static ptid_t (*super_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, int); - -/* The "to_wait" target_ops routine routine for ia64-hpux. */ - -static ptid_t -ia64_hpux_wait (struct target_ops *ops, ptid_t ptid, - struct target_waitstatus *ourstatus, int options) -{ - ptid_t new_ptid; - - new_ptid = super_to_wait (ops, ptid, ourstatus, options); - - /* If this is a DLD event (hard-coded breakpoint instruction - that was activated by the solib-ia64-hpux module), we need to - process it, and then resume the execution as if the event did - not happen. */ - if (ourstatus->kind == TARGET_WAITKIND_STOPPED - && ourstatus->value.sig == GDB_SIGNAL_TRAP - && ia64_hpux_at_dld_breakpoint_p (new_ptid)) - { - ia64_hpux_handle_dld_breakpoint (new_ptid); - - target_resume (new_ptid, 0, GDB_SIGNAL_0); - ourstatus->kind = TARGET_WAITKIND_IGNORE; - } - - return new_ptid; -} - -/* Fetch the RNAT register and supply it to the REGCACHE. */ - -static void -ia64_hpux_fetch_rnat_register (struct regcache *regcache) -{ - CORE_ADDR addr; - gdb_byte buf[8]; - int status; - - /* The value of RNAT is stored at bsp|0x1f8, and must be read using - TT_LWP_RDRSEBS. */ - - regcache_raw_read_unsigned (regcache, IA64_BSP_REGNUM, &addr); - addr |= 0x1f8; - - status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid), - ptid_get_lwp (inferior_ptid), addr, sizeof (buf), - (uintptr_t) buf); - if (status < 0) - error (_("failed to read RNAT register at %s"), - paddress (get_regcache_arch(regcache), addr)); - - regcache_raw_supply (regcache, IA64_RNAT_REGNUM, buf); -} - -/* Read the value of the register saved at OFFSET in the save_state_t - structure, and store its value in BUF. LEN is the size of the register - to be read. */ - -static int -ia64_hpux_read_register_from_save_state_t (int offset, gdb_byte *buf, int len) -{ - int status; - - status = ttrace (TT_LWP_RUREGS, ptid_get_pid (inferior_ptid), - ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf); - - return status; -} - -/* Fetch register REGNUM from the inferior. */ - -static void -ia64_hpux_fetch_register (struct regcache *regcache, int regnum) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - int offset, len, status; - gdb_byte *buf; - - if (regnum == IA64_GR0_REGNUM) - { - /* r0 is always 0. */ - regcache_raw_supply (regcache, regnum, r0_value); - return; - } - - if (regnum == IA64_FR0_REGNUM) - { - /* f0 is always 0.0. */ - regcache_raw_supply (regcache, regnum, f0_value); - return; - } - - if (regnum == IA64_FR1_REGNUM) - { - /* f1 is always 1.0. */ - regcache_raw_supply (regcache, regnum, f1_value); - return; - } - - if (regnum == IA64_RNAT_REGNUM) - { - ia64_hpux_fetch_rnat_register (regcache); - return; - } - - /* Get the register location. If the register can not be fetched, - then return now. */ - offset = u_offsets[regnum]; - if (offset == -1) - return; - - len = register_size (gdbarch, regnum); - buf = alloca (len * sizeof (gdb_byte)); - status = ia64_hpux_read_register_from_save_state_t (offset, buf, len); - if (status < 0) - warning (_("Failed to read register value for %s."), - gdbarch_register_name (gdbarch, regnum)); - - regcache_raw_supply (regcache, regnum, buf); -} - -/* The "to_fetch_registers" target_ops routine for ia64-hpux. */ - -static void -ia64_hpux_fetch_registers (struct target_ops *ops, - struct regcache *regcache, int regnum) -{ - if (regnum == -1) - for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); - regnum++) - ia64_hpux_fetch_register (regcache, regnum); - else - ia64_hpux_fetch_register (regcache, regnum); -} - -/* Save register REGNUM (stored in BUF) in the save_state_t structure. - LEN is the size of the register in bytes. - - Return the value from the corresponding ttrace call (a negative value - means that the operation failed). */ - -static int -ia64_hpux_write_register_to_saved_state_t (int offset, gdb_byte *buf, int len) -{ - return ttrace (TT_LWP_WUREGS, ptid_get_pid (inferior_ptid), - ptid_get_lwp (inferior_ptid), offset, len, (uintptr_t) buf); -} - -/* Store register REGNUM into the inferior. */ - -static void -ia64_hpux_store_register (const struct regcache *regcache, int regnum) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - int offset = u_offsets[regnum]; - gdb_byte *buf; - int len, status; - - /* If the register can not be stored, then return now. */ - if (offset == -1) - return; - - /* I don't know how to store that register for now. So just ignore any - request to store it, to avoid an internal error. */ - if (regnum == IA64_PSR_REGNUM) - return; - - len = register_size (gdbarch, regnum); - buf = alloca (len * sizeof (gdb_byte)); - regcache_raw_collect (regcache, regnum, buf); - - status = ia64_hpux_write_register_to_saved_state_t (offset, buf, len); - - if (status < 0) - error (_("failed to write register value for %s."), - gdbarch_register_name (gdbarch, regnum)); -} - -/* The "to_store_registers" target_ops routine for ia64-hpux. */ - -static void -ia64_hpux_store_registers (struct target_ops *ops, - struct regcache *regcache, int regnum) -{ - if (regnum == -1) - for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); - regnum++) - ia64_hpux_store_register (regcache, regnum); - else - ia64_hpux_store_register (regcache, regnum); -} - -/* The "xfer_partial" routine from the "inf-ttrace" target layer. - Ideally, we would like to use this routine for all transfer - requests, but this platforms has a lot of special cases that - need to be handled manually. So we override this routine and - delegate back if we detect that we are not in a special case. */ - -static target_xfer_partial_ftype *super_xfer_partial; - -/* The "xfer_partial" routine for a memory region that is completely - outside of the backing-store region. */ - -static enum target_xfer_status -ia64_hpux_xfer_memory_no_bs (struct target_ops *ops, const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - CORE_ADDR addr, LONGEST len, - ULONGEST *xfered_len) -{ - /* Memory writes need to be aligned on 16byte boundaries, at least - when writing in the text section. On the other hand, the size - of the buffer does not need to be a multiple of 16bytes. - - No such restriction when performing memory reads. */ - - if (writebuf && addr & 0x0f) - { - const CORE_ADDR aligned_addr = addr & ~0x0f; - const int aligned_len = len + (addr - aligned_addr); - gdb_byte *aligned_buf = alloca (aligned_len * sizeof (gdb_byte)); - LONGEST status; - - /* Read the portion of memory between ALIGNED_ADDR and ADDR, so - that we can write it back during our aligned memory write. */ - status = super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex, - aligned_buf /* read */, - NULL /* write */, - aligned_addr, addr - aligned_addr); - if (status <= 0) - return TARGET_XFER_EOF; - memcpy (aligned_buf + (addr - aligned_addr), writebuf, len); - - return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex, - NULL /* read */, aligned_buf /* write */, - aligned_addr, aligned_len, xfered_len); - } - else - /* Memory read or properly aligned memory write. */ - return super_xfer_partial (ops, TARGET_OBJECT_MEMORY, annex, readbuf, - writebuf, addr, len, xfered_len); -} - -/* Read LEN bytes at ADDR from memory, and store it in BUF. This memory - region is assumed to be inside the backing store. - - Return zero if the operation failed. */ - -static int -ia64_hpux_read_memory_bs (gdb_byte *buf, CORE_ADDR addr, int len) -{ - gdb_byte tmp_buf[8]; - CORE_ADDR tmp_addr = addr & ~0x7; - - while (tmp_addr < addr + len) - { - int status; - int skip_lo = 0; - int skip_hi = 0; - - status = ttrace (TT_LWP_RDRSEBS, ptid_get_pid (inferior_ptid), - ptid_get_lwp (inferior_ptid), tmp_addr, - sizeof (tmp_buf), (uintptr_t) tmp_buf); - if (status < 0) - return 0; - - if (tmp_addr < addr) - skip_lo = addr - tmp_addr; - - if (tmp_addr + sizeof (tmp_buf) > addr + len) - skip_hi = (tmp_addr + sizeof (tmp_buf)) - (addr + len); - - memcpy (buf + (tmp_addr + skip_lo - addr), - tmp_buf + skip_lo, - sizeof (tmp_buf) - skip_lo - skip_hi); - - tmp_addr += sizeof (tmp_buf); - } - - return 1; -} - -/* Write LEN bytes from BUF in memory at ADDR. This memory region is assumed - to be inside the backing store. - - Return zero if the operation failed. */ - -static int -ia64_hpux_write_memory_bs (const gdb_byte *buf, CORE_ADDR addr, int len) -{ - gdb_byte tmp_buf[8]; - CORE_ADDR tmp_addr = addr & ~0x7; - - while (tmp_addr < addr + len) - { - int status; - int lo = 0; - int hi = 7; - - if (tmp_addr < addr || tmp_addr + sizeof (tmp_buf) > addr + len) - /* Part of the 8byte region pointed by tmp_addr needs to be preserved. - So read it in before we copy the data that needs to be changed. */ - if (!ia64_hpux_read_memory_bs (tmp_buf, tmp_addr, sizeof (tmp_buf))) - return 0; - - if (tmp_addr < addr) - lo = addr - tmp_addr; - - if (tmp_addr + sizeof (tmp_buf) > addr + len) - hi = addr - tmp_addr + len - 1; - - memcpy (tmp_buf + lo, buf + tmp_addr - addr + lo, hi - lo + 1); - - status = ttrace (TT_LWP_WRRSEBS, ptid_get_pid (inferior_ptid), - ptid_get_lwp (inferior_ptid), tmp_addr, - sizeof (tmp_buf), (uintptr_t) tmp_buf); - if (status < 0) - return 0; - - tmp_addr += sizeof (tmp_buf); - } - - return 1; -} - -/* The "xfer_partial" routine for a memory region that is completely - inside of the backing-store region. */ - -static LONGEST -ia64_hpux_xfer_memory_bs (struct target_ops *ops, const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - CORE_ADDR addr, LONGEST len) -{ - int success; - - if (readbuf) - success = ia64_hpux_read_memory_bs (readbuf, addr, len); - else - success = ia64_hpux_write_memory_bs (writebuf, addr, len); - - if (success) - return len; - else - return 0; -} - -/* Get a register value as a unsigned value directly from the system, - instead of going through the regcache. - - This function is meant to be used when inferior_ptid is not - a thread/process known to GDB. */ - -static ULONGEST -ia64_hpux_get_register_from_save_state_t (int regnum, int reg_size) -{ - gdb_byte *buf = alloca (reg_size); - int offset = u_offsets[regnum]; - int status; - - /* The register is assumed to be available for fetching. */ - gdb_assert (offset != -1); - - status = ia64_hpux_read_register_from_save_state_t (offset, buf, reg_size); - if (status < 0) - { - /* This really should not happen. If it does, emit a warning - and pretend the register value is zero. Not exactly the best - error recovery mechanism, but better than nothing. We will - try to do better if we can demonstrate that this can happen - under normal circumstances. */ - warning (_("Failed to read value of register number %d."), regnum); - return 0; - } - - return extract_unsigned_integer (buf, reg_size, BFD_ENDIAN_BIG); -} - -/* The "xfer_partial" target_ops routine for ia64-hpux, in the case - where the requested object is TARGET_OBJECT_MEMORY. */ - -static enum target_xfer_status -ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - CORE_ADDR addr, ULONGEST len, ULONGEST *xfered_len) -{ - CORE_ADDR bsp, bspstore; - CORE_ADDR start_addr, short_len; - int status = 0; - - /* The back-store region cannot be read/written by the standard memory - read/write operations. So we handle the memory region piecemeal: - (1) and (2) The regions before and after the backing-store region, - which can be treated as normal memory; - (3) The region inside the backing-store, which needs to be - read/written specially. */ - - if (in_inferior_list (ptid_get_pid (inferior_ptid))) - { - struct regcache *regcache = get_current_regcache (); - - regcache_raw_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); - regcache_raw_read_unsigned (regcache, IA64_BSPSTORE_REGNUM, &bspstore); - } - else - { - /* This is probably a child of our inferior created by a fork. - Because this process has not been added to our inferior list - (we are probably in the process of handling that child - process), we do not have a regcache to read the registers - from. So get those values directly from the kernel. */ - bsp = ia64_hpux_get_register_from_save_state_t (IA64_BSP_REGNUM, 8); - bspstore = - ia64_hpux_get_register_from_save_state_t (IA64_BSPSTORE_REGNUM, 8); - } - - /* 1. Memory region before BSPSTORE. */ - - if (addr < bspstore) - { - short_len = len; - if (addr + len > bspstore) - short_len = bspstore - addr; - - status = ia64_hpux_xfer_memory_no_bs (ops, annex, readbuf, writebuf, - addr, short_len); - if (status <= 0) - return TARGET_XFER_EOF; - } - - /* 2. Memory region after BSP. */ - - if (addr + len > bsp) - { - start_addr = addr; - if (start_addr < bsp) - start_addr = bsp; - short_len = len + addr - start_addr; - - status = ia64_hpux_xfer_memory_no_bs - (ops, annex, - readbuf ? readbuf + (start_addr - addr) : NULL, - writebuf ? writebuf + (start_addr - addr) : NULL, - start_addr, short_len); - if (status <= 0) - return TARGET_XFER_EOF; - } - - /* 3. Memory region between BSPSTORE and BSP. */ - - if (bspstore != bsp - && ((addr < bspstore && addr + len > bspstore) - || (addr + len <= bsp && addr + len > bsp))) - { - start_addr = addr; - if (addr < bspstore) - start_addr = bspstore; - short_len = len + addr - start_addr; - - if (start_addr + short_len > bsp) - short_len = bsp - start_addr; - - gdb_assert (short_len > 0); - - status = ia64_hpux_xfer_memory_bs - (ops, annex, - readbuf ? readbuf + (start_addr - addr) : NULL, - writebuf ? writebuf + (start_addr - addr) : NULL, - start_addr, short_len); - if (status < 0) - return TARGET_XFER_EOF; - } - - *xfered_len = len; - return TARGET_XFER_OK; -} - -/* Handle the transfer of TARGET_OBJECT_HPUX_UREGS objects on ia64-hpux. - ANNEX is currently ignored. - - The current implementation does not support write transfers (because - we do not currently do not need these transfers), and will raise - a failed assertion if WRITEBUF is not NULL. */ - -static enum target_xfer_status -ia64_hpux_xfer_uregs (struct target_ops *ops, const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) -{ - int status; - - gdb_assert (writebuf == NULL); - - status = ia64_hpux_read_register_from_save_state_t (offset, readbuf, len); - if (status < 0) - return TARGET_XFER_E_IO; - - *xfered_len = (ULONGEST) len; - return TARGET_XFER_OK; -} - -/* Handle the transfer of TARGET_OBJECT_HPUX_SOLIB_GOT objects on ia64-hpux. - - The current implementation does not support write transfers (because - we do not currently do not need these transfers), and will raise - a failed assertion if WRITEBUF is not NULL. */ - -static enum target_xfer_status -ia64_hpux_xfer_solib_got (struct target_ops *ops, const char *annex, - gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) -{ - CORE_ADDR fun_addr; - /* The linkage pointer. We use a uint64_t to make sure that the size - of the object we are returning is always 64 bits long, as explained - in the description of the TARGET_OBJECT_HPUX_SOLIB_GOT object. - This is probably paranoia, but we do not use a CORE_ADDR because - it could conceivably be larger than uint64_t. */ - uint64_t got; - - gdb_assert (writebuf == NULL); - - if (offset > sizeof (got)) - return TARGET_XFER_EOF; - - fun_addr = string_to_core_addr (annex); - got = ia64_hpux_get_solib_linkage_addr (fun_addr); - - if (len > sizeof (got) - offset) - len = sizeof (got) - offset; - memcpy (readbuf, &got + offset, len); - - *xfered_len = (ULONGEST) len; - return TARGET_XFER_OK; -} - -/* The "to_xfer_partial" target_ops routine for ia64-hpux. */ - -static enum target_xfer_status -ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, - ULONGEST *xfered_len) -{ - enum target_xfer_status val; - - if (object == TARGET_OBJECT_MEMORY) - val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len, - xfered_len); - else if (object == TARGET_OBJECT_HPUX_UREGS) - val = ia64_hpux_xfer_uregs (ops, annex, readbuf, writebuf, offset, len, - xfered_len); - else if (object == TARGET_OBJECT_HPUX_SOLIB_GOT) - val = ia64_hpux_xfer_solib_got (ops, annex, readbuf, writebuf, offset, - len, xfered_len); - else - val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset, - len, xfered_len); - - return val; -} - -/* The "to_can_use_hw_breakpoint" target_ops routine for ia64-hpux. */ - -static int -ia64_hpux_can_use_hw_breakpoint (struct target_ops *self, - int type, int cnt, int othertype) -{ - /* No hardware watchpoint/breakpoint support yet. */ - return 0; -} - -/* The "to_mourn_inferior" routine from the "inf-ttrace" target_ops layer. */ - -static void (*super_mourn_inferior) (struct target_ops *); - -/* The "to_mourn_inferior" target_ops routine for ia64-hpux. */ - -static void -ia64_hpux_mourn_inferior (struct target_ops *ops) -{ - const int pid = ptid_get_pid (inferior_ptid); - int status; - - super_mourn_inferior (ops); - - /* On this platform, the process still exists even after we received - an exit event. Detaching from the process isn't sufficient either, - as it only turns the process into a zombie. So the only solution - we found is to kill it. */ - ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0); - wait (&status); -} - -/* Prevent warning from -Wmissing-prototypes. */ -void _initialize_ia64_hpux_nat (void); - -void -_initialize_ia64_hpux_nat (void) -{ - struct target_ops *t; - - t = inf_ttrace_target (); - super_to_wait = t->to_wait; - super_xfer_partial = t->to_xfer_partial; - super_mourn_inferior = t->to_mourn_inferior; - - t->to_wait = ia64_hpux_wait; - t->to_fetch_registers = ia64_hpux_fetch_registers; - t->to_store_registers = ia64_hpux_store_registers; - t->to_xfer_partial = ia64_hpux_xfer_partial; - t->to_can_use_hw_breakpoint = ia64_hpux_can_use_hw_breakpoint; - t->to_mourn_inferior = ia64_hpux_mourn_inferior; - t->to_attach_no_wait = 1; - - add_target (t); -} diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c deleted file mode 100644 index ba8c155..0000000 --- a/gdb/ia64-hpux-tdep.c +++ /dev/null @@ -1,434 +0,0 @@ -/* Target-dependent code for the IA-64 for GDB, the GNU debugger. - - Copyright (C) 2010-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "ia64-tdep.h" -#include "ia64-hpux-tdep.h" -#include "osabi.h" -#include "gdbtypes.h" -#include "solib.h" -#include "target.h" -#include "frame.h" -#include "regcache.h" -#include "gdbcore.h" -#include "inferior.h" - -/* A sequence of instructions pushed on the stack when we want to perform - an inferior function call. The main purpose of this code is to save - the output region of the register frame belonging to the function - from which we are making the call. Normally, all registers are saved - prior to the call, but this does not include stacked registers because - they are seen by GDB as pseudo registers. - - With Linux kernels, these stacked registers can be saved by simply - creating a new register frame, or in other words by moving the BSP. - But the HP/UX kernel does not allow this. So we rely on this code - instead, that makes functions calls whose only purpose is to create - new register frames. - - The array below is the result obtained after assembling the code - shown below. It's an array of bytes in order to make it independent - of the host endianess, in case it ends up being used on more than - one target. - - start: - // Save b0 before using it (into preserved reg: r4). - mov r4 = b0 - ;; - - br.call.dptk.few b0 = stub# - ;; - - // Add a nop bundle where we can insert our dummy breakpoint. - nop.m 0 - nop.i 0 - nop.i 0 - ;; - - stub: - // Alloc a new register stack frame. Here, we set the size - // of all regions to zero. Eventually, GDB will manually - // change the instruction to set the size of the local region - // to match size of the output region of the function from - // which we are making the function call. This is to protect - // the value of the output registers of the function from - // which we are making the call. - alloc r6 = ar.pfs, 0, 0, 0, 0 - - // Save b0 before using it again (into preserved reg: r5). - mov r5 = b0 - ;; - - // Now that we have protected the entire output region of the - // register stack frame, we can call our function that will - // setup the arguments, and call our target function. - br.call.dptk.few b0 = call_dummy# - ;; - - // Restore b0, ar.pfs, and return - mov b0 = r5 - mov.i ar.pfs = r6 - ;; - br.ret.dptk.few b0 - ;; - - call_dummy: - // Alloc a new frame, with 2 local registers, and 8 output registers - // (8 output registers for the maximum of 8 slots passed by register). - alloc r32 = ar.pfs, 2, 0, 8, 0 - - // Save b0 before using it to call our target function. - mov r33 = b0 - - // Load the argument values placed by GDB inside r14-r21 in their - // proper registers. - or r34 = r14, r0 - or r35 = r15, r0 - or r36 = r16, r0 - or r37 = r17, r0 - or r38 = r18, r0 - or r39 = r19, r0 - or r40 = r20, r0 - or r41 = r21, r0 - ;; - - // actual call - br.call.dptk.few b0 = b1 - ;; - - mov.i ar.pfs=r32 - mov b0=r33 - ;; - - br.ret.dptk.few b0 - ;; - -*/ - -static const gdb_byte ia64_hpux_dummy_code[] = -{ - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, - 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x52, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x02, 0x30, 0x00, 0x00, 0x80, 0x05, 0x50, 0x00, - 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x52, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, - 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0xaa, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02, - 0x00, 0x00, 0x29, 0x04, 0x80, 0x05, 0x10, 0x02, - 0x00, 0x62, 0x00, 0x40, 0xe4, 0x00, 0x38, 0x80, - 0x00, 0x18, 0x3d, 0x00, 0x0e, 0x20, 0x40, 0x82, - 0x00, 0x1c, 0x40, 0xa0, 0x14, 0x01, 0x38, 0x80, - 0x00, 0x30, 0x49, 0x00, 0x0e, 0x20, 0x70, 0x9a, - 0x00, 0x1c, 0x40, 0x00, 0x45, 0x01, 0x38, 0x80, - 0x0a, 0x48, 0x55, 0x00, 0x0e, 0x20, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x12, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x55, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x07, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02 -}; - -/* The offset to be used in order to get the __reason pseudo-register - when using one of the *UREGS ttrace requests (see system header file - /usr/include/ia64/sys/uregs.h for more details). - - The documentation for this pseudo-register says that a nonzero value - indicates that the thread stopped due to a fault, trap, or interrupt. - A null value indicates a stop inside a syscall. */ -#define IA64_HPUX_UREG_REASON 0x00070000 - -/* Return nonzero if the value of the register identified by REGNUM - can be modified. */ - -static int -ia64_hpux_can_store_ar_register (int regnum) -{ - switch (regnum) - { - case IA64_RSC_REGNUM: - case IA64_RNAT_REGNUM: - case IA64_CSD_REGNUM: - case IA64_SSD_REGNUM: - case IA64_CCV_REGNUM: - case IA64_UNAT_REGNUM: - case IA64_FPSR_REGNUM: - case IA64_PFS_REGNUM: - case IA64_LC_REGNUM: - case IA64_EC_REGNUM: - return 1; - break; - - default: - return 0; - break; - } -} - -/* The "cannot_store_register" target_ops method. */ - -static int -ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum) -{ - /* General registers. */ - - if (regnum == IA64_GR0_REGNUM) - return 1; - - /* FP register. */ - - if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM) - return 1; - - /* Application registers. */ - if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127) - return (!ia64_hpux_can_store_ar_register (regnum)); - - /* We can store all other registers. */ - return 0; -} - -/* Return nonzero if the inferior is stopped inside a system call. */ - -static int -ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct target_ops *ops = ¤t_target; - gdb_byte buf[8]; - int len; - - len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL, - buf, IA64_HPUX_UREG_REASON, sizeof (buf)); - if (len == -1) - /* The target wasn't able to tell us. Assume we are not stopped - in a system call, which is the normal situation. */ - return 0; - gdb_assert (len == 8); - - return (extract_unsigned_integer (buf, len, byte_order) == 0); -} - -/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */ - -static int -ia64_hpux_size_of_register_frame (struct frame_info *this_frame, - ULONGEST cfm) -{ - int sof; - - if (frame_relative_level (this_frame) == 0 - && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame))) - /* If the inferior stopped in a system call, the base address - of the register frame is at BSP - SOL instead of BSP - SOF. - This is an HP-UX exception. */ - sof = (cfm & 0x3f80) >> 7; - else - sof = (cfm & 0x7f); - - return sof; -} - -/* Implement the push_dummy_code gdbarch method. - - This function assumes that the SP is already 16-byte-aligned. */ - -static CORE_ADDR -ia64_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, - CORE_ADDR funaddr, struct value **args, int nargs, - struct type *value_type, CORE_ADDR *real_pc, - CORE_ADDR *bp_addr, struct regcache *regcache) -{ - ULONGEST cfm; - int sof, sol, sor, soo; - gdb_byte buf[16]; - - regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); - sof = cfm & 0x7f; - sol = (cfm >> 7) & 0x7f; - sor = (cfm >> 14) & 0xf; - soo = sof - sol - sor; - - /* Reserve some space on the stack to hold the dummy code. */ - sp = sp - sizeof (ia64_hpux_dummy_code); - - /* Set the breakpoint address at the first instruction of the bundle - in the dummy code that has only nops. This is where the dummy code - expects us to break. */ - *bp_addr = sp + 0x20; - - /* Start the inferior function call from the dummy code. The dummy - code will then call our function. */ - *real_pc = sp; - - /* Transfer the dummy code to the inferior. */ - write_memory (sp, ia64_hpux_dummy_code, sizeof (ia64_hpux_dummy_code)); - - /* Update the size of the local portion of the register frame allocated - by ``stub'' to match the size of the output region of the current - register frame. This allows us to save the stacked registers. - - The "alloc" instruction is located at slot 0 of the bundle at +0x30. - Update the "sof" and "sol" portion of that instruction which are - respectively at bits 18-24 and 25-31 of the bundle. */ - memcpy (buf, ia64_hpux_dummy_code + 0x30, sizeof (buf)); - - buf[2] |= ((soo & 0x3f) << 2); - buf[3] |= (soo << 1); - if (soo > 63) - buf[3] |= 1; - - write_memory (sp + 0x30, buf, sizeof (buf)); - - /* Return the new (already properly aligned) SP. */ - return sp; -} - -/* The "allocate_new_rse_frame" ia64_infcall_ops routine for ia64-hpux. */ - -static void -ia64_hpux_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, - int sof) -{ - /* We cannot change the value of the BSP register on HP-UX, - so we can't allocate a new RSE frame. */ -} - -/* The "store_argument_in_slot" ia64_infcall_ops routine for ia64-hpux. */ - -static void -ia64_hpux_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp, - int slotnum, gdb_byte *buf) -{ - /* The call sequence on this target expects us to place the arguments - inside r14 - r21. */ - regcache_cooked_write (regcache, IA64_GR0_REGNUM + 14 + slotnum, buf); -} - -/* The "set_function_addr" ia64_infcall_ops routine for ia64-hpux. */ - -static void -ia64_hpux_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr) -{ - /* The calling sequence calls the function whose address is placed - in register b1. */ - regcache_cooked_write_unsigned (regcache, IA64_BR1_REGNUM, func_addr); -} - -/* The ia64_infcall_ops structure for ia64-hpux. */ - -static const struct ia64_infcall_ops ia64_hpux_infcall_ops = -{ - ia64_hpux_allocate_new_rse_frame, - ia64_hpux_store_argument_in_slot, - ia64_hpux_set_function_addr -}; - -/* The "dummy_id" gdbarch routine for ia64-hpux. */ - -static struct frame_id -ia64_hpux_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) -{ - CORE_ADDR sp, pc, bp_addr, bsp; - - sp = get_frame_register_unsigned (this_frame, IA64_GR12_REGNUM); - - /* Just double-check that the frame PC is within a certain region - of the stack that would be plausible for our dummy code (the dummy - code was pushed at SP + 16). If not, then return a null frame ID. - This is necessary in our case, because it is possible to produce - the same frame ID for a normal frame, if that frame corresponds - to the function called by our dummy code, and the function has not - modified the registers that we use to build the dummy frame ID. */ - pc = get_frame_pc (this_frame); - if (pc < sp + 16 || pc >= sp + 16 + sizeof (ia64_hpux_dummy_code)) - return null_frame_id; - - /* The call sequence is such that the address of the dummy breakpoint - we inserted is stored in r5. */ - bp_addr = get_frame_register_unsigned (this_frame, IA64_GR5_REGNUM); - - bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM); - - return frame_id_build_special (sp, bp_addr, bsp); -} - -/* Should be set to non-NULL if the ia64-hpux solib module is linked in. - This may not be the case because the shared library support code can - only be compiled on ia64-hpux. */ - -struct target_so_ops *ia64_hpux_so_ops = NULL; - -/* The "find_global_pointer_from_solib" gdbarch_tdep routine for - ia64-hpux. */ - -static CORE_ADDR -ia64_hpux_find_global_pointer_from_solib (struct gdbarch *gdbarch, - CORE_ADDR faddr) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct target_ops *ops = ¤t_target; - gdb_byte buf[8]; - LONGEST len; - - len = target_read (ops, TARGET_OBJECT_HPUX_SOLIB_GOT, - paddress (gdbarch, faddr), buf, 0, sizeof (buf)); - - return extract_unsigned_integer (buf, len, byte_order); -} - -static void -ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - tdep->size_of_register_frame = ia64_hpux_size_of_register_frame; - - set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); - set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register); - - /* Inferior functions must be called from stack. */ - set_gdbarch_call_dummy_location (gdbarch, ON_STACK); - set_gdbarch_push_dummy_code (gdbarch, ia64_hpux_push_dummy_code); - tdep->infcall_ops = ia64_hpux_infcall_ops; - tdep->find_global_pointer_from_solib - = ia64_hpux_find_global_pointer_from_solib; - set_gdbarch_dummy_id (gdbarch, ia64_hpux_dummy_id); - - if (ia64_hpux_so_ops) - set_solib_ops (gdbarch, ia64_hpux_so_ops); -} - -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_ia64_hpux_tdep; - -void -_initialize_ia64_hpux_tdep (void) -{ - gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF, - ia64_hpux_init_abi); -} diff --git a/gdb/ia64-hpux-tdep.h b/gdb/ia64-hpux-tdep.h deleted file mode 100644 index a00b1de..0000000 --- a/gdb/ia64-hpux-tdep.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 2010-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef IA64_HPUX_TDEP_H -#define IA64_HPUX_TDEP_H - -struct target_so_ops; -extern struct target_so_ops *ia64_hpux_so_ops; - -#endif diff --git a/gdb/inf-ttrace.c b/gdb/inf-ttrace.c deleted file mode 100644 index 8957ca2..0000000 --- a/gdb/inf-ttrace.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* Low-level child interface to ttrace. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" - -/* The ttrace(2) system call didn't exist before HP-UX 10.30. Don't - try to compile this code unless we have it. */ -#ifdef HAVE_TTRACE - -#include "command.h" -#include "gdbcore.h" -#include "gdbthread.h" -#include "inferior.h" -#include "terminal.h" -#include "target.h" -#include <sys/mman.h> -#include <sys/ttrace.h> -#include <signal.h> - -#include "inf-child.h" -#include "inf-ttrace.h" -#include "common/filestuff.h" - - - -/* HP-UX uses a threading model where each user-space thread - corresponds to a kernel thread. These kernel threads are called - lwps. The ttrace(2) interface gives us almost full control over - the threads, which makes it very easy to support them in GDB. We - identify the threads by process ID and lwp ID. The ttrace(2) also - provides us with a thread's user ID (in the `tts_user_tid' member - of `ttstate_t') but we don't use that (yet) as it isn't necessary - to uniquely label the thread. */ - -/* Number of active lwps. */ -static int inf_ttrace_num_lwps; - - -/* On HP-UX versions that have the ttrace(2) system call, we can - implement "hardware" watchpoints by fiddling with the protection of - pages in the address space that contain the variable being watched. - In order to implement this, we keep a dictionary of pages for which - we have changed the protection. */ - -struct inf_ttrace_page -{ - CORE_ADDR addr; /* Page address. */ - int prot; /* Protection. */ - int refcount; /* Reference count. */ - struct inf_ttrace_page *next; - struct inf_ttrace_page *prev; -}; - -struct inf_ttrace_page_dict -{ - struct inf_ttrace_page buckets[128]; - int pagesize; /* Page size. */ - int count; /* Number of pages in this dictionary. */ -} inf_ttrace_page_dict; - -struct inf_ttrace_private_thread_info -{ - int dying; -}; - -/* Number of lwps that are currently in a system call. */ -static int inf_ttrace_num_lwps_in_syscall; - -/* Flag to indicate whether we should re-enable page protections after - the next wait. */ -static int inf_ttrace_reenable_page_protections; - -/* Enable system call events for process PID. */ - -static void -inf_ttrace_enable_syscall_events (pid_t pid) -{ - ttevent_t tte; - ttstate_t tts; - - gdb_assert (inf_ttrace_num_lwps_in_syscall == 0); - - if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN); - - if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0, - (uintptr_t)&tts, sizeof tts, 0) == -1) - perror_with_name (("ttrace")); - - if (tts.tts_flags & TTS_INSYSCALL) - inf_ttrace_num_lwps_in_syscall++; - - /* FIXME: Handle multiple threads. */ -} - -/* Disable system call events for process PID. */ - -static void -inf_ttrace_disable_syscall_events (pid_t pid) -{ - ttevent_t tte; - - gdb_assert (inf_ttrace_page_dict.count == 0); - - if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN); - - if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - inf_ttrace_num_lwps_in_syscall = 0; -} - -/* Get information about the page at address ADDR for process PID from - the dictionary. */ - -static struct inf_ttrace_page * -inf_ttrace_get_page (pid_t pid, CORE_ADDR addr) -{ - const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets); - const int pagesize = inf_ttrace_page_dict.pagesize; - int bucket; - struct inf_ttrace_page *page; - - bucket = (addr / pagesize) % num_buckets; - page = &inf_ttrace_page_dict.buckets[bucket]; - while (page) - { - if (page->addr == addr) - break; - - page = page->next; - } - - return page; -} - -/* Add the page at address ADDR for process PID to the dictionary. */ - -static struct inf_ttrace_page * -inf_ttrace_add_page (pid_t pid, CORE_ADDR addr) -{ - const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets); - const int pagesize = inf_ttrace_page_dict.pagesize; - int bucket; - struct inf_ttrace_page *page; - struct inf_ttrace_page *prev = NULL; - - bucket = (addr / pagesize) % num_buckets; - page = &inf_ttrace_page_dict.buckets[bucket]; - while (page) - { - if (page->addr == addr) - break; - - prev = page; - page = page->next; - } - - if (!page) - { - int prot; - - if (ttrace (TT_PROC_GET_MPROTECT, pid, 0, - addr, 0, (uintptr_t)&prot) == -1) - perror_with_name (("ttrace")); - - page = XNEW (struct inf_ttrace_page); - page->addr = addr; - page->prot = prot; - page->refcount = 0; - page->next = NULL; - - page->prev = prev; - prev->next = page; - - inf_ttrace_page_dict.count++; - if (inf_ttrace_page_dict.count == 1) - inf_ttrace_enable_syscall_events (pid); - - if (inf_ttrace_num_lwps_in_syscall == 0) - { - if (ttrace (TT_PROC_SET_MPROTECT, pid, 0, - addr, pagesize, prot & ~PROT_WRITE) == -1) - perror_with_name (("ttrace")); - } - } - - return page; -} - -/* Insert the page at address ADDR of process PID to the dictionary. */ - -static void -inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr) -{ - struct inf_ttrace_page *page; - - page = inf_ttrace_get_page (pid, addr); - if (!page) - page = inf_ttrace_add_page (pid, addr); - - page->refcount++; -} - -/* Remove the page at address ADDR of process PID from the dictionary. */ - -static void -inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr) -{ - const int pagesize = inf_ttrace_page_dict.pagesize; - struct inf_ttrace_page *page; - - page = inf_ttrace_get_page (pid, addr); - page->refcount--; - - gdb_assert (page->refcount >= 0); - - if (page->refcount == 0) - { - if (inf_ttrace_num_lwps_in_syscall == 0) - { - if (ttrace (TT_PROC_SET_MPROTECT, pid, 0, - addr, pagesize, page->prot) == -1) - perror_with_name (("ttrace")); - } - - inf_ttrace_page_dict.count--; - if (inf_ttrace_page_dict.count == 0) - inf_ttrace_disable_syscall_events (pid); - - page->prev->next = page->next; - if (page->next) - page->next->prev = page->prev; - - xfree (page); - } -} - -/* Mask the bits in PROT from the page protections that are currently - in the dictionary for process PID. */ - -static void -inf_ttrace_mask_page_protections (pid_t pid, int prot) -{ - const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets); - const int pagesize = inf_ttrace_page_dict.pagesize; - int bucket; - - for (bucket = 0; bucket < num_buckets; bucket++) - { - struct inf_ttrace_page *page; - - page = inf_ttrace_page_dict.buckets[bucket].next; - while (page) - { - if (ttrace (TT_PROC_SET_MPROTECT, pid, 0, - page->addr, pagesize, page->prot & ~prot) == -1) - perror_with_name (("ttrace")); - - page = page->next; - } - } -} - -/* Write-protect the pages in the dictionary for process PID. */ - -static void -inf_ttrace_enable_page_protections (pid_t pid) -{ - inf_ttrace_mask_page_protections (pid, PROT_WRITE); -} - -/* Restore the protection of the pages in the dictionary for process - PID. */ - -static void -inf_ttrace_disable_page_protections (pid_t pid) -{ - inf_ttrace_mask_page_protections (pid, 0); -} - -/* Insert a "hardware" watchpoint for LEN bytes at address ADDR of - type TYPE. */ - -static int -inf_ttrace_insert_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len, int type, - struct expression *cond) -{ - const int pagesize = inf_ttrace_page_dict.pagesize; - pid_t pid = ptid_get_pid (inferior_ptid); - CORE_ADDR page_addr; - int num_pages; - int page; - - gdb_assert (type == hw_write); - - page_addr = (addr / pagesize) * pagesize; - num_pages = (len + pagesize - 1) / pagesize; - - for (page = 0; page < num_pages; page++, page_addr += pagesize) - inf_ttrace_insert_page (pid, page_addr); - - return 1; -} - -/* Remove a "hardware" watchpoint for LEN bytes at address ADDR of - type TYPE. */ - -static int -inf_ttrace_remove_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len, int type, - struct expression *cond) -{ - const int pagesize = inf_ttrace_page_dict.pagesize; - pid_t pid = ptid_get_pid (inferior_ptid); - CORE_ADDR page_addr; - int num_pages; - int page; - - gdb_assert (type == hw_write); - - page_addr = (addr / pagesize) * pagesize; - num_pages = (len + pagesize - 1) / pagesize; - - for (page = 0; page < num_pages; page++, page_addr += pagesize) - inf_ttrace_remove_page (pid, page_addr); - - return 1; -} - -static int -inf_ttrace_can_use_hw_breakpoint (struct target_ops *self, - int type, int len, int ot) -{ - return (type == bp_hardware_watchpoint); -} - -static int -inf_ttrace_region_ok_for_hw_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len) -{ - return 1; -} - -/* Return non-zero if the current inferior was (potentially) stopped - by hitting a "hardware" watchpoint. */ - -static int -inf_ttrace_stopped_by_watchpoint (struct target_ops *ops) -{ - pid_t pid = ptid_get_pid (inferior_ptid); - lwpid_t lwpid = ptid_get_lwp (inferior_ptid); - ttstate_t tts; - - if (inf_ttrace_page_dict.count > 0) - { - if (ttrace (TT_LWP_GET_STATE, pid, lwpid, - (uintptr_t)&tts, sizeof tts, 0) == -1) - perror_with_name (("ttrace")); - - if (tts.tts_event == TTEVT_SIGNAL - && tts.tts_u.tts_signal.tts_signo == SIGBUS) - { - const int pagesize = inf_ttrace_page_dict.pagesize; - void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr; - CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize; - - if (inf_ttrace_get_page (pid, page_addr)) - return 1; - } - } - - return 0; -} - - -/* Target hook for follow_fork. On entry and at return inferior_ptid - is the ptid of the followed inferior. */ - -static int -inf_ttrace_follow_fork (struct target_ops *ops, int follow_child, - int detach_fork) -{ - struct thread_info *tp = inferior_thread (); - - gdb_assert (tp->pending_follow.kind == TARGET_WAITKIND_FORKED - || tp->pending_follow.kind == TARGET_WAITKIND_VFORKED); - - if (follow_child) - { - struct thread_info *ti; - - /* The child will start out single-threaded. */ - inf_ttrace_num_lwps = 1; - inf_ttrace_num_lwps_in_syscall = 0; - - ti = inferior_thread (); - ti->priv = - xmalloc (sizeof (struct inf_ttrace_private_thread_info)); - memset (ti->priv, 0, - sizeof (struct inf_ttrace_private_thread_info)); - } - else - { - pid_t child_pid; - - /* Following parent. Detach child now. */ - child_pid = ptid_get_pid (tp->pending_follow.value.related_pid); - if (ttrace (TT_PROC_DETACH, child_pid, 0, 0, 0, 0) == -1) - perror_with_name (("ttrace")); - } - - return 0; -} - - -/* File descriptors for pipes used as semaphores during initial - startup of an inferior. */ -static int inf_ttrace_pfd1[2]; -static int inf_ttrace_pfd2[2]; - -static void -do_cleanup_pfds (void *dummy) -{ - close (inf_ttrace_pfd1[0]); - close (inf_ttrace_pfd1[1]); - close (inf_ttrace_pfd2[0]); - close (inf_ttrace_pfd2[1]); - - unmark_fd_no_cloexec (inf_ttrace_pfd1[0]); - unmark_fd_no_cloexec (inf_ttrace_pfd1[1]); - unmark_fd_no_cloexec (inf_ttrace_pfd2[0]); - unmark_fd_no_cloexec (inf_ttrace_pfd2[1]); -} - -static void -inf_ttrace_prepare (void) -{ - if (pipe (inf_ttrace_pfd1) == -1) - perror_with_name (("pipe")); - - if (pipe (inf_ttrace_pfd2) == -1) - { - close (inf_ttrace_pfd1[0]); - close (inf_ttrace_pfd2[0]); - perror_with_name (("pipe")); - } - - mark_fd_no_cloexec (inf_ttrace_pfd1[0]); - mark_fd_no_cloexec (inf_ttrace_pfd1[1]); - mark_fd_no_cloexec (inf_ttrace_pfd2[0]); - mark_fd_no_cloexec (inf_ttrace_pfd2[1]); -} - -/* Prepare to be traced. */ - -static void -inf_ttrace_me (void) -{ - struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0); - char c; - - /* "Trace me, Dr. Memory!" */ - if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1) - perror_with_name (("ttrace")); - - /* Tell our parent that we are ready to be traced. */ - if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c) - perror_with_name (("write")); - - /* Wait until our parent has set the initial event mask. */ - if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c) - perror_with_name (("read")); - - do_cleanups (old_chain); -} - -/* Start tracing PID. */ - -static void -inf_ttrace_him (struct target_ops *ops, int pid) -{ - struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0); - ttevent_t tte; - char c; - - /* Wait until our child is ready to be traced. */ - if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c) - perror_with_name (("read")); - - /* Set the initial event mask. */ - memset (&tte, 0, sizeof (tte)); - tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK; - tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE; -#ifdef TTEVT_BPT_SSTEP - tte.tte_events |= TTEVT_BPT_SSTEP; -#endif - tte.tte_opts |= TTEO_PROC_INHERIT; - if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - /* Tell our child that we have set the initial event mask. */ - if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c) - perror_with_name (("write")); - - do_cleanups (old_chain); - - if (!target_is_pushed (ops)) - push_target (ops); - - startup_inferior (START_INFERIOR_TRAPS_EXPECTED); - - /* On some targets, there must be some explicit actions taken after - the inferior has been started up. */ - target_post_startup_inferior (pid_to_ptid (pid)); -} - -static void -inf_ttrace_create_inferior (struct target_ops *ops, char *exec_file, - char *allargs, char **env, int from_tty) -{ - int pid; - - gdb_assert (inf_ttrace_num_lwps == 0); - gdb_assert (inf_ttrace_num_lwps_in_syscall == 0); - gdb_assert (inf_ttrace_page_dict.count == 0); - gdb_assert (inf_ttrace_reenable_page_protections == 0); - - pid = fork_inferior (exec_file, allargs, env, inf_ttrace_me, NULL, - inf_ttrace_prepare, NULL, NULL); - - inf_ttrace_him (ops, pid); -} - -static void -inf_ttrace_mourn_inferior (struct target_ops *ops) -{ - const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets); - int bucket; - - inf_ttrace_num_lwps = 0; - inf_ttrace_num_lwps_in_syscall = 0; - - for (bucket = 0; bucket < num_buckets; bucket++) - { - struct inf_ttrace_page *page; - struct inf_ttrace_page *next; - - page = inf_ttrace_page_dict.buckets[bucket].next; - while (page) - { - next = page->next; - xfree (page); - page = next; - } - } - inf_ttrace_page_dict.count = 0; - - inf_child_mourn_inferior (ops); -} - -/* Assuming we just attached the debugger to a new inferior, create - a new thread_info structure for each thread, and add it to our - list of threads. */ - -static void -inf_ttrace_create_threads_after_attach (int pid) -{ - int status; - ptid_t ptid; - ttstate_t tts; - struct thread_info *ti; - - status = ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0, - (uintptr_t) &tts, sizeof (ttstate_t), 0); - if (status < 0) - perror_with_name (_("TT_PROC_GET_FIRST_LWP_STATE ttrace call failed")); - gdb_assert (tts.tts_pid == pid); - - /* Add the stopped thread. */ - ptid = ptid_build (pid, tts.tts_lwpid, 0); - ti = add_thread (ptid); - ti->priv = xzalloc (sizeof (struct inf_ttrace_private_thread_info)); - inf_ttrace_num_lwps++; - - /* We use the "first stopped thread" as the currently active thread. */ - inferior_ptid = ptid; - - /* Iterative over all the remaining threads. */ - - for (;;) - { - ptid_t ptid; - - status = ttrace (TT_PROC_GET_NEXT_LWP_STATE, pid, 0, - (uintptr_t) &tts, sizeof (ttstate_t), 0); - if (status < 0) - perror_with_name (_("TT_PROC_GET_NEXT_LWP_STATE ttrace call failed")); - if (status == 0) - break; /* End of list. */ - - ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - ti = add_thread (ptid); - ti->priv = xzalloc (sizeof (struct inf_ttrace_private_thread_info)); - inf_ttrace_num_lwps++; - } -} - -static void -inf_ttrace_attach (struct target_ops *ops, const char *args, int from_tty) -{ - char *exec_file; - pid_t pid; - ttevent_t tte; - struct inferior *inf; - - pid = parse_pid_to_attach (args); - - if (pid == getpid ()) /* Trying to masturbate? */ - error (_("I refuse to debug myself!")); - - if (from_tty) - { - exec_file = get_exec_file (0); - - if (exec_file) - printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file, - target_pid_to_str (pid_to_ptid (pid))); - else - printf_unfiltered (_("Attaching to %s\n"), - target_pid_to_str (pid_to_ptid (pid))); - - gdb_flush (gdb_stdout); - } - - gdb_assert (inf_ttrace_num_lwps == 0); - gdb_assert (inf_ttrace_num_lwps_in_syscall == 0); - - if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1) - perror_with_name (("ttrace")); - - inf = current_inferior (); - inferior_appeared (inf, pid); - inf->attach_flag = 1; - - /* Set the initial event mask. */ - memset (&tte, 0, sizeof (tte)); - tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK; - tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE; -#ifdef TTEVT_BPT_SSTEP - tte.tte_events |= TTEVT_BPT_SSTEP; -#endif - tte.tte_opts |= TTEO_PROC_INHERIT; - if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0, - (uintptr_t)&tte, sizeof tte, 0) == -1) - perror_with_name (("ttrace")); - - if (!target_is_pushed (ops)) - push_target (ops); - - inf_ttrace_create_threads_after_attach (pid); -} - -static void -inf_ttrace_detach (struct target_ops *ops, const char *args, int from_tty) -{ - pid_t pid = ptid_get_pid (inferior_ptid); - int sig = 0; - - if (from_tty) - { - char *exec_file = get_exec_file (0); - if (exec_file == 0) - exec_file = ""; - printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file, - target_pid_to_str (pid_to_ptid (pid))); - gdb_flush (gdb_stdout); - } - if (args) - sig = atoi (args); - - /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we - can pass a signal number here. Does this really work? */ - if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1) - perror_with_name (("ttrace")); - - inf_ttrace_num_lwps = 0; - inf_ttrace_num_lwps_in_syscall = 0; - - inferior_ptid = null_ptid; - detach_inferior (pid); - - inf_child_maybe_unpush_target (ops); -} - -static void -inf_ttrace_kill (struct target_ops *ops) -{ - pid_t pid = ptid_get_pid (inferior_ptid); - - if (pid == 0) - return; - - if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1) - perror_with_name (("ttrace")); - /* ??? Is it necessary to call ttrace_wait() here? */ - - target_mourn_inferior (); -} - -/* Check is a dying thread is dead by now, and delete it from GDBs - thread list if so. */ -static int -inf_ttrace_delete_dead_threads_callback (struct thread_info *info, void *arg) -{ - lwpid_t lwpid; - struct inf_ttrace_private_thread_info *p; - - if (is_exited (info->ptid)) - return 0; - - lwpid = ptid_get_lwp (info->ptid); - p = (struct inf_ttrace_private_thread_info *) info->priv; - - /* Check if an lwp that was dying is still there or not. */ - if (p->dying && (kill (lwpid, 0) == -1)) - /* It's gone now. */ - delete_thread (info->ptid); - - return 0; -} - -/* Resume the lwp pointed to by INFO, with REQUEST, and pass it signal - SIG. */ - -static void -inf_ttrace_resume_lwp (struct thread_info *info, ttreq_t request, int sig) -{ - pid_t pid = ptid_get_pid (info->ptid); - lwpid_t lwpid = ptid_get_lwp (info->ptid); - - if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1) - { - struct inf_ttrace_private_thread_info *p - = (struct inf_ttrace_private_thread_info *) info->priv; - if (p->dying && errno == EPROTO) - /* This is expected, it means the dying lwp is really gone - by now. If ttrace had an event to inform the debugger - the lwp is really gone, this wouldn't be needed. */ - delete_thread (info->ptid); - else - /* This was really unexpected. */ - perror_with_name (("ttrace")); - } -} - -/* Callback for iterate_over_threads. */ - -static int -inf_ttrace_resume_callback (struct thread_info *info, void *arg) -{ - if (!ptid_equal (info->ptid, inferior_ptid) && !is_exited (info->ptid)) - inf_ttrace_resume_lwp (info, TT_LWP_CONTINUE, 0); - - return 0; -} - -static void -inf_ttrace_resume (struct target_ops *ops, - ptid_t ptid, int step, enum gdb_signal signal) -{ - int resume_all; - ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE; - int sig = gdb_signal_to_host (signal); - struct thread_info *info; - - /* A specific PTID means `step only this process id'. */ - resume_all = (ptid_equal (ptid, minus_one_ptid)); - - /* If resuming all threads, it's the current thread that should be - handled specially. */ - if (resume_all) - ptid = inferior_ptid; - - info = find_thread_ptid (ptid); - inf_ttrace_resume_lwp (info, request, sig); - - if (resume_all) - /* Let all the other threads run too. */ - iterate_over_threads (inf_ttrace_resume_callback, NULL); -} - -static ptid_t -inf_ttrace_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *ourstatus, int options) -{ - pid_t pid = ptid_get_pid (ptid); - lwpid_t lwpid = ptid_get_lwp (ptid); - ttstate_t tts; - struct thread_info *ti; - ptid_t related_ptid; - - /* Until proven otherwise. */ - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - - if (pid == -1) - pid = lwpid = 0; - - gdb_assert (pid != 0 || lwpid == 0); - - do - { - set_sigint_trap (); - - if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1) - perror_with_name (("ttrace_wait")); - - clear_sigint_trap (); - } - while (tts.tts_event == TTEVT_NONE); - - /* Now that we've waited, we can re-enable the page protections. */ - if (inf_ttrace_reenable_page_protections) - { - gdb_assert (inf_ttrace_num_lwps_in_syscall == 0); - inf_ttrace_enable_page_protections (tts.tts_pid); - inf_ttrace_reenable_page_protections = 0; - } - - ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - - if (inf_ttrace_num_lwps == 0) - { - struct thread_info *ti; - - inf_ttrace_num_lwps = 1; - - /* This is the earliest we hear about the lwp member of - INFERIOR_PTID, after an attach or fork_inferior. */ - gdb_assert (ptid_get_lwp (inferior_ptid) == 0); - - /* We haven't set the private member on the main thread yet. Do - it now. */ - ti = find_thread_ptid (inferior_ptid); - gdb_assert (ti != NULL && ti->priv == NULL); - ti->priv = - xmalloc (sizeof (struct inf_ttrace_private_thread_info)); - memset (ti->priv, 0, - sizeof (struct inf_ttrace_private_thread_info)); - - /* Notify the core that this ptid changed. This changes - inferior_ptid as well. */ - thread_change_ptid (inferior_ptid, ptid); - } - - switch (tts.tts_event) - { -#ifdef TTEVT_BPT_SSTEP - case TTEVT_BPT_SSTEP: - /* Make it look like a breakpoint. */ - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; -#endif - - case TTEVT_EXEC: - ourstatus->kind = TARGET_WAITKIND_EXECD; - ourstatus->value.execd_pathname = - xmalloc (tts.tts_u.tts_exec.tts_pathlen + 1); - if (ttrace (TT_PROC_GET_PATHNAME, tts.tts_pid, 0, - (uintptr_t)ourstatus->value.execd_pathname, - tts.tts_u.tts_exec.tts_pathlen, 0) == -1) - perror_with_name (("ttrace")); - ourstatus->value.execd_pathname[tts.tts_u.tts_exec.tts_pathlen] = 0; - - /* At this point, all inserted breakpoints are gone. Doing this - as soon as we detect an exec prevents the badness of deleting - a breakpoint writing the current "shadow contents" to lift - the bp. That shadow is NOT valid after an exec. */ - mark_breakpoints_out (); - break; - - case TTEVT_EXIT: - store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode); - inf_ttrace_num_lwps = 0; - break; - - case TTEVT_FORK: - related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid, - tts.tts_u.tts_fork.tts_flwpid, 0); - - ourstatus->kind = TARGET_WAITKIND_FORKED; - ourstatus->value.related_pid = related_ptid; - - /* Make sure the other end of the fork is stopped too. */ - if (ttrace_wait (tts.tts_u.tts_fork.tts_fpid, - tts.tts_u.tts_fork.tts_flwpid, - TTRACE_WAITOK, &tts, sizeof tts) == -1) - perror_with_name (("ttrace_wait")); - - gdb_assert (tts.tts_event == TTEVT_FORK); - if (tts.tts_u.tts_fork.tts_isparent) - { - related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid, - tts.tts_u.tts_fork.tts_flwpid, 0); - ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - ourstatus->value.related_pid = related_ptid; - } - break; - - case TTEVT_VFORK: - if (tts.tts_u.tts_fork.tts_isparent) - ourstatus->kind = TARGET_WAITKIND_VFORK_DONE; - else - { - related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid, - tts.tts_u.tts_fork.tts_flwpid, 0); - - ourstatus->kind = TARGET_WAITKIND_VFORKED; - ourstatus->value.related_pid = related_ptid; - } - break; - - case TTEVT_LWP_CREATE: - lwpid = tts.tts_u.tts_thread.tts_target_lwpid; - ptid = ptid_build (tts.tts_pid, lwpid, 0); - ti = add_thread (ptid); - ti->priv = - xmalloc (sizeof (struct inf_ttrace_private_thread_info)); - memset (ti->priv, 0, - sizeof (struct inf_ttrace_private_thread_info)); - inf_ttrace_num_lwps++; - ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - /* Let the lwp_create-caller thread continue. */ - ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), - ptid_get_lwp (ptid), TT_NOPC, 0, 0); - /* Return without stopping the whole process. */ - ourstatus->kind = TARGET_WAITKIND_IGNORE; - return ptid; - - case TTEVT_LWP_EXIT: - if (print_thread_events) - printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid)); - ti = find_thread_ptid (ptid); - gdb_assert (ti != NULL); - ((struct inf_ttrace_private_thread_info *)ti->priv)->dying = 1; - inf_ttrace_num_lwps--; - /* Let the thread really exit. */ - ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), - ptid_get_lwp (ptid), TT_NOPC, 0, 0); - /* Return without stopping the whole process. */ - ourstatus->kind = TARGET_WAITKIND_IGNORE; - return ptid; - - case TTEVT_LWP_TERMINATE: - lwpid = tts.tts_u.tts_thread.tts_target_lwpid; - ptid = ptid_build (tts.tts_pid, lwpid, 0); - if (print_thread_events) - printf_unfiltered(_("[%s has been terminated]\n"), - target_pid_to_str (ptid)); - ti = find_thread_ptid (ptid); - gdb_assert (ti != NULL); - ((struct inf_ttrace_private_thread_info *)ti->priv)->dying = 1; - inf_ttrace_num_lwps--; - - /* Resume the lwp_terminate-caller thread. */ - ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), - ptid_get_lwp (ptid), TT_NOPC, 0, 0); - /* Return without stopping the whole process. */ - ourstatus->kind = TARGET_WAITKIND_IGNORE; - return ptid; - - case TTEVT_SIGNAL: - ourstatus->kind = TARGET_WAITKIND_STOPPED; - ourstatus->value.sig = - gdb_signal_from_host (tts.tts_u.tts_signal.tts_signo); - break; - - case TTEVT_SYSCALL_ENTRY: - gdb_assert (inf_ttrace_reenable_page_protections == 0); - inf_ttrace_num_lwps_in_syscall++; - if (inf_ttrace_num_lwps_in_syscall == 1) - { - /* A thread has just entered a system call. Disable any - page protections as the kernel can't deal with them. */ - inf_ttrace_disable_page_protections (tts.tts_pid); - } - ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY; - ourstatus->value.syscall_number = tts.tts_scno; - break; - - case TTEVT_SYSCALL_RETURN: - if (inf_ttrace_num_lwps_in_syscall > 0) - { - /* If the last thread has just left the system call, this - would be a logical place to re-enable the page - protections, but that doesn't work. We can't re-enable - them until we've done another wait. */ - inf_ttrace_reenable_page_protections = - (inf_ttrace_num_lwps_in_syscall == 1); - inf_ttrace_num_lwps_in_syscall--; - } - ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN; - ourstatus->value.syscall_number = tts.tts_scno; - break; - - default: - gdb_assert (!"Unexpected ttrace event"); - break; - } - - /* Make sure all threads within the process are stopped. */ - if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1) - perror_with_name (("ttrace")); - - /* Now that the whole process is stopped, check if any dying thread - is really dead by now. If a dying thread is still alive, it will - be stopped too, and will still show up in `info threads', tagged - with "(Exiting)". We could make `info threads' prune dead - threads instead via inf_ttrace_thread_alive, but doing this here - has the advantage that a frontend is notificed sooner of thread - exits. Note that a dying lwp is still alive, it still has to be - resumed, like any other lwp. */ - iterate_over_threads (inf_ttrace_delete_dead_threads_callback, NULL); - - return ptid; -} - -/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF, - and transfer LEN bytes from WRITEBUF into the inferior's memory at - ADDR. Either READBUF or WRITEBUF may be null, in which case the - corresponding transfer doesn't happen. Return the number of bytes - actually transferred (which may be zero if an error occurs). */ - -static LONGEST -inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len, - void *readbuf, const void *writebuf) -{ - pid_t pid = ptid_get_pid (inferior_ptid); - - /* HP-UX treats text space and data space differently. GDB however, - doesn't really know the difference. Therefore we try both. Try - text space before data space though because when we're writing - into text space the instruction cache might need to be flushed. */ - - if (readbuf - && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1 - && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1) - return 0; - - if (writebuf - && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1 - && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1) - return 0; - - return len; -} - -static enum target_xfer_status -inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) -{ - switch (object) - { - case TARGET_OBJECT_MEMORY: - { - LONGEST val = inf_ttrace_xfer_memory (offset, len, readbuf, writebuf); - - if (val == 0) - return TARGET_XFER_EOF; - else - { - *xfered_len = (ULONGEST) val; - return TARGET_XFER_OK; - } - } - - case TARGET_OBJECT_UNWIND_TABLE: - return TARGET_XFER_E_IO; - - case TARGET_OBJECT_AUXV: - return TARGET_XFER_E_IO; - - case TARGET_OBJECT_WCOOKIE: - return TARGET_XFER_E_IO; - - default: - return TARGET_XFER_E_IO; - } -} - -/* Print status information about what we're accessing. */ - -static void -inf_ttrace_files_info (struct target_ops *ignore) -{ - struct inferior *inf = current_inferior (); - printf_filtered (_("\tUsing the running image of %s %s.\n"), - inf->attach_flag ? "attached" : "child", - target_pid_to_str (inferior_ptid)); -} - -static int -inf_ttrace_thread_alive (struct target_ops *ops, ptid_t ptid) -{ - return 1; -} - -/* Return a string describing the state of the thread specified by - INFO. */ - -static char * -inf_ttrace_extra_thread_info (struct target_ops *self, - struct thread_info *info) -{ - struct inf_ttrace_private_thread_info* priv = - (struct inf_ttrace_private_thread_info *) info->priv; - - if (priv != NULL && priv->dying) - return "Exiting"; - - return NULL; -} - -static char * -inf_ttrace_pid_to_str (struct target_ops *ops, ptid_t ptid) -{ - pid_t pid = ptid_get_pid (ptid); - lwpid_t lwpid = ptid_get_lwp (ptid); - static char buf[128]; - - if (lwpid == 0) - xsnprintf (buf, sizeof buf, "process %ld", - (long) pid); - else - xsnprintf (buf, sizeof buf, "process %ld, lwp %ld", - (long) pid, (long) lwpid); - return buf; -} - - -/* Implement the get_ada_task_ptid target_ops method. */ - -static ptid_t -inf_ttrace_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) -{ - return ptid_build (ptid_get_pid (inferior_ptid), lwp, 0); -} - - -struct target_ops * -inf_ttrace_target (void) -{ - struct target_ops *t = inf_child_target (); - - t->to_attach = inf_ttrace_attach; - t->to_detach = inf_ttrace_detach; - t->to_resume = inf_ttrace_resume; - t->to_wait = inf_ttrace_wait; - t->to_files_info = inf_ttrace_files_info; - t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint; - t->to_insert_watchpoint = inf_ttrace_insert_watchpoint; - t->to_remove_watchpoint = inf_ttrace_remove_watchpoint; - t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint; - t->to_region_ok_for_hw_watchpoint = - inf_ttrace_region_ok_for_hw_watchpoint; - t->to_kill = inf_ttrace_kill; - t->to_create_inferior = inf_ttrace_create_inferior; - t->to_follow_fork = inf_ttrace_follow_fork; - t->to_mourn_inferior = inf_ttrace_mourn_inferior; - t->to_thread_alive = inf_ttrace_thread_alive; - t->to_extra_thread_info = inf_ttrace_extra_thread_info; - t->to_pid_to_str = inf_ttrace_pid_to_str; - t->to_xfer_partial = inf_ttrace_xfer_partial; - t->to_get_ada_task_ptid = inf_ttrace_get_ada_task_ptid; - - return t; -} -#endif - - -/* Prevent warning from -Wmissing-prototypes. */ -void _initialize_inf_ttrace (void); - -void -_initialize_inf_ttrace (void) -{ -#ifdef HAVE_TTRACE - inf_ttrace_page_dict.pagesize = getpagesize(); -#endif -} diff --git a/gdb/inf-ttrace.h b/gdb/inf-ttrace.h deleted file mode 100644 index c762dd0..0000000 --- a/gdb/inf-ttrace.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Low-level child interface to ttrace. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef INF_TTRACE_H -#define INF_TTRACE_H - -/* Create a prototype ttrace target. The client can override it with - local methods. */ - -extern struct target_ops *inf_ttrace_target (void); - -#endif diff --git a/gdb/solib-ia64-hpux.c b/gdb/solib-ia64-hpux.c deleted file mode 100644 index b133c12..0000000 --- a/gdb/solib-ia64-hpux.c +++ /dev/null @@ -1,705 +0,0 @@ -/* Copyright (C) 2010-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "ia64-tdep.h" -#include "ia64-hpux-tdep.h" -#include "solib-ia64-hpux.h" -#include "solist.h" -#include "solib.h" -#include "target.h" -#include "gdbtypes.h" -#include "inferior.h" -#include "gdbcore.h" -#include "regcache.h" -#include "opcode/ia64.h" -#include "symfile.h" -#include "objfiles.h" -#include "elf-bfd.h" - -/* Need to define the following macro in order to get the complete - load_module_desc struct definition in dlfcn.h Otherwise, it doesn't - match the size of the struct the loader is providing us during load - events. */ -#define _LOAD_MODULE_DESC_EXT - -#include <sys/ttrace.h> -#include <dlfcn.h> -#include <elf.h> -#include <service_mgr.h> - -/* The following is to have access to the definition of type load_info_t. */ -#include <crt0.h> - -/* The r32 pseudo-register number. - - Like all stacked registers, r32 is treated as a pseudo-register, - because it is not always available for read/write via the ttrace - interface. */ -/* This is a bit of a hack, as we duplicate something hidden inside - ia64-tdep.c, but oh well... */ -#define IA64_R32_PSEUDO_REGNUM (IA64_NAT127_REGNUM + 2) - -/* Our struct so_list private data structure. */ - -struct lm_info -{ - /* The shared library module descriptor. We extract this structure - from the loader at the time the shared library gets mapped. */ - struct load_module_desc module_desc; - - /* The text segment address as defined in the shared library object - (this is not the address where this segment got loaded). This - field is initially set to zero, and computed lazily. */ - CORE_ADDR text_start; - - /* The data segment address as defined in the shared library object - (this is not the address where this segment got loaded). This - field is initially set to zero, and computed lazily. */ - CORE_ADDR data_start; -}; - -/* The list of shared libraries currently mapped by the inferior. */ - -static struct so_list *so_list_head = NULL; - -/* Create a new so_list element. The result should be deallocated - when no longer in use. */ - -static struct so_list * -new_so_list (char *so_name, struct load_module_desc module_desc) -{ - struct so_list *new_so; - - new_so = (struct so_list *) XCNEW (struct so_list); - new_so->lm_info = (struct lm_info *) XCNEW (struct lm_info); - new_so->lm_info->module_desc = module_desc; - - strncpy (new_so->so_name, so_name, SO_NAME_MAX_PATH_SIZE - 1); - new_so->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; - strcpy (new_so->so_original_name, new_so->so_name); - - return new_so; -} - -/* Return non-zero if the instruction at the current PC is a breakpoint - part of the dynamic loading process. - - We identify such instructions by checking that the instruction at - the current pc is a break insn where no software breakpoint has been - inserted by us. We also verify that the operands have specific - known values, to be extra certain. - - PTID is the ptid of the thread that should be checked, but this - function also assumes that inferior_ptid is already equal to PTID. - Ideally, we would like to avoid the requirement on inferior_ptid, - but many routines still use the inferior_ptid global to access - the relevant thread's register and memory. We still have the ptid - as parameter to be able to pass it to the routines that do take a ptid - - that way we avoid increasing explicit uses of the inferior_ptid - global. */ - -static int -ia64_hpux_at_dld_breakpoint_1_p (ptid_t ptid) -{ - struct regcache *regcache = get_thread_regcache (ptid); - CORE_ADDR pc = regcache_read_pc (regcache); - struct address_space *aspace = get_regcache_aspace (regcache); - ia64_insn t0, t1, slot[3], templ, insn; - int slotnum; - bfd_byte bundle[16]; - - /* If this is a regular breakpoint, then it can not be a dld one. */ - if (breakpoint_inserted_here_p (aspace, pc)) - return 0; - - slotnum = ((long) pc) & 0xf; - if (slotnum > 2) - internal_error (__FILE__, __LINE__, - "invalid slot (%d) for address %s", slotnum, - paddress (get_regcache_arch (regcache), pc)); - - pc -= (pc & 0xf); - read_memory (pc, bundle, sizeof (bundle)); - - /* bundles are always in little-endian byte order */ - t0 = bfd_getl64 (bundle); - t1 = bfd_getl64 (bundle + 8); - templ = (t0 >> 1) & 0xf; - slot[0] = (t0 >> 5) & 0x1ffffffffffLL; - slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18); - slot[2] = (t1 >> 23) & 0x1ffffffffffLL; - - if (templ == 2 && slotnum == 1) - { - /* skip L slot in MLI template: */ - slotnum = 2; - } - - insn = slot[slotnum]; - - return (insn == 0x1c0c9c0 /* break.i 0x070327 */ - || insn == 0x3c0c9c0); /* break.i 0x0f0327 */ -} - -/* Same as ia64_hpux_at_dld_breakpoint_1_p above, with the following - differences: It temporarily sets inferior_ptid to PTID, and also - contains any exception being raised. */ - -int -ia64_hpux_at_dld_breakpoint_p (ptid_t ptid) -{ - ptid_t saved_ptid = inferior_ptid; - int result = 0; - - inferior_ptid = ptid; - TRY - { - result = ia64_hpux_at_dld_breakpoint_1_p (ptid); - } - inferior_ptid = saved_ptid; - CATCH (e, RETURN_MASK_ALL) - { - warning (_("error while checking for dld breakpoint: %s"), e.message); - } - END_CATCH - - return result; -} - -/* Handler for library load event: Read the information provided by - the loader, and then use it to read the shared library symbols. */ - -static void -ia64_hpux_handle_load_event (struct regcache *regcache) -{ - CORE_ADDR module_desc_addr; - ULONGEST module_desc_size; - CORE_ADDR so_path_addr; - char so_path[PATH_MAX]; - struct load_module_desc module_desc; - struct so_list *new_so; - - /* Extract the data provided by the loader as follow: - - r33: Address of load_module_desc structure - - r34: size of struct load_module_desc - - r35: Address of string holding shared library path - */ - regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 1, - &module_desc_addr); - regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 2, - &module_desc_size); - regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 3, - &so_path_addr); - - if (module_desc_size != sizeof (struct load_module_desc)) - warning (_("load_module_desc size (%ld) != size returned by kernel (%s)"), - sizeof (struct load_module_desc), - pulongest (module_desc_size)); - - read_memory_string (so_path_addr, so_path, PATH_MAX); - read_memory (module_desc_addr, (gdb_byte *) &module_desc, - sizeof (module_desc)); - - /* Create a new so_list element and insert it at the start of our - so_list_head (we insert at the start of the list only because - it is less work compared to inserting it elsewhere). */ - new_so = new_so_list (so_path, module_desc); - new_so->next = so_list_head; - so_list_head = new_so; -} - -/* Update the value of the PC to point to the begining of the next - instruction bundle. */ - -static void -ia64_hpux_move_pc_to_next_bundle (struct regcache *regcache) -{ - CORE_ADDR pc = regcache_read_pc (regcache); - - pc -= pc & 0xf; - pc += 16; - ia64_write_pc (regcache, pc); -} - -/* Handle loader events. - - PTID is the ptid of the thread corresponding to the event being - handled. Similarly to ia64_hpux_at_dld_breakpoint_1_p, this - function assumes that inferior_ptid is set to PTID. */ - -static void -ia64_hpux_handle_dld_breakpoint_1 (ptid_t ptid) -{ - struct regcache *regcache = get_thread_regcache (ptid); - ULONGEST arg0; - - /* The type of event is provided by the loaded via r32. */ - regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM, &arg0); - switch (arg0) - { - case BREAK_DE_SVC_LOADED: - /* Currently, the only service loads are uld and dld, - so we shouldn't need to do anything. Just ignore. */ - break; - case BREAK_DE_LIB_LOADED: - ia64_hpux_handle_load_event (regcache); - solib_add (NULL, 0, ¤t_target, auto_solib_add); - break; - case BREAK_DE_LIB_UNLOADED: - case BREAK_DE_LOAD_COMPLETE: - case BREAK_DE_BOR: - /* Ignore for now. */ - break; - } - - /* Now that we have handled the event, we can move the PC to - the next instruction bundle, past the break instruction. */ - ia64_hpux_move_pc_to_next_bundle (regcache); -} - -/* Same as ia64_hpux_handle_dld_breakpoint_1 above, with the following - differences: This function temporarily sets inferior_ptid to PTID, - and also contains any exception. */ - -void -ia64_hpux_handle_dld_breakpoint (ptid_t ptid) -{ - ptid_t saved_ptid = inferior_ptid; - - inferior_ptid = ptid; - TRY - { - ia64_hpux_handle_dld_breakpoint_1 (ptid); - } - inferior_ptid = saved_ptid; - CATCH (e, RETURN_MASK_ALL) - { - warning (_("error detected while handling dld breakpoint: %s"), e.message); - } - END_CATCH -} - -/* Find the address of the code and data segments in ABFD, and update - TEXT_START and DATA_START accordingly. */ - -static void -ia64_hpux_find_start_vma (bfd *abfd, CORE_ADDR *text_start, - CORE_ADDR *data_start) -{ - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - Elf64_Phdr phdr; - int i; - - *text_start = 0; - *data_start = 0; - - if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1) - error (_("invalid program header offset in %s"), abfd->filename); - - for (i = 0; i < i_ehdrp->e_phnum; i++) - { - if (bfd_bread (&phdr, sizeof (phdr), abfd) != sizeof (phdr)) - error (_("failed to read segment %d in %s"), i, abfd->filename); - - if (phdr.p_flags & PF_X - && (*text_start == 0 || phdr.p_vaddr < *text_start)) - *text_start = phdr.p_vaddr; - - if (phdr.p_flags & PF_W - && (*data_start == 0 || phdr.p_vaddr < *data_start)) - *data_start = phdr.p_vaddr; - } -} - -/* The "relocate_section_addresses" target_so_ops routine for ia64-hpux. */ - -static void -ia64_hpux_relocate_section_addresses (struct so_list *so, - struct target_section *sec) -{ - CORE_ADDR offset = 0; - - /* If we haven't computed the text & data segment addresses, do so now. - We do this here, because we now have direct access to the associated - bfd, whereas we would have had to open our own if we wanted to do it - while processing the library-load event. */ - if (so->lm_info->text_start == 0 && so->lm_info->data_start == 0) - ia64_hpux_find_start_vma (sec->the_bfd_section->owner, - &so->lm_info->text_start, - &so->lm_info->data_start); - - /* Determine the relocation offset based on which segment - the section belongs to. */ - if ((so->lm_info->text_start < so->lm_info->data_start - && sec->addr < so->lm_info->data_start) - || (so->lm_info->text_start > so->lm_info->data_start - && sec->addr >= so->lm_info->text_start)) - offset = so->lm_info->module_desc.text_base - so->lm_info->text_start; - else if ((so->lm_info->text_start < so->lm_info->data_start - && sec->addr >= so->lm_info->data_start) - || (so->lm_info->text_start > so->lm_info->data_start - && sec->addr < so->lm_info->text_start)) - offset = so->lm_info->module_desc.data_base - so->lm_info->data_start; - - /* And now apply the relocation. */ - sec->addr += offset; - sec->endaddr += offset; - - /* Best effort to set addr_high/addr_low. This is used only by - 'info sharedlibrary'. */ - if (so->addr_low == 0 || sec->addr < so->addr_low) - so->addr_low = sec->addr; - - if (so->addr_high == 0 || sec->endaddr > so->addr_high) - so->addr_high = sec->endaddr; -} - -/* The "free_so" target_so_ops routine for ia64-hpux. */ - -static void -ia64_hpux_free_so (struct so_list *so) -{ - xfree (so->lm_info); -} - -/* The "clear_solib" target_so_ops routine for ia64-hpux. */ - -static void -ia64_hpux_clear_solib (void) -{ - struct so_list *so; - - while (so_list_head != NULL) - { - so = so_list_head; - so_list_head = so_list_head->next; - - ia64_hpux_free_so (so); - xfree (so); - } -} - -/* Assuming the inferior just stopped on an EXEC event, return - the address of the load_info_t structure. */ - -static CORE_ADDR -ia64_hpux_get_load_info_addr (void) -{ - struct type *data_ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; - CORE_ADDR addr; - int status; - - /* The address of the load_info_t structure is stored in the 4th - argument passed to the initial thread of the process (in other - words, in argv[3]). So get the address of these arguments, - and extract the 4th one. */ - status = ttrace (TT_PROC_GET_ARGS, ptid_get_pid (inferior_ptid), - 0, (uintptr_t) &addr, sizeof (CORE_ADDR), 0); - if (status == -1 && errno) - perror_with_name (_("Unable to get argument list")); - return (read_memory_typed_address (addr + 3 * 8, data_ptr_type)); -} - -/* A structure used to aggregate some information extracted from - the dynamic section of the main executable. */ - -struct dld_info -{ - ULONGEST dld_flags; - CORE_ADDR load_map; -}; - -/* Scan the ".dynamic" section referenced by ABFD and DYN_SECT, - and extract the information needed to fill in INFO. */ - -static void -ia64_hpux_read_dynamic_info (struct gdbarch *gdbarch, bfd *abfd, - asection *dyn_sect, struct dld_info *info) -{ - int sect_size; - char *buf; - char *buf_end; - - /* Make sure that info always has initialized data, even if we fail - to read the syn_sect section. */ - memset (info, 0, sizeof (struct dld_info)); - - sect_size = bfd_section_size (abfd, dyn_sect); - buf = alloca (sect_size); - buf_end = buf + sect_size; - - if (bfd_seek (abfd, dyn_sect->filepos, SEEK_SET) != 0 - || bfd_bread (buf, sect_size, abfd) != sect_size) - error (_("failed to read contents of .dynamic section")); - - for (; buf < buf_end; buf += sizeof (Elf64_Dyn)) - { - Elf64_Dyn *dynp = (Elf64_Dyn *) buf; - Elf64_Sxword d_tag; - - d_tag = bfd_h_get_64 (abfd, &dynp->d_tag); - switch (d_tag) - { - case DT_HP_DLD_FLAGS: - info->dld_flags = bfd_h_get_64 (abfd, &dynp->d_un); - break; - - case DT_HP_LOAD_MAP: - { - CORE_ADDR load_map_addr = bfd_h_get_64 (abfd, &dynp->d_un.d_ptr); - - if (target_read_memory (load_map_addr, - (gdb_byte *) &info->load_map, - sizeof (info->load_map)) != 0) - error (_("failed to read load map at %s"), - paddress (gdbarch, load_map_addr)); - } - break; - } - } -} - -/* Wrapper around target_read_memory used with libdl. */ - -static void * -ia64_hpux_read_tgt_mem (void *buffer, uint64_t ptr, size_t bufsiz, int ident) -{ - if (target_read_memory (ptr, (gdb_byte *) buffer, bufsiz) != 0) - return 0; - else - return buffer; -} - -/* Create a new so_list object for a shared library, and store that - new so_list object in our SO_LIST_HEAD list. - - SO_INDEX is an index specifying the placement of the loaded shared - library in the dynamic loader's search list. Normally, this index - is strictly positive, but an index of -1 refers to the loader itself. - - Return nonzero if the so_list object could be created. A null - return value with a positive SO_INDEX normally means that there are - no more entries in the dynamic loader's search list at SO_INDEX or - beyond. */ - -static int -ia64_hpux_add_so_from_dld_info (struct dld_info info, int so_index) -{ - struct load_module_desc module_desc; - uint64_t so_handle; - char *so_path; - struct so_list *so; - - so_handle = dlgetmodinfo (so_index, &module_desc, sizeof (module_desc), - ia64_hpux_read_tgt_mem, 0, info.load_map); - - if (so_handle == 0) - /* No such entry. We probably reached the end of the list. */ - return 0; - - so_path = dlgetname (&module_desc, sizeof (module_desc), - ia64_hpux_read_tgt_mem, 0, info.load_map); - if (so_path == NULL) - { - /* Should never happen, but let's not crash if it does. */ - warning (_("unable to get shared library name, symbols not loaded")); - return 0; - } - - /* Create a new so_list and insert it at the start of our list. - The order is not extremely important, but it's less work to do so - at the end of the list. */ - so = new_so_list (so_path, module_desc); - so->next = so_list_head; - so_list_head = so; - - return 1; -} - -/* Assuming we just attached to a process, update our list of shared - libraries (SO_LIST_HEAD) as well as GDB's list. */ - -static void -ia64_hpux_solib_add_after_attach (void) -{ - bfd *abfd; - asection *dyn_sect; - struct dld_info info; - int i; - - if (symfile_objfile == NULL) - return; - - abfd = symfile_objfile->obfd; - dyn_sect = bfd_get_section_by_name (abfd, ".dynamic"); - - if (dyn_sect == NULL || bfd_section_size (abfd, dyn_sect) == 0) - return; - - ia64_hpux_read_dynamic_info (get_objfile_arch (symfile_objfile), abfd, - dyn_sect, &info); - - if ((info.dld_flags & DT_HP_DEBUG_PRIVATE) == 0) - { - warning (_( -"The shared libraries were not privately mapped; setting a breakpoint\n\ -in a shared library will not work until you rerun the program.\n\ -Use the following command to enable debugging of shared libraries.\n\ -chatr +dbg enable a.out")); - } - - /* Read the symbols of the dynamic loader (dld.so). */ - ia64_hpux_add_so_from_dld_info (info, -1); - - /* Read the symbols of all the other shared libraries. */ - for (i = 1; ; i++) - if (!ia64_hpux_add_so_from_dld_info (info, i)) - break; /* End of list. */ - - /* Resync the library list at the core level. */ - solib_add (NULL, 1, ¤t_target, auto_solib_add); -} - -/* The "create_inferior_hook" target_so_ops routine for ia64-hpux. */ - -static void -ia64_hpux_solib_create_inferior_hook (int from_tty) -{ - CORE_ADDR load_info_addr; - load_info_t load_info; - - /* Initially, we were thinking about adding a check that the program - (accessible through symfile_objfile) was linked against some shared - libraries, by searching for a ".dynamic" section. However, could - this break in the case of a statically linked program that later - uses dlopen? Programs that are fully statically linked are very - rare, and we will worry about them when we encounter one that - causes trouble. */ - - /* Set the LI_TRACE flag in the load_info_t structure. This enables - notifications when shared libraries are being mapped. */ - load_info_addr = ia64_hpux_get_load_info_addr (); - read_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info)); - load_info.li_flags |= LI_TRACE; - write_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info)); - - /* If we just attached to our process, some shard libraries have - already been mapped. Find which ones they are... */ - if (current_inferior ()->attach_flag) - ia64_hpux_solib_add_after_attach (); -} - -/* The "special_symbol_handling" target_so_ops routine for ia64-hpux. */ - -static void -ia64_hpux_special_symbol_handling (void) -{ - /* Nothing to do. */ -} - -/* The "current_sos" target_so_ops routine for ia64-hpux. */ - -static struct so_list * -ia64_hpux_current_sos (void) -{ - /* Return a deep copy of our own list. */ - struct so_list *new_head = NULL, *prev_new_so = NULL; - struct so_list *our_so; - - for (our_so = so_list_head; our_so != NULL; our_so = our_so->next) - { - struct so_list *new_so; - - new_so = new_so_list (our_so->so_name, our_so->lm_info->module_desc); - if (prev_new_so != NULL) - prev_new_so->next = new_so; - prev_new_so = new_so; - if (new_head == NULL) - new_head = new_so; - } - - return new_head; -} - -/* The "open_symbol_file_object" target_so_ops routine for ia64-hpux. */ - -static int -ia64_hpux_open_symbol_file_object (void *from_ttyp) -{ - return 0; -} - -/* The "in_dynsym_resolve_code" target_so_ops routine for ia64-hpux. */ - -static int -ia64_hpux_in_dynsym_resolve_code (CORE_ADDR pc) -{ - return 0; -} - -/* If FADDR is the address of a function inside one of the shared - libraries, return the shared library linkage address. */ - -CORE_ADDR -ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr) -{ - struct so_list *so = so_list_head; - - while (so != NULL) - { - struct load_module_desc module_desc = so->lm_info->module_desc; - - if (module_desc.text_base <= faddr - && (module_desc.text_base + module_desc.text_size) > faddr) - return module_desc.linkage_ptr; - - so = so->next; - } - - return 0; -} - -/* Create a new target_so_ops structure suitable for ia64-hpux, and - return its address. */ - -static struct target_so_ops * -ia64_hpux_target_so_ops (void) -{ - struct target_so_ops *ops = XCNEW (struct target_so_ops); - - ops->relocate_section_addresses = ia64_hpux_relocate_section_addresses; - ops->free_so = ia64_hpux_free_so; - ops->clear_solib = ia64_hpux_clear_solib; - ops->solib_create_inferior_hook = ia64_hpux_solib_create_inferior_hook; - ops->special_symbol_handling = ia64_hpux_special_symbol_handling; - ops->current_sos = ia64_hpux_current_sos; - ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object; - ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code; - ops->bfd_open = solib_bfd_open; - - return ops; -} - -/* Prevent warning from -Wmissing-prototypes. */ -void _initialize_solib_ia64_hpux (void); - -void -_initialize_solib_ia64_hpux (void) -{ - ia64_hpux_so_ops = ia64_hpux_target_so_ops (); -} diff --git a/gdb/solib-ia64-hpux.h b/gdb/solib-ia64-hpux.h deleted file mode 100644 index b550fd0..0000000 --- a/gdb/solib-ia64-hpux.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (C) 2010-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef SOLIB_IA64_HPUX_H -#define SOLIB_IA64_HPUX_H - -int ia64_hpux_at_dld_breakpoint_p (ptid_t ptid); -void ia64_hpux_handle_dld_breakpoint (ptid_t ptid); -CORE_ADDR ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr); - -#endif diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c deleted file mode 100644 index a176aab..0000000 --- a/gdb/solib-pa64.c +++ /dev/null @@ -1,654 +0,0 @@ -/* Handle PA64 shared libraries for GDB, the GNU Debugger. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* HP in their infinite stupidity choose not to use standard ELF dynamic - linker interfaces. They also choose not to make their ELF dymamic - linker interfaces compatible with the SOM dynamic linker. The - net result is we can not use either of the existing somsolib.c or - solib.c. What a crock. - - Even more disgusting. This file depends on functions provided only - in certain PA64 libraries. Thus this file is supposed to only be - used native. When will HP ever learn that they need to provide the - same functionality in all their libraries! */ - -#include "defs.h" -#include "symtab.h" -#include "bfd.h" -#include "symfile.h" -#include "objfiles.h" -#include "gdbcore.h" -#include "target.h" -#include "inferior.h" -#include "regcache.h" -#include "gdb_bfd.h" - -#include "hppa-tdep.h" -#include "solist.h" -#include "solib.h" -#include "solib-pa64.h" - -#undef SOLIB_PA64_DBG - -/* We can build this file only when running natively on 64-bit HP/UX. - We check for that by checking for the elf_hp.h header file. */ -#if defined(HAVE_ELF_HP_H) && defined(__LP64__) - -/* FIXME: kettenis/20041213: These includes should be eliminated. */ -#include <dlfcn.h> -#include <elf.h> -#include <elf_hp.h> - -struct lm_info { - struct load_module_desc desc; - CORE_ADDR desc_addr; -}; - -/* When adding fields, be sure to clear them in _initialize_pa64_solib. */ -typedef struct - { - CORE_ADDR dld_flags_addr; - LONGEST dld_flags; - struct bfd_section *dyninfo_sect; - int have_read_dld_descriptor; - int is_valid; - CORE_ADDR load_map; - CORE_ADDR load_map_addr; - struct load_module_desc dld_desc; - } -dld_cache_t; - -static dld_cache_t dld_cache; - -static int read_dynamic_info (asection *dyninfo_sect, - dld_cache_t *dld_cache_p); - -static void -pa64_relocate_section_addresses (struct so_list *so, - struct target_section *sec) -{ - asection *asec = sec->the_bfd_section; - CORE_ADDR load_offset; - - /* Relocate all the sections based on where they got loaded. */ - - load_offset = bfd_section_vma (so->abfd, asec) - asec->filepos; - - if (asec->flags & SEC_CODE) - { - sec->addr += so->lm_info->desc.text_base - load_offset; - sec->endaddr += so->lm_info->desc.text_base - load_offset; - } - else if (asec->flags & SEC_DATA) - { - sec->addr += so->lm_info->desc.data_base - load_offset; - sec->endaddr += so->lm_info->desc.data_base - load_offset; - } -} - -static void -pa64_free_so (struct so_list *so) -{ - xfree (so->lm_info); -} - -static void -pa64_clear_solib (void) -{ -} - -/* Wrapper for target_read_memory for dlgetmodinfo. */ - -static void * -pa64_target_read_memory (void *buffer, CORE_ADDR ptr, size_t bufsiz, int ident) -{ - if (target_read_memory (ptr, buffer, bufsiz) != 0) - return 0; - return buffer; -} - -/* Read the dynamic linker's internal shared library descriptor. - - This must happen after dld starts running, so we can't do it in - read_dynamic_info. Record the fact that we have loaded the - descriptor. If the library is archive bound or the load map - hasn't been setup, then return zero; else return nonzero. */ - -static int -read_dld_descriptor (void) -{ - char *dll_path; - asection *dyninfo_sect; - - /* If necessary call read_dynamic_info to extract the contents of the - .dynamic section from the shared library. */ - if (!dld_cache.is_valid) - { - if (symfile_objfile == NULL) - error (_("No object file symbols.")); - - dyninfo_sect = bfd_get_section_by_name (symfile_objfile->obfd, - ".dynamic"); - if (!dyninfo_sect) - { - return 0; - } - - if (!read_dynamic_info (dyninfo_sect, &dld_cache)) - error (_("Unable to read in .dynamic section information.")); - } - - /* Read the load map pointer. */ - if (target_read_memory (dld_cache.load_map_addr, - (char *) &dld_cache.load_map, - sizeof (dld_cache.load_map)) - != 0) - { - error (_("Error while reading in load map pointer.")); - } - - if (!dld_cache.load_map) - return 0; - - /* Read in the dld load module descriptor. */ - if (dlgetmodinfo (-1, - &dld_cache.dld_desc, - sizeof (dld_cache.dld_desc), - pa64_target_read_memory, - 0, - dld_cache.load_map) - == 0) - { - error (_("Error trying to get information about dynamic linker.")); - } - - /* Indicate that we have loaded the dld descriptor. */ - dld_cache.have_read_dld_descriptor = 1; - - return 1; -} - - -/* Read the .dynamic section and extract the information of interest, - which is stored in dld_cache. The routine elf_locate_base in solib.c - was used as a model for this. */ - -static int -read_dynamic_info (asection *dyninfo_sect, dld_cache_t *dld_cache_p) -{ - char *buf; - char *bufend; - CORE_ADDR dyninfo_addr; - int dyninfo_sect_size; - CORE_ADDR entry_addr; - - /* Read in .dynamic section, silently ignore errors. */ - dyninfo_addr = bfd_section_vma (symfile_objfile->obfd, dyninfo_sect); - dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect); - buf = alloca (dyninfo_sect_size); - if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) - return 0; - - /* Scan the .dynamic section and record the items of interest. - In particular, DT_HP_DLD_FLAGS. */ - for (bufend = buf + dyninfo_sect_size, entry_addr = dyninfo_addr; - buf < bufend; - buf += sizeof (Elf64_Dyn), entry_addr += sizeof (Elf64_Dyn)) - { - Elf64_Dyn *x_dynp = (Elf64_Dyn*)buf; - Elf64_Sxword dyn_tag; - CORE_ADDR dyn_ptr; - - dyn_tag = bfd_h_get_64 (symfile_objfile->obfd, - (bfd_byte*) &x_dynp->d_tag); - - /* We can't use a switch here because dyn_tag is 64 bits and HP's - lame comiler does not handle 64bit items in switch statements. */ - if (dyn_tag == DT_NULL) - break; - else if (dyn_tag == DT_HP_DLD_FLAGS) - { - /* Set dld_flags_addr and dld_flags in *dld_cache_p. */ - dld_cache_p->dld_flags_addr = entry_addr + offsetof(Elf64_Dyn, d_un); - if (target_read_memory (dld_cache_p->dld_flags_addr, - (char*) &dld_cache_p->dld_flags, - sizeof (dld_cache_p->dld_flags)) - != 0) - { - error (_("Error while reading in " - ".dynamic section of the program.")); - } - } - else if (dyn_tag == DT_HP_LOAD_MAP) - { - /* Dld will place the address of the load map at load_map_addr - after it starts running. */ - if (target_read_memory (entry_addr + offsetof(Elf64_Dyn, - d_un.d_ptr), - (char*) &dld_cache_p->load_map_addr, - sizeof (dld_cache_p->load_map_addr)) - != 0) - { - error (_("Error while reading in " - ".dynamic section of the program.")); - } - } - else - { - /* Tag is not of interest. */ - } - } - - /* Record other information and set is_valid to 1. */ - dld_cache_p->dyninfo_sect = dyninfo_sect; - - /* Verify that we read in required info. These fields are re-set to zero - in pa64_solib_restart. */ - - if (dld_cache_p->dld_flags_addr != 0 && dld_cache_p->load_map_addr != 0) - dld_cache_p->is_valid = 1; - else - return 0; - - return 1; -} - -/* Helper function for gdb_bfd_lookup_symbol_from_symtab. */ - -static int -cmp_name (asymbol *sym, void *data) -{ - return (strcmp (sym->name, (const char *) data) == 0); -} - -/* This hook gets called just before the first instruction in the - inferior process is executed. - - This is our opportunity to set magic flags in the inferior so - that GDB can be notified when a shared library is mapped in and - to tell the dynamic linker that a private copy of the library is - needed (so GDB can set breakpoints in the library). - - We need to set DT_HP_DEBUG_CALLBACK to indicate that we want the - dynamic linker to call the breakpoint routine for significant events. - We used to set DT_HP_DEBUG_PRIVATE to indicate that shared libraries - should be mapped private. However, this flag can be set using - "chatr +dbg enable". Not setting DT_HP_DEBUG_PRIVATE allows debugging - with shared libraries mapped shareable. */ - -static void -pa64_solib_create_inferior_hook (int from_tty) -{ - struct minimal_symbol *msymbol; - unsigned int dld_flags, status; - asection *shlib_info, *interp_sect; - struct objfile *objfile; - CORE_ADDR anaddr; - - if (symfile_objfile == NULL) - return; - - /* First see if the objfile was dynamically linked. */ - shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, ".dynamic"); - if (!shlib_info) - return; - - /* It's got a .dynamic section, make sure it's not empty. */ - if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0) - return; - - /* Read in the .dynamic section. */ - if (! read_dynamic_info (shlib_info, &dld_cache)) - error (_("Unable to read the .dynamic section.")); - - /* If the libraries were not mapped private, warn the user. */ - if ((dld_cache.dld_flags & DT_HP_DEBUG_PRIVATE) == 0) - warning - (_("\ -Private mapping of shared library text was not specified\n\ -by the executable; setting a breakpoint in a shared library which\n\ -is not privately mapped will not work. See the HP-UX 11i v3 chatr\n\ -manpage for methods to privately map shared library text.")); - - /* Turn on the flags we care about. */ - dld_cache.dld_flags |= DT_HP_DEBUG_CALLBACK; - status = target_write_memory (dld_cache.dld_flags_addr, - (char *) &dld_cache.dld_flags, - sizeof (dld_cache.dld_flags)); - if (status != 0) - error (_("Unable to modify dynamic linker flags.")); - - /* Now we have to create a shared library breakpoint in the dynamic - linker. This can be somewhat tricky since the symbol is inside - the dynamic linker (for which we do not have symbols or a base - load address! Luckily I wrote this code for solib.c years ago. */ - interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); - if (interp_sect) - { - unsigned int interp_sect_size; - char *buf; - CORE_ADDR load_addr; - bfd *tmp_bfd; - CORE_ADDR sym_addr = 0; - - /* Read the contents of the .interp section into a local buffer; - the contents specify the dynamic linker this program uses. */ - interp_sect_size = bfd_section_size (exec_bfd, interp_sect); - buf = alloca (interp_sect_size); - bfd_get_section_contents (exec_bfd, interp_sect, - buf, 0, interp_sect_size); - - /* Now we need to figure out where the dynamic linker was - loaded so that we can load its symbols and place a breakpoint - in the dynamic linker itself. - - This address is stored on the stack. However, I've been unable - to find any magic formula to find it for Solaris (appears to - be trivial on GNU/Linux). Therefore, we have to try an alternate - mechanism to find the dynamic linker's base address. */ - tmp_bfd = gdb_bfd_open (buf, gnutarget, -1); - if (tmp_bfd == NULL) - return; - - /* Make sure the dynamic linker's really a useful object. */ - if (!bfd_check_format (tmp_bfd, bfd_object)) - { - warning (_("Unable to grok dynamic linker %s as an object file"), - buf); - gdb_bfd_unref (tmp_bfd); - return; - } - - /* We find the dynamic linker's base address by examining the - current pc (which point at the entry point for the dynamic - linker) and subtracting the offset of the entry point. - - Also note the breakpoint is the second instruction in the - routine. */ - load_addr = regcache_read_pc (get_current_regcache ()) - - tmp_bfd->start_address; - sym_addr = gdb_bfd_lookup_symbol_from_symtab (tmp_bfd, cmp_name, - "__dld_break"); - sym_addr = load_addr + sym_addr + 4; - - /* Create the shared library breakpoint. */ - { - struct breakpoint *b - = create_solib_event_breakpoint (target_gdbarch (), sym_addr); - - /* The breakpoint is actually hard-coded into the dynamic linker, - so we don't need to actually insert a breakpoint instruction - there. In fact, the dynamic linker's code is immutable, even to - ttrace, so we shouldn't even try to do that. For cases like - this, we have "permanent" breakpoints. */ - make_breakpoint_permanent (b); - } - - /* We're done with the temporary bfd. */ - gdb_bfd_unref (tmp_bfd); - } -} - -static void -pa64_special_symbol_handling (void) -{ -} - -static struct so_list * -pa64_current_sos (void) -{ - struct so_list *head = 0; - struct so_list **link_ptr = &head; - int dll_index; - - /* Read in the load map pointer if we have not done so already. */ - if (! dld_cache.have_read_dld_descriptor) - if (! read_dld_descriptor ()) - return NULL; - - for (dll_index = -1; ; dll_index++) - { - struct load_module_desc dll_desc; - char *dll_path; - struct so_list *newobj; - struct cleanup *old_chain; - - if (dll_index == 0) - continue; - - /* Read in the load module descriptor. */ - if (dlgetmodinfo (dll_index, &dll_desc, sizeof (dll_desc), - pa64_target_read_memory, 0, dld_cache.load_map) - == 0) - break; - - /* Get the name of the shared library. */ - dll_path = (char *)dlgetname (&dll_desc, sizeof (dll_desc), - pa64_target_read_memory, - 0, dld_cache.load_map); - - newobj = (struct so_list *) xmalloc (sizeof (struct so_list)); - memset (newobj, 0, sizeof (struct so_list)); - newobj->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); - memset (newobj->lm_info, 0, sizeof (struct lm_info)); - - strncpy (newobj->so_name, dll_path, SO_NAME_MAX_PATH_SIZE - 1); - newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; - strcpy (newobj->so_original_name, newobj->so_name); - - memcpy (&newobj->lm_info->desc, &dll_desc, sizeof (dll_desc)); - -#ifdef SOLIB_PA64_DBG - { - struct load_module_desc *d = &newobj->lm_info->desc; - - printf ("\n+ library \"%s\" is described at index %d\n", newobj->so_name, - dll_index); - printf (" text_base = %s\n", hex_string (d->text_base)); - printf (" text_size = %s\n", hex_string (d->text_size)); - printf (" data_base = %s\n", hex_string (d->data_base)); - printf (" data_size = %s\n", hex_string (d->data_size)); - printf (" unwind_base = %s\n", hex_string (d->unwind_base)); - printf (" linkage_ptr = %s\n", hex_string (d->linkage_ptr)); - printf (" phdr_base = %s\n", hex_string (d->phdr_base)); - printf (" tls_size = %s\n", hex_string (d->tls_size)); - printf (" tls_start_addr = %s\n", hex_string (d->tls_start_addr)); - printf (" unwind_size = %s\n", hex_string (d->unwind_size)); - printf (" tls_index = %s\n", hex_string (d->tls_index)); - } -#endif - - /* Link the new object onto the list. */ - newobj->next = NULL; - *link_ptr = newobj; - link_ptr = &newobj->next; - } - - return head; -} - -static int -pa64_open_symbol_file_object (void *from_ttyp) -{ - int from_tty = *(int *)from_ttyp; - struct load_module_desc dll_desc; - char *dll_path; - - if (symfile_objfile) - if (!query (_("Attempt to reload symbols from process? "))) - return 0; - - /* Read in the load map pointer if we have not done so already. */ - if (! dld_cache.have_read_dld_descriptor) - if (! read_dld_descriptor ()) - return 0; - - /* Read in the load module descriptor. */ - if (dlgetmodinfo (0, &dll_desc, sizeof (dll_desc), - pa64_target_read_memory, 0, dld_cache.load_map) == 0) - return 0; - - /* Get the name of the shared library. */ - dll_path = (char *)dlgetname (&dll_desc, sizeof (dll_desc), - pa64_target_read_memory, - 0, dld_cache.load_map); - - /* Have a pathname: read the symbol file. */ - symbol_file_add_main (dll_path, from_tty); - - return 1; -} - -/* Return nonzero if PC is an address inside the dynamic linker. */ -static int -pa64_in_dynsym_resolve_code (CORE_ADDR pc) -{ - asection *shlib_info; - - if (symfile_objfile == NULL) - return 0; - - if (!dld_cache.have_read_dld_descriptor) - if (!read_dld_descriptor ()) - return 0; - - return (pc >= dld_cache.dld_desc.text_base - && pc < dld_cache.dld_desc.text_base + dld_cache.dld_desc.text_size); -} - - -/* Return the GOT value for the shared library in which ADDR belongs. If - ADDR isn't in any known shared library, return zero. */ - -static CORE_ADDR -pa64_solib_get_got_by_pc (CORE_ADDR addr) -{ - struct so_list *so_list = master_so_list (); - CORE_ADDR got_value = 0; - - while (so_list) - { - if (so_list->lm_info->desc.text_base <= addr - && ((so_list->lm_info->desc.text_base - + so_list->lm_info->desc.text_size) - > addr)) - { - got_value = so_list->lm_info->desc.linkage_ptr; - break; - } - so_list = so_list->next; - } - return got_value; -} - -/* Get some HPUX-specific data from a shared lib. */ -static CORE_ADDR -pa64_solib_thread_start_addr (struct so_list *so) -{ - return so->lm_info->desc.tls_start_addr; -} - - -/* Return the address of the handle of the shared library in which ADDR - belongs. If ADDR isn't in any known shared library, return zero. */ - -static CORE_ADDR -pa64_solib_get_solib_by_pc (CORE_ADDR addr) -{ - struct so_list *so_list = master_so_list (); - CORE_ADDR retval = 0; - - while (so_list) - { - if (so_list->lm_info->desc.text_base <= addr - && ((so_list->lm_info->desc.text_base - + so_list->lm_info->desc.text_size) - > addr)) - { - retval = so_list->lm_info->desc_addr; - break; - } - so_list = so_list->next; - } - return retval; -} - -/* pa64 libraries do not seem to set the section offsets in a standard (i.e. - SVr4) way; the text section offset stored in the file doesn't correspond - to the place where the library is actually loaded into memory. Instead, - we rely on the dll descriptor to tell us where things were loaded. */ -static CORE_ADDR -pa64_solib_get_text_base (struct objfile *objfile) -{ - struct so_list *so; - - for (so = master_so_list (); so; so = so->next) - if (so->objfile == objfile) - return so->lm_info->desc.text_base; - - return 0; -} - -static struct target_so_ops pa64_so_ops; - -extern initialize_file_ftype _initialize_pa64_solib; /* -Wmissing-prototypes */ - -void -_initialize_pa64_solib (void) -{ - pa64_so_ops.relocate_section_addresses = pa64_relocate_section_addresses; - pa64_so_ops.free_so = pa64_free_so; - pa64_so_ops.clear_solib = pa64_clear_solib; - pa64_so_ops.solib_create_inferior_hook = pa64_solib_create_inferior_hook; - pa64_so_ops.special_symbol_handling = pa64_special_symbol_handling; - pa64_so_ops.current_sos = pa64_current_sos; - pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object; - pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code; - pa64_so_ops.bfd_open = solib_bfd_open; - - memset (&dld_cache, 0, sizeof (dld_cache)); -} - -void pa64_solib_select (struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - set_solib_ops (gdbarch, &pa64_so_ops); - tdep->solib_thread_start_addr = pa64_solib_thread_start_addr; - tdep->solib_get_got_by_pc = pa64_solib_get_got_by_pc; - tdep->solib_get_solib_by_pc = pa64_solib_get_solib_by_pc; - tdep->solib_get_text_base = pa64_solib_get_text_base; -} - -#else /* HAVE_ELF_HP_H */ - -extern initialize_file_ftype _initialize_pa64_solib; /* -Wmissing-prototypes */ - -void -_initialize_pa64_solib (void) -{ -} - -void pa64_solib_select (struct gdbarch *gdbarch) -{ - /* For a SOM-only target, there is no pa64 solib support. This is needed - for hppa-hpux-tdep.c to build. */ - error (_("Cannot select pa64 solib support for this configuration.")); -} -#endif diff --git a/gdb/solib-pa64.h b/gdb/solib-pa64.h deleted file mode 100644 index 9784c41..0000000 --- a/gdb/solib-pa64.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Handle PA64 shared libraries for GDB, the GNU Debugger. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef SOLIB_PA64_H -#define SOLIB_PA64_H - -void pa64_solib_select (struct gdbarch *gdbarch); - -#endif diff --git a/gdb/solib-som.c b/gdb/solib-som.c deleted file mode 100644 index 27e39a7..0000000 --- a/gdb/solib-som.c +++ /dev/null @@ -1,891 +0,0 @@ -/* Handle SOM shared libraries. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "symtab.h" -#include "bfd.h" -#include "symfile.h" -#include "objfiles.h" -#include "gdbcore.h" -#include "target.h" -#include "inferior.h" - -#include "hppa-tdep.h" -#include "solist.h" -#include "solib.h" -#include "solib-som.h" - -#undef SOLIB_SOM_DBG - -/* These ought to be defined in some public interface, but aren't. They - define the meaning of the various bits in the distinguished __dld_flags - variable that is declared in every debuggable a.out on HP-UX, and that - is shared between the debugger and the dynamic linker. */ - -#define DLD_FLAGS_MAPPRIVATE 0x1 -#define DLD_FLAGS_HOOKVALID 0x2 -#define DLD_FLAGS_LISTVALID 0x4 -#define DLD_FLAGS_BOR_ENABLE 0x8 - -struct lm_info - { - /* Version of this structure (it is expected to change again in - hpux10). */ - unsigned char struct_version; - - /* Binding mode for this library. */ - unsigned char bind_mode; - - /* Version of this library. */ - short library_version; - - /* Start of text address, - link-time text location (length of text area), - end of text address. */ - CORE_ADDR text_addr; - CORE_ADDR text_link_addr; - CORE_ADDR text_end; - - /* Start of data, start of bss and end of data. */ - CORE_ADDR data_start; - CORE_ADDR bss_start; - CORE_ADDR data_end; - - /* Value of linkage pointer (%r19). */ - CORE_ADDR got_value; - - /* Address in target of offset from thread-local register of - start of this thread's data. I.e., the first thread-local - variable in this shared library starts at *(tsd_start_addr) - from that area pointed to by cr27 (mpsfu_hi). - - We do the indirection as soon as we read it, so from then - on it's the offset itself. */ - CORE_ADDR tsd_start_addr; - - /* Address of the link map entry in the loader. */ - CORE_ADDR lm_addr; - }; - -/* These addresses should be filled in by som_solib_create_inferior_hook. - They are also used elsewhere in this module. */ - -typedef struct - { - CORE_ADDR address; - struct unwind_table_entry *unwind; - } -addr_and_unwind_t; - -/* When adding fields, be sure to clear them in _initialize_som_solib. */ -static struct - { - int is_valid; - addr_and_unwind_t hook; - addr_and_unwind_t hook_stub; - addr_and_unwind_t load; - addr_and_unwind_t load_stub; - addr_and_unwind_t unload; - addr_and_unwind_t unload2; - addr_and_unwind_t unload_stub; - } -dld_cache; - -static void -som_relocate_section_addresses (struct so_list *so, - struct target_section *sec) -{ - flagword aflag = bfd_get_section_flags(so->abfd, sec->the_bfd_section); - - if (aflag & SEC_CODE) - { - sec->addr += so->lm_info->text_addr - so->lm_info->text_link_addr; - sec->endaddr += so->lm_info->text_addr - so->lm_info->text_link_addr; - } - else if (aflag & SEC_DATA) - { - sec->addr += so->lm_info->data_start; - sec->endaddr += so->lm_info->data_start; - } - else - { - /* Nothing. */ - } -} - - -/* Variable storing HP-UX major release number. - - On non-native system, simply assume that the major release number - is 11. On native systems, hppa-hpux-nat.c initialization code - sets this number to the real one on startup. - - We cannot compute this value here, because we need to make a native - call to "uname". We are are not allowed to do that from here, as - this file is used for both native and cross debugging. */ - -#define DEFAULT_HPUX_MAJOR_RELEASE 11 -int hpux_major_release = DEFAULT_HPUX_MAJOR_RELEASE; - -static int -get_hpux_major_release (void) -{ - return hpux_major_release; -} - -/* DL header flag defines. */ -#define SHLIB_TEXT_PRIVATE_ENABLE 0x4000 - -/* The DL header is documented in <shl.h>. We are only interested - in the flags field to determine whether the executable wants shared - libraries mapped private. */ -struct { - short junk[37]; - short flags; -} dl_header; - -/* This hook gets called just before the first instruction in the - inferior process is executed. - - This is our opportunity to set magic flags in the inferior so - that GDB can be notified when a shared library is mapped in and - to tell the dynamic linker that a private copy of the library is - needed (so GDB can set breakpoints in the library). - - __dld_flags is the location of the magic flags; as of this implementation - there are 3 flags of interest: - - bit 0 when set indicates that private copies of the libraries are needed - bit 1 when set indicates that the callback hook routine is valid - bit 2 when set indicates that the dynamic linker should maintain the - __dld_list structure when loading/unloading libraries. - - Note that shared libraries are not mapped in at this time, so we have - run the inferior until the libraries are mapped in. Typically this - means running until the "_start" is called. */ - -static void -som_solib_create_inferior_hook (int from_tty) -{ - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - struct bound_minimal_symbol msymbol; - unsigned int dld_flags, status, have_endo; - asection *shlib_info; - gdb_byte buf[4]; - CORE_ADDR anaddr; - - if (symfile_objfile == NULL) - return; - - /* First see if the objfile was dynamically linked. */ - shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$"); - if (!shlib_info) - return; - - /* It's got a $SHLIB_INFO$ section, make sure it's not empty. */ - if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0) - return; - - /* Read the DL header. */ - bfd_get_section_contents (symfile_objfile->obfd, shlib_info, - (char *) &dl_header, 0, sizeof (dl_header)); - - have_endo = 0; - /* Slam the pid of the process into __d_pid. - - We used to warn when this failed, but that warning is only useful - on very old HP systems (hpux9 and older). The warnings are an - annoyance to users of modern systems and foul up the testsuite as - well. As a result, the warnings have been disabled. */ - msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - goto keep_going; - - anaddr = BMSYMBOL_VALUE_ADDRESS (msymbol); - store_unsigned_integer (buf, 4, byte_order, ptid_get_pid (inferior_ptid)); - status = target_write_memory (anaddr, buf, 4); - if (status != 0) - { - warning (_("\ -Unable to write __d_pid.\n\ -Suggest linking with /opt/langtools/lib/end.o.\n\ -GDB will be unable to track shl_load/shl_unload calls")); - goto keep_going; - } - - /* Get the value of _DLD_HOOK (an export stub) and put it in __dld_hook; - This will force the dynamic linker to call __d_trap when significant - events occur. - - Note that the above is the pre-HP-UX 9.0 behaviour. At 9.0 and above, - the dld provides an export stub named "__d_trap" as well as the - function named "__d_trap" itself, but doesn't provide "_DLD_HOOK". - We'll look first for the old flavor and then the new. */ - - msymbol = lookup_minimal_symbol ("_DLD_HOOK", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - { - warning (_("\ -Unable to find _DLD_HOOK symbol in object file.\n\ -Suggest linking with /opt/langtools/lib/end.o.\n\ -GDB will be unable to track shl_load/shl_unload calls")); - goto keep_going; - } - anaddr = BMSYMBOL_VALUE_ADDRESS (msymbol); - dld_cache.hook.address = anaddr; - - /* Grrr, this might not be an export symbol! We have to find the - export stub. */ - msymbol - = hppa_lookup_stub_minimal_symbol (MSYMBOL_LINKAGE_NAME (msymbol.minsym), - EXPORT); - if (msymbol.minsym != NULL) - { - anaddr = MSYMBOL_VALUE (msymbol.minsym); - dld_cache.hook_stub.address = anaddr; - } - store_unsigned_integer (buf, 4, byte_order, anaddr); - - msymbol = lookup_minimal_symbol ("__dld_hook", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - { - warning (_("\ -Unable to find __dld_hook symbol in object file.\n\ -Suggest linking with /opt/langtools/lib/end.o.\n\ -GDB will be unable to track shl_load/shl_unload calls")); - goto keep_going; - } - anaddr = BMSYMBOL_VALUE_ADDRESS (msymbol); - status = target_write_memory (anaddr, buf, 4); - - /* Now set a shlib_event breakpoint at __d_trap so we can track - significant shared library events. */ - msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - { - warning (_("\ -Unable to find __dld_d_trap symbol in object file.\n\ -Suggest linking with /opt/langtools/lib/end.o.\n\ -GDB will be unable to track shl_load/shl_unload calls")); - goto keep_going; - } - create_solib_event_breakpoint (target_gdbarch (), - BMSYMBOL_VALUE_ADDRESS (msymbol)); - - /* We have all the support usually found in end.o, so we can track - shl_load and shl_unload calls. */ - have_endo = 1; - -keep_going: - - /* Get the address of __dld_flags, if no such symbol exists, then we can - not debug the shared code. */ - msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL); - if (msymbol.minsym == NULL) - { - error (_("Unable to find __dld_flags symbol in object file.")); - } - - anaddr = BMSYMBOL_VALUE_ADDRESS (msymbol); - - /* Read the current contents. */ - status = target_read_memory (anaddr, buf, 4); - if (status != 0) - error (_("Unable to read __dld_flags.")); - dld_flags = extract_unsigned_integer (buf, 4, byte_order); - - /* If the libraries were not mapped private on HP-UX 11 and later, warn - the user. On HP-UX 10 and earlier, there is no easy way to specify - that shared libraries should be privately mapped. So, we just force - private mapping. */ - if (get_hpux_major_release () >= 11 - && (dl_header.flags & SHLIB_TEXT_PRIVATE_ENABLE) == 0 - && (dld_flags & DLD_FLAGS_MAPPRIVATE) == 0) - warning - (_("\ -Private mapping of shared library text was not specified\n\ -by the executable; setting a breakpoint in a shared library which\n\ -is not privately mapped will not work. See the HP-UX 11i v3 chatr\n\ -manpage for methods to privately map shared library text.")); - - /* Turn on the flags we care about. */ - if (get_hpux_major_release () < 11) - dld_flags |= DLD_FLAGS_MAPPRIVATE; - if (have_endo) - dld_flags |= DLD_FLAGS_HOOKVALID; - store_unsigned_integer (buf, 4, byte_order, dld_flags); - status = target_write_memory (anaddr, buf, 4); - if (status != 0) - error (_("Unable to write __dld_flags.")); - - /* Now find the address of _start and set a breakpoint there. - We still need this code for two reasons: - - * Not all sites have /opt/langtools/lib/end.o, so it's not always - possible to track the dynamic linker's events. - - * At this time no events are triggered for shared libraries - loaded at startup time (what a crock). */ - - msymbol = lookup_minimal_symbol ("_start", NULL, symfile_objfile); - if (msymbol.minsym == NULL) - error (_("Unable to find _start symbol in object file.")); - - anaddr = BMSYMBOL_VALUE_ADDRESS (msymbol); - - /* Make the breakpoint at "_start" a shared library event breakpoint. */ - create_solib_event_breakpoint (target_gdbarch (), anaddr); - - clear_symtab_users (0); -} - -static void -som_special_symbol_handling (void) -{ -} - -static void -som_solib_desire_dynamic_linker_symbols (void) -{ - struct objfile *objfile; - struct unwind_table_entry *u; - struct bound_minimal_symbol dld_msymbol; - - /* Do we already know the value of these symbols? If so, then - we've no work to do. - - (If you add clauses to this test, be sure to likewise update the - test within the loop.) */ - - if (dld_cache.is_valid) - return; - - ALL_OBJFILES (objfile) - { - dld_msymbol = lookup_minimal_symbol ("shl_load", NULL, objfile); - if (dld_msymbol.minsym != NULL) - { - dld_cache.load.address = MSYMBOL_VALUE (dld_msymbol.minsym); - dld_cache.load.unwind = find_unwind_entry (dld_cache.load.address); - } - - dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_load", - objfile); - if (dld_msymbol.minsym != NULL) - { - if (MSYMBOL_TYPE (dld_msymbol.minsym) == mst_solib_trampoline) - { - u = find_unwind_entry (MSYMBOL_VALUE (dld_msymbol.minsym)); - if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT)) - { - dld_cache.load_stub.address - = MSYMBOL_VALUE (dld_msymbol.minsym); - dld_cache.load_stub.unwind = u; - } - } - } - - dld_msymbol = lookup_minimal_symbol ("shl_unload", NULL, objfile); - if (dld_msymbol.minsym != NULL) - { - dld_cache.unload.address = MSYMBOL_VALUE (dld_msymbol.minsym); - dld_cache.unload.unwind = find_unwind_entry (dld_cache.unload.address); - - /* ??rehrauer: I'm not sure exactly what this is, but it appears - that on some HPUX 10.x versions, there's two unwind regions to - cover the body of "shl_unload", the second being 4 bytes past - the end of the first. This is a large hack to handle that - case, but since I don't seem to have any legitimate way to - look for this thing via the symbol table... */ - - if (dld_cache.unload.unwind != NULL) - { - u = find_unwind_entry (dld_cache.unload.unwind->region_end + 4); - if (u != NULL) - { - dld_cache.unload2.address = u->region_start; - dld_cache.unload2.unwind = u; - } - } - } - - dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_unload", - objfile); - if (dld_msymbol.minsym != NULL) - { - if (MSYMBOL_TYPE (dld_msymbol.minsym) == mst_solib_trampoline) - { - u = find_unwind_entry (MSYMBOL_VALUE (dld_msymbol.minsym)); - if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT)) - { - dld_cache.unload_stub.address - = MSYMBOL_VALUE (dld_msymbol.minsym); - dld_cache.unload_stub.unwind = u; - } - } - } - - /* Did we find everything we were looking for? If so, stop. */ - if ((dld_cache.load.address != 0) - && (dld_cache.load_stub.address != 0) - && (dld_cache.unload.address != 0) - && (dld_cache.unload_stub.address != 0)) - { - dld_cache.is_valid = 1; - break; - } - } - - dld_cache.hook.unwind = find_unwind_entry (dld_cache.hook.address); - dld_cache.hook_stub.unwind = find_unwind_entry (dld_cache.hook_stub.address); - - /* We're prepared not to find some of these symbols, which is why - this function is a "desire" operation, and not a "require". */ -} - -static int -som_in_dynsym_resolve_code (CORE_ADDR pc) -{ - struct unwind_table_entry *u_pc; - - /* Are we in the dld itself? - - ??rehrauer: Large hack -- We'll assume that any address in a - shared text region is the dld's text. This would obviously - fall down if the user attached to a process, whose shlibs - weren't mapped to a (writeable) private region. However, in - that case the debugger probably isn't able to set the fundamental - breakpoint in the dld callback anyways, so this hack should be - safe. */ - - if ((pc & (CORE_ADDR) 0xc0000000) == (CORE_ADDR) 0xc0000000) - return 1; - - /* Cache the address of some symbols that are part of the dynamic - linker, if not already known. */ - - som_solib_desire_dynamic_linker_symbols (); - - /* Are we in the dld callback? Or its export stub? */ - u_pc = find_unwind_entry (pc); - if (u_pc == NULL) - return 0; - - if ((u_pc == dld_cache.hook.unwind) || (u_pc == dld_cache.hook_stub.unwind)) - return 1; - - /* Or the interface of the dld (i.e., "shl_load" or friends)? */ - if ((u_pc == dld_cache.load.unwind) - || (u_pc == dld_cache.unload.unwind) - || (u_pc == dld_cache.unload2.unwind) - || (u_pc == dld_cache.load_stub.unwind) - || (u_pc == dld_cache.unload_stub.unwind)) - return 1; - - /* Apparently this address isn't part of the dld's text. */ - return 0; -} - -static void -som_clear_solib (void) -{ -} - -struct dld_list { - char name[4]; - char info[4]; - char text_addr[4]; - char text_link_addr[4]; - char text_end[4]; - char data_start[4]; - char bss_start[4]; - char data_end[4]; - char got_value[4]; - char next[4]; - char tsd_start_addr_ptr[4]; -}; - -static CORE_ADDR -link_map_start (void) -{ - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - struct bound_minimal_symbol sym; - CORE_ADDR addr; - gdb_byte buf[4]; - unsigned int dld_flags; - - sym = lookup_minimal_symbol ("__dld_flags", NULL, NULL); - if (!sym.minsym) - error (_("Unable to find __dld_flags symbol in object file.")); - addr = BMSYMBOL_VALUE_ADDRESS (sym); - read_memory (addr, buf, 4); - dld_flags = extract_unsigned_integer (buf, 4, byte_order); - if ((dld_flags & DLD_FLAGS_LISTVALID) == 0) - error (_("__dld_list is not valid according to __dld_flags.")); - - sym = lookup_minimal_symbol ("__dld_list", NULL, NULL); - if (!sym.minsym) - { - /* Older crt0.o files (hpux8) don't have __dld_list as a symbol, - but the data is still available if you know where to look. */ - sym = lookup_minimal_symbol ("__dld_flags", NULL, NULL); - if (!sym.minsym) - { - error (_("Unable to find dynamic library list.")); - return 0; - } - addr = BMSYMBOL_VALUE_ADDRESS (sym) - 8; - } - else - addr = BMSYMBOL_VALUE_ADDRESS (sym); - - read_memory (addr, buf, 4); - addr = extract_unsigned_integer (buf, 4, byte_order); - if (addr == 0) - return 0; - - read_memory (addr, buf, 4); - return extract_unsigned_integer (buf, 4, byte_order); -} - -/* Does this so's name match the main binary? */ -static int -match_main (const char *name) -{ - return strcmp (name, objfile_name (symfile_objfile)) == 0; -} - -static struct so_list * -som_current_sos (void) -{ - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - CORE_ADDR lm; - struct so_list *head = 0; - struct so_list **link_ptr = &head; - - for (lm = link_map_start (); lm; ) - { - char *namebuf; - CORE_ADDR addr; - struct so_list *newobj; - struct cleanup *old_chain; - int errcode; - struct dld_list dbuf; - gdb_byte tsdbuf[4]; - - newobj = (struct so_list *) xmalloc (sizeof (struct so_list)); - old_chain = make_cleanup (xfree, newobj); - - memset (newobj, 0, sizeof (*newobj)); - newobj->lm_info = xmalloc (sizeof (struct lm_info)); - make_cleanup (xfree, newobj->lm_info); - - read_memory (lm, (gdb_byte *)&dbuf, sizeof (struct dld_list)); - - addr = extract_unsigned_integer ((gdb_byte *)&dbuf.name, - sizeof (dbuf.name), byte_order); - target_read_string (addr, &namebuf, SO_NAME_MAX_PATH_SIZE - 1, &errcode); - if (errcode != 0) - warning (_("Can't read pathname for load map: %s."), - safe_strerror (errcode)); - else - { - strncpy (newobj->so_name, namebuf, SO_NAME_MAX_PATH_SIZE - 1); - newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; - xfree (namebuf); - strcpy (newobj->so_original_name, newobj->so_name); - } - - if (newobj->so_name[0] && !match_main (newobj->so_name)) - { - struct lm_info *lmi = newobj->lm_info; - unsigned int tmp; - - lmi->lm_addr = lm; - -#define EXTRACT(_fld) \ - extract_unsigned_integer ((gdb_byte *)&dbuf._fld, \ - sizeof (dbuf._fld), byte_order); - - lmi->text_addr = EXTRACT (text_addr); - tmp = EXTRACT (info); - lmi->library_version = (tmp >> 16) & 0xffff; - lmi->bind_mode = (tmp >> 8) & 0xff; - lmi->struct_version = tmp & 0xff; - lmi->text_link_addr = EXTRACT (text_link_addr); - lmi->text_end = EXTRACT (text_end); - lmi->data_start = EXTRACT (data_start); - lmi->bss_start = EXTRACT (bss_start); - lmi->data_end = EXTRACT (data_end); - lmi->got_value = EXTRACT (got_value); - tmp = EXTRACT (tsd_start_addr_ptr); - read_memory (tmp, tsdbuf, 4); - lmi->tsd_start_addr - = extract_unsigned_integer (tsdbuf, 4, byte_order); - -#ifdef SOLIB_SOM_DBG - printf ("\n+ library \"%s\" is described at %s\n", newobj->so_name, - paddress (target_gdbarch (), lm)); - printf (" 'version' is %d\n", newobj->lm_info->struct_version); - printf (" 'bind_mode' is %d\n", newobj->lm_info->bind_mode); - printf (" 'library_version' is %d\n", - newobj->lm_info->library_version); - printf (" 'text_addr' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->text_addr)); - printf (" 'text_link_addr' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->text_link_addr)); - printf (" 'text_end' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->text_end)); - printf (" 'data_start' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->data_start)); - printf (" 'bss_start' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->bss_start)); - printf (" 'data_end' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->data_end)); - printf (" 'got_value' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->got_value)); - printf (" 'tsd_start_addr' is %s\n", - paddress (target_gdbarch (), newobj->lm_info->tsd_start_addr)); -#endif - - newobj->addr_low = lmi->text_addr; - newobj->addr_high = lmi->text_end; - - /* Link the new object onto the list. */ - newobj->next = NULL; - *link_ptr = newobj; - link_ptr = &newobj->next; - } - else - { - free_so (newobj); - } - - lm = EXTRACT (next); - discard_cleanups (old_chain); -#undef EXTRACT - } - - /* TODO: The original somsolib code has logic to detect and eliminate - duplicate entries. Do we need that? */ - - return head; -} - -static int -som_open_symbol_file_object (void *from_ttyp) -{ - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - CORE_ADDR lm, l_name; - char *filename; - int errcode; - int from_tty = *(int *)from_ttyp; - gdb_byte buf[4]; - struct cleanup *cleanup; - - if (symfile_objfile) - if (!query (_("Attempt to reload symbols from process? "))) - return 0; - - /* First link map member should be the executable. */ - if ((lm = link_map_start ()) == 0) - return 0; /* failed somehow... */ - - /* Read address of name from target memory to GDB. */ - read_memory (lm + offsetof (struct dld_list, name), buf, 4); - - /* Convert the address to host format. Assume that the address is - unsigned. */ - l_name = extract_unsigned_integer (buf, 4, byte_order); - - if (l_name == 0) - return 0; /* No filename. */ - - /* Now fetch the filename from target memory. */ - target_read_string (l_name, &filename, SO_NAME_MAX_PATH_SIZE - 1, &errcode); - - if (errcode) - { - warning (_("failed to read exec filename from attached file: %s"), - safe_strerror (errcode)); - return 0; - } - - cleanup = make_cleanup (xfree, filename); - /* Have a pathname: read the symbol file. */ - symbol_file_add_main (filename, from_tty); - - do_cleanups (cleanup); - return 1; -} - -static void -som_free_so (struct so_list *so) -{ - xfree (so->lm_info); -} - -static CORE_ADDR -som_solib_thread_start_addr (struct so_list *so) -{ - return so->lm_info->tsd_start_addr; -} - -/* Return the GOT value for the shared library in which ADDR belongs. If - ADDR isn't in any known shared library, return zero. */ - -static CORE_ADDR -som_solib_get_got_by_pc (CORE_ADDR addr) -{ - struct so_list *so_list = master_so_list (); - CORE_ADDR got_value = 0; - - while (so_list) - { - if (so_list->lm_info->text_addr <= addr - && so_list->lm_info->text_end > addr) - { - got_value = so_list->lm_info->got_value; - break; - } - so_list = so_list->next; - } - return got_value; -} - -/* Return the address of the handle of the shared library in which - ADDR belongs. If ADDR isn't in any known shared library, return - zero. */ -/* This function is used in initialize_hp_cxx_exception_support in - hppa-hpux-tdep.c. */ - -static CORE_ADDR -som_solib_get_solib_by_pc (CORE_ADDR addr) -{ - struct so_list *so_list = master_so_list (); - - while (so_list) - { - if (so_list->lm_info->text_addr <= addr - && so_list->lm_info->text_end > addr) - { - break; - } - so_list = so_list->next; - } - if (so_list) - return so_list->lm_info->lm_addr; - else - return 0; -} - - -static struct target_so_ops som_so_ops; - -extern initialize_file_ftype _initialize_som_solib; /* -Wmissing-prototypes */ - -void -_initialize_som_solib (void) -{ - som_so_ops.relocate_section_addresses = som_relocate_section_addresses; - som_so_ops.free_so = som_free_so; - som_so_ops.clear_solib = som_clear_solib; - som_so_ops.solib_create_inferior_hook = som_solib_create_inferior_hook; - som_so_ops.special_symbol_handling = som_special_symbol_handling; - som_so_ops.current_sos = som_current_sos; - som_so_ops.open_symbol_file_object = som_open_symbol_file_object; - som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code; - som_so_ops.bfd_open = solib_bfd_open; -} - -void -som_solib_select (struct gdbarch *gdbarch) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - set_solib_ops (gdbarch, &som_so_ops); - tdep->solib_thread_start_addr = som_solib_thread_start_addr; - tdep->solib_get_got_by_pc = som_solib_get_got_by_pc; - tdep->solib_get_solib_by_pc = som_solib_get_solib_by_pc; -} - -/* The rest of these functions are not part of the solib interface; they - are used by somread.c or hppa-hpux-tdep.c. */ - -int -som_solib_section_offsets (struct objfile *objfile, - struct section_offsets *offsets) -{ - struct so_list *so_list = master_so_list (); - - while (so_list) - { - /* Oh what a pain! We need the offsets before so_list->objfile - is valid. The BFDs will never match. Make a best guess. */ - if (strstr (objfile_name (objfile), so_list->so_name)) - { - asection *private_section; - struct obj_section *sect; - - /* The text offset is easy. */ - offsets->offsets[SECT_OFF_TEXT (objfile)] - = (so_list->lm_info->text_addr - - so_list->lm_info->text_link_addr); - - /* We should look at presumed_dp in the SOM header, but - that's not easily available. This should be OK though. */ - private_section = bfd_get_section_by_name (objfile->obfd, - "$PRIVATE$"); - if (!private_section) - { - warning (_("Unable to find $PRIVATE$ in shared library!")); - offsets->offsets[SECT_OFF_DATA (objfile)] = 0; - offsets->offsets[SECT_OFF_BSS (objfile)] = 0; - return 1; - } - if (objfile->sect_index_data != -1) - { - offsets->offsets[SECT_OFF_DATA (objfile)] - = (so_list->lm_info->data_start - private_section->vma); - if (objfile->sect_index_bss != -1) - offsets->offsets[SECT_OFF_BSS (objfile)] - = ANOFFSET (offsets, SECT_OFF_DATA (objfile)); - } - - ALL_OBJFILE_OSECTIONS (objfile, sect) - { - flagword flags = bfd_get_section_flags (objfile->obfd, - sect->the_bfd_section); - - if ((flags & SEC_CODE) != 0) - offsets->offsets[sect->the_bfd_section->index] - = offsets->offsets[SECT_OFF_TEXT (objfile)]; - else - offsets->offsets[sect->the_bfd_section->index] - = offsets->offsets[SECT_OFF_DATA (objfile)]; - } - - return 1; - } - so_list = so_list->next; - } - return 0; -} diff --git a/gdb/solib-som.h b/gdb/solib-som.h deleted file mode 100644 index f64ab8c..0000000 --- a/gdb/solib-som.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Handle SOM shared libraries for GDB, the GNU Debugger. - - Copyright (C) 2004-2015 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef SOLIB_SOM_H -#define SOLIB_SOM_H - -struct objfile; -struct section_offsets; -struct gdbarch; - -extern int hpux_major_release; - -void som_solib_select (struct gdbarch *gdbarch); - -int som_solib_section_offsets (struct objfile *objfile, - struct section_offsets *offsets); - -#endif - diff --git a/gdb/somread.c b/gdb/somread.c deleted file mode 100644 index 49cfe76..0000000 --- a/gdb/somread.c +++ /dev/null @@ -1,547 +0,0 @@ -/* Read HP PA/Risc object files for GDB. - Copyright (C) 1991-2015 Free Software Foundation, Inc. - Written by Fred Fish at Cygnus Support. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "bfd.h" -#include "som/aout.h" -#include "symtab.h" -#include "symfile.h" -#include "objfiles.h" -#include "buildsym.h" -#include "stabsread.h" -#include "gdb-stabs.h" -#include "complaints.h" -#include "demangle.h" -#include "som.h" -#include "libhppa.h" -#include "psymtab.h" - -#include "solib-som.h" - -/* Read the symbol table of a SOM file. - - Given an open bfd, a base address to relocate symbols to, and a - flag that specifies whether or not this bfd is for an executable - or not (may be shared library for example), add all the global - function and data symbols to the minimal symbol table. */ - -static void -som_symtab_read (bfd *abfd, struct objfile *objfile, - struct section_offsets *section_offsets) -{ - struct cleanup *cleanup; - struct gdbarch *gdbarch = get_objfile_arch (objfile); - unsigned int number_of_symbols; - int val, dynamic; - char *stringtab; - asection *shlib_info; - struct som_external_symbol_dictionary_record *buf, *bufp, *endbufp; - char *symname; - const int symsize = sizeof (struct som_external_symbol_dictionary_record); - - - number_of_symbols = bfd_get_symcount (abfd); - - /* Allocate a buffer to read in the debug info. - We avoid using alloca because the memory size could be so large - that we could hit the stack size limit. */ - buf = xmalloc (symsize * number_of_symbols); - cleanup = make_cleanup (xfree, buf); - bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET); - val = bfd_bread (buf, symsize * number_of_symbols, abfd); - if (val != symsize * number_of_symbols) - error (_("Couldn't read symbol dictionary!")); - - /* Allocate a buffer to read in the som stringtab section of - the debugging info. Again, we avoid using alloca because - the data could be so large that we could potentially hit - the stack size limitat. */ - stringtab = xmalloc (obj_som_stringtab_size (abfd)); - make_cleanup (xfree, stringtab); - bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET); - val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd); - if (val != obj_som_stringtab_size (abfd)) - error (_("Can't read in HP string table.")); - - /* We need to determine if objfile is a dynamic executable (so we - can do the right thing for ST_ENTRY vs ST_CODE symbols). - - There's nothing in the header which easily allows us to do - this. - - This code used to rely upon the existence of a $SHLIB_INFO$ - section to make this determination. HP claims that it is - more accurate to check for a nonzero text offset, but they - have not provided any information about why that test is - more accurate. */ - dynamic = (ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)) != 0); - - endbufp = buf + number_of_symbols; - for (bufp = buf; bufp < endbufp; ++bufp) - { - enum minimal_symbol_type ms_type; - unsigned int flags = bfd_getb32 (bufp->flags); - unsigned int symbol_type - = (flags >> SOM_SYMBOL_TYPE_SH) & SOM_SYMBOL_TYPE_MASK; - unsigned int symbol_scope - = (flags >> SOM_SYMBOL_SCOPE_SH) & SOM_SYMBOL_SCOPE_MASK; - CORE_ADDR symbol_value = bfd_getb32 (bufp->symbol_value); - asection *section = NULL; - - QUIT; - - /* Compute the section. */ - switch (symbol_scope) - { - case SS_EXTERNAL: - if (symbol_type != ST_STORAGE) - section = bfd_und_section_ptr; - else - section = bfd_com_section_ptr; - break; - - case SS_UNSAT: - if (symbol_type != ST_STORAGE) - section = bfd_und_section_ptr; - else - section = bfd_com_section_ptr; - break; - - case SS_UNIVERSAL: - section = bfd_section_from_som_symbol (abfd, bufp); - break; - - case SS_LOCAL: - section = bfd_section_from_som_symbol (abfd, bufp); - break; - } - - switch (symbol_scope) - { - case SS_UNIVERSAL: - case SS_EXTERNAL: - switch (symbol_type) - { - case ST_SYM_EXT: - case ST_ARG_EXT: - continue; - - case ST_CODE: - case ST_PRI_PROG: - case ST_SEC_PROG: - case ST_MILLICODE: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_text; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - case ST_ENTRY: - symname = bfd_getb32 (bufp->name) + stringtab; - /* For a dynamic executable, ST_ENTRY symbols are - the stubs, while the ST_CODE symbol is the real - function. */ - if (dynamic) - ms_type = mst_solib_trampoline; - else - ms_type = mst_text; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - case ST_STUB: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_solib_trampoline; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - case ST_DATA: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_data; - break; - default: - continue; - } - break; - -#if 0 - /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!). */ - case SS_GLOBAL: -#endif - case SS_LOCAL: - switch (symbol_type) - { - case ST_SYM_EXT: - case ST_ARG_EXT: - continue; - - case ST_CODE: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_file_text; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - - check_strange_names: - /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local - label prefixes for stabs, constant data, etc. So we need - only filter out L$ symbols which are left in due to - limitations in how GAS generates SOM relocations. - - When linking in the HPUX C-library the HP linker has - the nasty habit of placing section symbols from the literal - subspaces in the middle of the program's text. Filter - those out as best we can. Check for first and last character - being '$'. - - And finally, the newer HP compilers emit crud like $PIC_foo$N - in some circumstance (PIC code I guess). It's also claimed - that they emit D$ symbols too. What stupidity. */ - if ((symname[0] == 'L' && symname[1] == '$') - || (symname[0] == '$' && symname[strlen (symname) - 1] == '$') - || (symname[0] == 'D' && symname[1] == '$') - || (startswith (symname, "L0\001")) - || (startswith (symname, "$PIC"))) - continue; - break; - - case ST_PRI_PROG: - case ST_SEC_PROG: - case ST_MILLICODE: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_file_text; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - case ST_ENTRY: - symname = bfd_getb32 (bufp->name) + stringtab; - /* SS_LOCAL symbols in a shared library do not have - export stubs, so we do not have to worry about - using mst_file_text vs mst_solib_trampoline here like - we do for SS_UNIVERSAL and SS_EXTERNAL symbols above. */ - ms_type = mst_file_text; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - case ST_STUB: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_solib_trampoline; - symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value); - break; - - - case ST_DATA: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_file_data; - goto check_strange_names; - - default: - continue; - } - break; - - /* This can happen for common symbols when -E is passed to the - final link. No idea _why_ that would make the linker force - common symbols to have an SS_UNSAT scope, but it does. - - This also happens for weak symbols, but their type is - ST_DATA. */ - case SS_UNSAT: - switch (symbol_type) - { - case ST_STORAGE: - case ST_DATA: - symname = bfd_getb32 (bufp->name) + stringtab; - ms_type = mst_data; - break; - - default: - continue; - } - break; - - default: - continue; - } - - if (bfd_getb32 (bufp->name) > obj_som_stringtab_size (abfd)) - error (_("Invalid symbol data; bad HP string table offset: %s"), - plongest (bfd_getb32 (bufp->name))); - - if (bfd_is_const_section (section)) - { - struct obj_section *iter; - - ALL_OBJFILE_OSECTIONS (objfile, iter) - { - CORE_ADDR start; - CORE_ADDR len; - - if (bfd_is_const_section (iter->the_bfd_section)) - continue; - - start = bfd_get_section_vma (iter->objfile->obfd, - iter->the_bfd_section); - len = bfd_get_section_size (iter->the_bfd_section); - if (start <= symbol_value && symbol_value < start + len) - { - section = iter->the_bfd_section; - break; - } - } - } - - prim_record_minimal_symbol_and_info (symname, symbol_value, ms_type, - gdb_bfd_section_index (objfile->obfd, - section), - objfile); - } - - do_cleanups (cleanup); -} - -/* Scan and build partial symbols for a symbol file. - We have been initialized by a call to som_symfile_init, which - currently does nothing. - - SECTION_OFFSETS is a set of offsets to apply to relocate the symbols - in each section. This is ignored, as it isn't needed for SOM. - - This function only does the minimum work necessary for letting the - user "name" things symbolically; it does not read the entire symtab. - Instead, it reads the external and static symbols and puts them in partial - symbol tables. When more extensive information is requested of a - file, the corresponding partial symbol table is mutated into a full - fledged symbol table by going back and reading the symbols - for real. - - We look for sections with specific names, to tell us what debug - format to look for. - - somstab_build_psymtabs() handles STABS symbols. - - Note that SOM files have a "minimal" symbol table, which is vaguely - reminiscent of a COFF symbol table, but has only the minimal information - necessary for linking. We process this also, and use the information to - build gdb's minimal symbol table. This gives us some minimal debugging - capability even for files compiled without -g. */ - -static void -som_symfile_read (struct objfile *objfile, int symfile_flags) -{ - bfd *abfd = objfile->obfd; - struct cleanup *back_to; - - init_minimal_symbol_collection (); - back_to = make_cleanup_discard_minimal_symbols (); - - /* Process the normal SOM symbol table first. - This reads in the DNTT and string table, but doesn't - actually scan the DNTT. It does scan the linker symbol - table and thus build up a "minimal symbol table". */ - - som_symtab_read (abfd, objfile, objfile->section_offsets); - - /* Install any minimal symbols that have been collected as the current - minimal symbols for this objfile. - Further symbol-reading is done incrementally, file-by-file, - in a step known as "psymtab-to-symtab" expansion. hp-symtab-read.c - contains the code to do the actual DNTT scanning and symtab building. */ - install_minimal_symbols (objfile); - do_cleanups (back_to); - - /* Now read information from the stabs debug sections. - This is emitted by gcc. */ - stabsect_build_psymtabs (objfile, - "$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$"); -} - -/* Initialize anything that needs initializing when a completely new symbol - file is specified (not just adding some symbols from another file, e.g. a - shared library). - - We reinitialize buildsym, since we may be reading stabs from a SOM file. */ - -static void -som_new_init (struct objfile *ignore) -{ - stabsread_new_init (); - buildsym_new_init (); -} - -/* Perform any local cleanups required when we are done with a particular - objfile. I.e, we are in the process of discarding all symbol information - for an objfile, freeing up all memory held for it, and unlinking the - objfile struct from the global list of known objfiles. */ - -static void -som_symfile_finish (struct objfile *objfile) -{ -} - -/* SOM specific initialization routine for reading symbols. */ - -static void -som_symfile_init (struct objfile *objfile) -{ - /* SOM objects may be reordered, so set OBJF_REORDERED. If we - find this causes a significant slowdown in gdb then we could - set it in the debug symbol readers only when necessary. */ - objfile->flags |= OBJF_REORDERED; -} - -/* An object of this type is passed to find_section_offset. */ - -struct find_section_offset_arg -{ - /* The objfile. */ - - struct objfile *objfile; - - /* Flags to invert. */ - - flagword invert; - - /* Flags to look for. */ - - flagword flags; - - /* A text section with non-zero size, if any. */ - - asection *best_section; - - /* An empty text section, if any. */ - - asection *empty_section; -}; - -/* A callback for bfd_map_over_sections that tries to find a section - with particular flags in an objfile. */ - -static void -find_section_offset (bfd *abfd, asection *sect, void *arg) -{ - struct find_section_offset_arg *info = arg; - flagword aflag; - - aflag = bfd_get_section_flags (abfd, sect); - - aflag ^= info->invert; - - if ((aflag & info->flags) == info->flags) - { - if (bfd_section_size (abfd, sect) > 0) - { - if (info->best_section == NULL) - info->best_section = sect; - } - else - { - if (info->empty_section == NULL) - info->empty_section = sect; - } - } -} - -/* Set a section index from a BFD. */ - -static void -set_section_index (struct objfile *objfile, flagword invert, flagword flags, - int *index_ptr) -{ - struct find_section_offset_arg info; - - info.objfile = objfile; - info.best_section = NULL; - info.empty_section = NULL; - info.invert = invert; - info.flags = flags; - bfd_map_over_sections (objfile->obfd, find_section_offset, &info); - - if (info.best_section) - *index_ptr = info.best_section->index; - else if (info.empty_section) - *index_ptr = info.empty_section->index; -} - -/* SOM specific parsing routine for section offsets. - - Plain and simple for now. */ - -static void -som_symfile_offsets (struct objfile *objfile, - const struct section_addr_info *addrs) -{ - int i; - CORE_ADDR text_addr; - asection *sect; - - objfile->num_sections = bfd_count_sections (objfile->obfd); - objfile->section_offsets = (struct section_offsets *) - obstack_alloc (&objfile->objfile_obstack, - SIZEOF_N_SECTION_OFFSETS (objfile->num_sections)); - - set_section_index (objfile, 0, SEC_ALLOC | SEC_CODE, - &objfile->sect_index_text); - set_section_index (objfile, 0, SEC_ALLOC | SEC_DATA, - &objfile->sect_index_data); - set_section_index (objfile, SEC_LOAD, SEC_ALLOC | SEC_LOAD, - &objfile->sect_index_bss); - set_section_index (objfile, 0, SEC_ALLOC | SEC_READONLY, - &objfile->sect_index_rodata); - - /* First see if we're a shared library. If so, get the section - offsets from the library, else get them from addrs. */ - if (!som_solib_section_offsets (objfile, objfile->section_offsets)) - { - /* Note: Here is OK to compare with ".text" because this is the - name that gdb itself gives to that section, not the SOM - name. */ - for (i = 0; i < addrs->num_sections; i++) - if (strcmp (addrs->other[i].name, ".text") == 0) - break; - text_addr = addrs->other[i].addr; - - for (i = 0; i < objfile->num_sections; i++) - (objfile->section_offsets)->offsets[i] = text_addr; - } -} - - - -/* Register that we are able to handle SOM object file formats. */ - -static const struct sym_fns som_sym_fns = -{ - som_new_init, /* init anything gbl to entire symtab */ - som_symfile_init, /* read initial info, setup for sym_read() */ - som_symfile_read, /* read a symbol file into symtab */ - NULL, /* sym_read_psymbols */ - som_symfile_finish, /* finished with file, cleanup */ - som_symfile_offsets, /* Translate ext. to int. relocation */ - default_symfile_segments, /* Get segment information from a file. */ - NULL, - default_symfile_relocate, /* Relocate a debug section. */ - NULL, /* sym_get_probes */ - &psym_functions -}; - -initialize_file_ftype _initialize_somread; - -void -_initialize_somread (void) -{ - add_symtab_fns (bfd_target_som_flavour, &som_sym_fns); -} |