Remove HPUX

IIUC it is a pre-requisite for IPv6 support, some UNICes do not support
getaddrinfo required for IPv6.  But coincidentally such UNICes are no longer
really supported by GDB.  Therefore it was concluded we can remove all such
UNICes and then we can implement IPv6 easily with getaddrinfo.

In mail
        Re: getaddrinfo available on all GDB hosts? [Re: [PATCH v2] Add IPv6 support for remote TCP connections]
        Message-ID: <20140211034157.GG5485@adacore.com>
        https://sourceware.org/ml/gdb-patches/2014-02/msg00333.html
Joel said:

So I chose HP-UX first for this patch.

gdb/ChangeLog
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.
This commit is contained in:
Jan Kratochvil 2015-03-13 20:24:22 +01:00
parent 25268153a1
commit 61a12cfa7b
25 changed files with 88 additions and 7390 deletions

View File

@ -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).

View File

@ -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 \

View File

@ -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

View File

@ -1,3 +0,0 @@
# Host: ia64 running HP-UX
NATDEPFILES= fork-child.o inf-ttrace.o ia64-hpux-nat.o \
solib-ia64-hpux.o

View File

@ -1,3 +0,0 @@
# Host: PA-RISC HP-UX
NATDEPFILES= fork-child.o inf-ptrace.o inf-ttrace.o \
hppa-hpux-nat.o

106
gdb/configure vendored
View File

@ -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}"

View File

@ -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}"

View File

@ -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

View File

@ -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 \

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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 = &current_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 = &current_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);
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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, &current_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, &current_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 ();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}