mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
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:
parent
25268153a1
commit
61a12cfa7b
@ -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).
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Host: ia64 running HP-UX
|
||||
NATDEPFILES= fork-child.o inf-ttrace.o ia64-hpux-nat.o \
|
||||
solib-ia64-hpux.o
|
@ -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
106
gdb/configure
vendored
@ -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}"
|
||||
|
||||
|
@ -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}"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
1572
gdb/hppa-hpux-tdep.c
1572
gdb/hppa-hpux-tdep.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -1,434 +0,0 @@
|
||||
/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2010-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "ia64-tdep.h"
|
||||
#include "ia64-hpux-tdep.h"
|
||||
#include "osabi.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "solib.h"
|
||||
#include "target.h"
|
||||
#include "frame.h"
|
||||
#include "regcache.h"
|
||||
#include "gdbcore.h"
|
||||
#include "inferior.h"
|
||||
|
||||
/* A sequence of instructions pushed on the stack when we want to perform
|
||||
an inferior function call. The main purpose of this code is to save
|
||||
the output region of the register frame belonging to the function
|
||||
from which we are making the call. Normally, all registers are saved
|
||||
prior to the call, but this does not include stacked registers because
|
||||
they are seen by GDB as pseudo registers.
|
||||
|
||||
With Linux kernels, these stacked registers can be saved by simply
|
||||
creating a new register frame, or in other words by moving the BSP.
|
||||
But the HP/UX kernel does not allow this. So we rely on this code
|
||||
instead, that makes functions calls whose only purpose is to create
|
||||
new register frames.
|
||||
|
||||
The array below is the result obtained after assembling the code
|
||||
shown below. It's an array of bytes in order to make it independent
|
||||
of the host endianess, in case it ends up being used on more than
|
||||
one target.
|
||||
|
||||
start:
|
||||
// Save b0 before using it (into preserved reg: r4).
|
||||
mov r4 = b0
|
||||
;;
|
||||
|
||||
br.call.dptk.few b0 = stub#
|
||||
;;
|
||||
|
||||
// Add a nop bundle where we can insert our dummy breakpoint.
|
||||
nop.m 0
|
||||
nop.i 0
|
||||
nop.i 0
|
||||
;;
|
||||
|
||||
stub:
|
||||
// Alloc a new register stack frame. Here, we set the size
|
||||
// of all regions to zero. Eventually, GDB will manually
|
||||
// change the instruction to set the size of the local region
|
||||
// to match size of the output region of the function from
|
||||
// which we are making the function call. This is to protect
|
||||
// the value of the output registers of the function from
|
||||
// which we are making the call.
|
||||
alloc r6 = ar.pfs, 0, 0, 0, 0
|
||||
|
||||
// Save b0 before using it again (into preserved reg: r5).
|
||||
mov r5 = b0
|
||||
;;
|
||||
|
||||
// Now that we have protected the entire output region of the
|
||||
// register stack frame, we can call our function that will
|
||||
// setup the arguments, and call our target function.
|
||||
br.call.dptk.few b0 = call_dummy#
|
||||
;;
|
||||
|
||||
// Restore b0, ar.pfs, and return
|
||||
mov b0 = r5
|
||||
mov.i ar.pfs = r6
|
||||
;;
|
||||
br.ret.dptk.few b0
|
||||
;;
|
||||
|
||||
call_dummy:
|
||||
// Alloc a new frame, with 2 local registers, and 8 output registers
|
||||
// (8 output registers for the maximum of 8 slots passed by register).
|
||||
alloc r32 = ar.pfs, 2, 0, 8, 0
|
||||
|
||||
// Save b0 before using it to call our target function.
|
||||
mov r33 = b0
|
||||
|
||||
// Load the argument values placed by GDB inside r14-r21 in their
|
||||
// proper registers.
|
||||
or r34 = r14, r0
|
||||
or r35 = r15, r0
|
||||
or r36 = r16, r0
|
||||
or r37 = r17, r0
|
||||
or r38 = r18, r0
|
||||
or r39 = r19, r0
|
||||
or r40 = r20, r0
|
||||
or r41 = r21, r0
|
||||
;;
|
||||
|
||||
// actual call
|
||||
br.call.dptk.few b0 = b1
|
||||
;;
|
||||
|
||||
mov.i ar.pfs=r32
|
||||
mov b0=r33
|
||||
;;
|
||||
|
||||
br.ret.dptk.few b0
|
||||
;;
|
||||
|
||||
*/
|
||||
|
||||
static const gdb_byte ia64_hpux_dummy_code[] =
|
||||
{
|
||||
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00,
|
||||
0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x52,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x02, 0x30, 0x00, 0x00, 0x80, 0x05, 0x50, 0x00,
|
||||
0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x52,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28,
|
||||
0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0xaa, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02,
|
||||
0x00, 0x00, 0x29, 0x04, 0x80, 0x05, 0x10, 0x02,
|
||||
0x00, 0x62, 0x00, 0x40, 0xe4, 0x00, 0x38, 0x80,
|
||||
0x00, 0x18, 0x3d, 0x00, 0x0e, 0x20, 0x40, 0x82,
|
||||
0x00, 0x1c, 0x40, 0xa0, 0x14, 0x01, 0x38, 0x80,
|
||||
0x00, 0x30, 0x49, 0x00, 0x0e, 0x20, 0x70, 0x9a,
|
||||
0x00, 0x1c, 0x40, 0x00, 0x45, 0x01, 0x38, 0x80,
|
||||
0x0a, 0x48, 0x55, 0x00, 0x0e, 0x20, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x12,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x55, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x07,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x84, 0x02
|
||||
};
|
||||
|
||||
/* The offset to be used in order to get the __reason pseudo-register
|
||||
when using one of the *UREGS ttrace requests (see system header file
|
||||
/usr/include/ia64/sys/uregs.h for more details).
|
||||
|
||||
The documentation for this pseudo-register says that a nonzero value
|
||||
indicates that the thread stopped due to a fault, trap, or interrupt.
|
||||
A null value indicates a stop inside a syscall. */
|
||||
#define IA64_HPUX_UREG_REASON 0x00070000
|
||||
|
||||
/* Return nonzero if the value of the register identified by REGNUM
|
||||
can be modified. */
|
||||
|
||||
static int
|
||||
ia64_hpux_can_store_ar_register (int regnum)
|
||||
{
|
||||
switch (regnum)
|
||||
{
|
||||
case IA64_RSC_REGNUM:
|
||||
case IA64_RNAT_REGNUM:
|
||||
case IA64_CSD_REGNUM:
|
||||
case IA64_SSD_REGNUM:
|
||||
case IA64_CCV_REGNUM:
|
||||
case IA64_UNAT_REGNUM:
|
||||
case IA64_FPSR_REGNUM:
|
||||
case IA64_PFS_REGNUM:
|
||||
case IA64_LC_REGNUM:
|
||||
case IA64_EC_REGNUM:
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The "cannot_store_register" target_ops method. */
|
||||
|
||||
static int
|
||||
ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
|
||||
{
|
||||
/* General registers. */
|
||||
|
||||
if (regnum == IA64_GR0_REGNUM)
|
||||
return 1;
|
||||
|
||||
/* FP register. */
|
||||
|
||||
if (regnum == IA64_FR0_REGNUM || regnum == IA64_FR1_REGNUM)
|
||||
return 1;
|
||||
|
||||
/* Application registers. */
|
||||
if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_AR0_REGNUM + 127)
|
||||
return (!ia64_hpux_can_store_ar_register (regnum));
|
||||
|
||||
/* We can store all other registers. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if the inferior is stopped inside a system call. */
|
||||
|
||||
static int
|
||||
ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
struct target_ops *ops = ¤t_target;
|
||||
gdb_byte buf[8];
|
||||
int len;
|
||||
|
||||
len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL,
|
||||
buf, IA64_HPUX_UREG_REASON, sizeof (buf));
|
||||
if (len == -1)
|
||||
/* The target wasn't able to tell us. Assume we are not stopped
|
||||
in a system call, which is the normal situation. */
|
||||
return 0;
|
||||
gdb_assert (len == 8);
|
||||
|
||||
return (extract_unsigned_integer (buf, len, byte_order) == 0);
|
||||
}
|
||||
|
||||
/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */
|
||||
|
||||
static int
|
||||
ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
|
||||
ULONGEST cfm)
|
||||
{
|
||||
int sof;
|
||||
|
||||
if (frame_relative_level (this_frame) == 0
|
||||
&& ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
|
||||
/* If the inferior stopped in a system call, the base address
|
||||
of the register frame is at BSP - SOL instead of BSP - SOF.
|
||||
This is an HP-UX exception. */
|
||||
sof = (cfm & 0x3f80) >> 7;
|
||||
else
|
||||
sof = (cfm & 0x7f);
|
||||
|
||||
return sof;
|
||||
}
|
||||
|
||||
/* Implement the push_dummy_code gdbarch method.
|
||||
|
||||
This function assumes that the SP is already 16-byte-aligned. */
|
||||
|
||||
static CORE_ADDR
|
||||
ia64_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
|
||||
CORE_ADDR funaddr, struct value **args, int nargs,
|
||||
struct type *value_type, CORE_ADDR *real_pc,
|
||||
CORE_ADDR *bp_addr, struct regcache *regcache)
|
||||
{
|
||||
ULONGEST cfm;
|
||||
int sof, sol, sor, soo;
|
||||
gdb_byte buf[16];
|
||||
|
||||
regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
|
||||
sof = cfm & 0x7f;
|
||||
sol = (cfm >> 7) & 0x7f;
|
||||
sor = (cfm >> 14) & 0xf;
|
||||
soo = sof - sol - sor;
|
||||
|
||||
/* Reserve some space on the stack to hold the dummy code. */
|
||||
sp = sp - sizeof (ia64_hpux_dummy_code);
|
||||
|
||||
/* Set the breakpoint address at the first instruction of the bundle
|
||||
in the dummy code that has only nops. This is where the dummy code
|
||||
expects us to break. */
|
||||
*bp_addr = sp + 0x20;
|
||||
|
||||
/* Start the inferior function call from the dummy code. The dummy
|
||||
code will then call our function. */
|
||||
*real_pc = sp;
|
||||
|
||||
/* Transfer the dummy code to the inferior. */
|
||||
write_memory (sp, ia64_hpux_dummy_code, sizeof (ia64_hpux_dummy_code));
|
||||
|
||||
/* Update the size of the local portion of the register frame allocated
|
||||
by ``stub'' to match the size of the output region of the current
|
||||
register frame. This allows us to save the stacked registers.
|
||||
|
||||
The "alloc" instruction is located at slot 0 of the bundle at +0x30.
|
||||
Update the "sof" and "sol" portion of that instruction which are
|
||||
respectively at bits 18-24 and 25-31 of the bundle. */
|
||||
memcpy (buf, ia64_hpux_dummy_code + 0x30, sizeof (buf));
|
||||
|
||||
buf[2] |= ((soo & 0x3f) << 2);
|
||||
buf[3] |= (soo << 1);
|
||||
if (soo > 63)
|
||||
buf[3] |= 1;
|
||||
|
||||
write_memory (sp + 0x30, buf, sizeof (buf));
|
||||
|
||||
/* Return the new (already properly aligned) SP. */
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* The "allocate_new_rse_frame" ia64_infcall_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp,
|
||||
int sof)
|
||||
{
|
||||
/* We cannot change the value of the BSP register on HP-UX,
|
||||
so we can't allocate a new RSE frame. */
|
||||
}
|
||||
|
||||
/* The "store_argument_in_slot" ia64_infcall_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
|
||||
int slotnum, gdb_byte *buf)
|
||||
{
|
||||
/* The call sequence on this target expects us to place the arguments
|
||||
inside r14 - r21. */
|
||||
regcache_cooked_write (regcache, IA64_GR0_REGNUM + 14 + slotnum, buf);
|
||||
}
|
||||
|
||||
/* The "set_function_addr" ia64_infcall_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
|
||||
{
|
||||
/* The calling sequence calls the function whose address is placed
|
||||
in register b1. */
|
||||
regcache_cooked_write_unsigned (regcache, IA64_BR1_REGNUM, func_addr);
|
||||
}
|
||||
|
||||
/* The ia64_infcall_ops structure for ia64-hpux. */
|
||||
|
||||
static const struct ia64_infcall_ops ia64_hpux_infcall_ops =
|
||||
{
|
||||
ia64_hpux_allocate_new_rse_frame,
|
||||
ia64_hpux_store_argument_in_slot,
|
||||
ia64_hpux_set_function_addr
|
||||
};
|
||||
|
||||
/* The "dummy_id" gdbarch routine for ia64-hpux. */
|
||||
|
||||
static struct frame_id
|
||||
ia64_hpux_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR sp, pc, bp_addr, bsp;
|
||||
|
||||
sp = get_frame_register_unsigned (this_frame, IA64_GR12_REGNUM);
|
||||
|
||||
/* Just double-check that the frame PC is within a certain region
|
||||
of the stack that would be plausible for our dummy code (the dummy
|
||||
code was pushed at SP + 16). If not, then return a null frame ID.
|
||||
This is necessary in our case, because it is possible to produce
|
||||
the same frame ID for a normal frame, if that frame corresponds
|
||||
to the function called by our dummy code, and the function has not
|
||||
modified the registers that we use to build the dummy frame ID. */
|
||||
pc = get_frame_pc (this_frame);
|
||||
if (pc < sp + 16 || pc >= sp + 16 + sizeof (ia64_hpux_dummy_code))
|
||||
return null_frame_id;
|
||||
|
||||
/* The call sequence is such that the address of the dummy breakpoint
|
||||
we inserted is stored in r5. */
|
||||
bp_addr = get_frame_register_unsigned (this_frame, IA64_GR5_REGNUM);
|
||||
|
||||
bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
|
||||
|
||||
return frame_id_build_special (sp, bp_addr, bsp);
|
||||
}
|
||||
|
||||
/* Should be set to non-NULL if the ia64-hpux solib module is linked in.
|
||||
This may not be the case because the shared library support code can
|
||||
only be compiled on ia64-hpux. */
|
||||
|
||||
struct target_so_ops *ia64_hpux_so_ops = NULL;
|
||||
|
||||
/* The "find_global_pointer_from_solib" gdbarch_tdep routine for
|
||||
ia64-hpux. */
|
||||
|
||||
static CORE_ADDR
|
||||
ia64_hpux_find_global_pointer_from_solib (struct gdbarch *gdbarch,
|
||||
CORE_ADDR faddr)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
struct target_ops *ops = ¤t_target;
|
||||
gdb_byte buf[8];
|
||||
LONGEST len;
|
||||
|
||||
len = target_read (ops, TARGET_OBJECT_HPUX_SOLIB_GOT,
|
||||
paddress (gdbarch, faddr), buf, 0, sizeof (buf));
|
||||
|
||||
return extract_unsigned_integer (buf, len, byte_order);
|
||||
}
|
||||
|
||||
static void
|
||||
ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
|
||||
|
||||
set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
|
||||
set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
|
||||
|
||||
/* Inferior functions must be called from stack. */
|
||||
set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
|
||||
set_gdbarch_push_dummy_code (gdbarch, ia64_hpux_push_dummy_code);
|
||||
tdep->infcall_ops = ia64_hpux_infcall_ops;
|
||||
tdep->find_global_pointer_from_solib
|
||||
= ia64_hpux_find_global_pointer_from_solib;
|
||||
set_gdbarch_dummy_id (gdbarch, ia64_hpux_dummy_id);
|
||||
|
||||
if (ia64_hpux_so_ops)
|
||||
set_solib_ops (gdbarch, ia64_hpux_so_ops);
|
||||
}
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
extern initialize_file_ftype _initialize_ia64_hpux_tdep;
|
||||
|
||||
void
|
||||
_initialize_ia64_hpux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_ia64, 0, GDB_OSABI_HPUX_ELF,
|
||||
ia64_hpux_init_abi);
|
||||
}
|
@ -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
|
1224
gdb/inf-ttrace.c
1224
gdb/inf-ttrace.c
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -1,705 +0,0 @@
|
||||
/* Copyright (C) 2010-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "ia64-tdep.h"
|
||||
#include "ia64-hpux-tdep.h"
|
||||
#include "solib-ia64-hpux.h"
|
||||
#include "solist.h"
|
||||
#include "solib.h"
|
||||
#include "target.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "opcode/ia64.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "elf-bfd.h"
|
||||
|
||||
/* Need to define the following macro in order to get the complete
|
||||
load_module_desc struct definition in dlfcn.h Otherwise, it doesn't
|
||||
match the size of the struct the loader is providing us during load
|
||||
events. */
|
||||
#define _LOAD_MODULE_DESC_EXT
|
||||
|
||||
#include <sys/ttrace.h>
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <service_mgr.h>
|
||||
|
||||
/* The following is to have access to the definition of type load_info_t. */
|
||||
#include <crt0.h>
|
||||
|
||||
/* The r32 pseudo-register number.
|
||||
|
||||
Like all stacked registers, r32 is treated as a pseudo-register,
|
||||
because it is not always available for read/write via the ttrace
|
||||
interface. */
|
||||
/* This is a bit of a hack, as we duplicate something hidden inside
|
||||
ia64-tdep.c, but oh well... */
|
||||
#define IA64_R32_PSEUDO_REGNUM (IA64_NAT127_REGNUM + 2)
|
||||
|
||||
/* Our struct so_list private data structure. */
|
||||
|
||||
struct lm_info
|
||||
{
|
||||
/* The shared library module descriptor. We extract this structure
|
||||
from the loader at the time the shared library gets mapped. */
|
||||
struct load_module_desc module_desc;
|
||||
|
||||
/* The text segment address as defined in the shared library object
|
||||
(this is not the address where this segment got loaded). This
|
||||
field is initially set to zero, and computed lazily. */
|
||||
CORE_ADDR text_start;
|
||||
|
||||
/* The data segment address as defined in the shared library object
|
||||
(this is not the address where this segment got loaded). This
|
||||
field is initially set to zero, and computed lazily. */
|
||||
CORE_ADDR data_start;
|
||||
};
|
||||
|
||||
/* The list of shared libraries currently mapped by the inferior. */
|
||||
|
||||
static struct so_list *so_list_head = NULL;
|
||||
|
||||
/* Create a new so_list element. The result should be deallocated
|
||||
when no longer in use. */
|
||||
|
||||
static struct so_list *
|
||||
new_so_list (char *so_name, struct load_module_desc module_desc)
|
||||
{
|
||||
struct so_list *new_so;
|
||||
|
||||
new_so = (struct so_list *) XCNEW (struct so_list);
|
||||
new_so->lm_info = (struct lm_info *) XCNEW (struct lm_info);
|
||||
new_so->lm_info->module_desc = module_desc;
|
||||
|
||||
strncpy (new_so->so_name, so_name, SO_NAME_MAX_PATH_SIZE - 1);
|
||||
new_so->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
|
||||
strcpy (new_so->so_original_name, new_so->so_name);
|
||||
|
||||
return new_so;
|
||||
}
|
||||
|
||||
/* Return non-zero if the instruction at the current PC is a breakpoint
|
||||
part of the dynamic loading process.
|
||||
|
||||
We identify such instructions by checking that the instruction at
|
||||
the current pc is a break insn where no software breakpoint has been
|
||||
inserted by us. We also verify that the operands have specific
|
||||
known values, to be extra certain.
|
||||
|
||||
PTID is the ptid of the thread that should be checked, but this
|
||||
function also assumes that inferior_ptid is already equal to PTID.
|
||||
Ideally, we would like to avoid the requirement on inferior_ptid,
|
||||
but many routines still use the inferior_ptid global to access
|
||||
the relevant thread's register and memory. We still have the ptid
|
||||
as parameter to be able to pass it to the routines that do take a ptid
|
||||
- that way we avoid increasing explicit uses of the inferior_ptid
|
||||
global. */
|
||||
|
||||
static int
|
||||
ia64_hpux_at_dld_breakpoint_1_p (ptid_t ptid)
|
||||
{
|
||||
struct regcache *regcache = get_thread_regcache (ptid);
|
||||
CORE_ADDR pc = regcache_read_pc (regcache);
|
||||
struct address_space *aspace = get_regcache_aspace (regcache);
|
||||
ia64_insn t0, t1, slot[3], templ, insn;
|
||||
int slotnum;
|
||||
bfd_byte bundle[16];
|
||||
|
||||
/* If this is a regular breakpoint, then it can not be a dld one. */
|
||||
if (breakpoint_inserted_here_p (aspace, pc))
|
||||
return 0;
|
||||
|
||||
slotnum = ((long) pc) & 0xf;
|
||||
if (slotnum > 2)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"invalid slot (%d) for address %s", slotnum,
|
||||
paddress (get_regcache_arch (regcache), pc));
|
||||
|
||||
pc -= (pc & 0xf);
|
||||
read_memory (pc, bundle, sizeof (bundle));
|
||||
|
||||
/* bundles are always in little-endian byte order */
|
||||
t0 = bfd_getl64 (bundle);
|
||||
t1 = bfd_getl64 (bundle + 8);
|
||||
templ = (t0 >> 1) & 0xf;
|
||||
slot[0] = (t0 >> 5) & 0x1ffffffffffLL;
|
||||
slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
|
||||
slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
|
||||
|
||||
if (templ == 2 && slotnum == 1)
|
||||
{
|
||||
/* skip L slot in MLI template: */
|
||||
slotnum = 2;
|
||||
}
|
||||
|
||||
insn = slot[slotnum];
|
||||
|
||||
return (insn == 0x1c0c9c0 /* break.i 0x070327 */
|
||||
|| insn == 0x3c0c9c0); /* break.i 0x0f0327 */
|
||||
}
|
||||
|
||||
/* Same as ia64_hpux_at_dld_breakpoint_1_p above, with the following
|
||||
differences: It temporarily sets inferior_ptid to PTID, and also
|
||||
contains any exception being raised. */
|
||||
|
||||
int
|
||||
ia64_hpux_at_dld_breakpoint_p (ptid_t ptid)
|
||||
{
|
||||
ptid_t saved_ptid = inferior_ptid;
|
||||
int result = 0;
|
||||
|
||||
inferior_ptid = ptid;
|
||||
TRY
|
||||
{
|
||||
result = ia64_hpux_at_dld_breakpoint_1_p (ptid);
|
||||
}
|
||||
inferior_ptid = saved_ptid;
|
||||
CATCH (e, RETURN_MASK_ALL)
|
||||
{
|
||||
warning (_("error while checking for dld breakpoint: %s"), e.message);
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Handler for library load event: Read the information provided by
|
||||
the loader, and then use it to read the shared library symbols. */
|
||||
|
||||
static void
|
||||
ia64_hpux_handle_load_event (struct regcache *regcache)
|
||||
{
|
||||
CORE_ADDR module_desc_addr;
|
||||
ULONGEST module_desc_size;
|
||||
CORE_ADDR so_path_addr;
|
||||
char so_path[PATH_MAX];
|
||||
struct load_module_desc module_desc;
|
||||
struct so_list *new_so;
|
||||
|
||||
/* Extract the data provided by the loader as follow:
|
||||
- r33: Address of load_module_desc structure
|
||||
- r34: size of struct load_module_desc
|
||||
- r35: Address of string holding shared library path
|
||||
*/
|
||||
regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 1,
|
||||
&module_desc_addr);
|
||||
regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 2,
|
||||
&module_desc_size);
|
||||
regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM + 3,
|
||||
&so_path_addr);
|
||||
|
||||
if (module_desc_size != sizeof (struct load_module_desc))
|
||||
warning (_("load_module_desc size (%ld) != size returned by kernel (%s)"),
|
||||
sizeof (struct load_module_desc),
|
||||
pulongest (module_desc_size));
|
||||
|
||||
read_memory_string (so_path_addr, so_path, PATH_MAX);
|
||||
read_memory (module_desc_addr, (gdb_byte *) &module_desc,
|
||||
sizeof (module_desc));
|
||||
|
||||
/* Create a new so_list element and insert it at the start of our
|
||||
so_list_head (we insert at the start of the list only because
|
||||
it is less work compared to inserting it elsewhere). */
|
||||
new_so = new_so_list (so_path, module_desc);
|
||||
new_so->next = so_list_head;
|
||||
so_list_head = new_so;
|
||||
}
|
||||
|
||||
/* Update the value of the PC to point to the begining of the next
|
||||
instruction bundle. */
|
||||
|
||||
static void
|
||||
ia64_hpux_move_pc_to_next_bundle (struct regcache *regcache)
|
||||
{
|
||||
CORE_ADDR pc = regcache_read_pc (regcache);
|
||||
|
||||
pc -= pc & 0xf;
|
||||
pc += 16;
|
||||
ia64_write_pc (regcache, pc);
|
||||
}
|
||||
|
||||
/* Handle loader events.
|
||||
|
||||
PTID is the ptid of the thread corresponding to the event being
|
||||
handled. Similarly to ia64_hpux_at_dld_breakpoint_1_p, this
|
||||
function assumes that inferior_ptid is set to PTID. */
|
||||
|
||||
static void
|
||||
ia64_hpux_handle_dld_breakpoint_1 (ptid_t ptid)
|
||||
{
|
||||
struct regcache *regcache = get_thread_regcache (ptid);
|
||||
ULONGEST arg0;
|
||||
|
||||
/* The type of event is provided by the loaded via r32. */
|
||||
regcache_cooked_read_unsigned (regcache, IA64_R32_PSEUDO_REGNUM, &arg0);
|
||||
switch (arg0)
|
||||
{
|
||||
case BREAK_DE_SVC_LOADED:
|
||||
/* Currently, the only service loads are uld and dld,
|
||||
so we shouldn't need to do anything. Just ignore. */
|
||||
break;
|
||||
case BREAK_DE_LIB_LOADED:
|
||||
ia64_hpux_handle_load_event (regcache);
|
||||
solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
||||
break;
|
||||
case BREAK_DE_LIB_UNLOADED:
|
||||
case BREAK_DE_LOAD_COMPLETE:
|
||||
case BREAK_DE_BOR:
|
||||
/* Ignore for now. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now that we have handled the event, we can move the PC to
|
||||
the next instruction bundle, past the break instruction. */
|
||||
ia64_hpux_move_pc_to_next_bundle (regcache);
|
||||
}
|
||||
|
||||
/* Same as ia64_hpux_handle_dld_breakpoint_1 above, with the following
|
||||
differences: This function temporarily sets inferior_ptid to PTID,
|
||||
and also contains any exception. */
|
||||
|
||||
void
|
||||
ia64_hpux_handle_dld_breakpoint (ptid_t ptid)
|
||||
{
|
||||
ptid_t saved_ptid = inferior_ptid;
|
||||
|
||||
inferior_ptid = ptid;
|
||||
TRY
|
||||
{
|
||||
ia64_hpux_handle_dld_breakpoint_1 (ptid);
|
||||
}
|
||||
inferior_ptid = saved_ptid;
|
||||
CATCH (e, RETURN_MASK_ALL)
|
||||
{
|
||||
warning (_("error detected while handling dld breakpoint: %s"), e.message);
|
||||
}
|
||||
END_CATCH
|
||||
}
|
||||
|
||||
/* Find the address of the code and data segments in ABFD, and update
|
||||
TEXT_START and DATA_START accordingly. */
|
||||
|
||||
static void
|
||||
ia64_hpux_find_start_vma (bfd *abfd, CORE_ADDR *text_start,
|
||||
CORE_ADDR *data_start)
|
||||
{
|
||||
Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
|
||||
Elf64_Phdr phdr;
|
||||
int i;
|
||||
|
||||
*text_start = 0;
|
||||
*data_start = 0;
|
||||
|
||||
if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1)
|
||||
error (_("invalid program header offset in %s"), abfd->filename);
|
||||
|
||||
for (i = 0; i < i_ehdrp->e_phnum; i++)
|
||||
{
|
||||
if (bfd_bread (&phdr, sizeof (phdr), abfd) != sizeof (phdr))
|
||||
error (_("failed to read segment %d in %s"), i, abfd->filename);
|
||||
|
||||
if (phdr.p_flags & PF_X
|
||||
&& (*text_start == 0 || phdr.p_vaddr < *text_start))
|
||||
*text_start = phdr.p_vaddr;
|
||||
|
||||
if (phdr.p_flags & PF_W
|
||||
&& (*data_start == 0 || phdr.p_vaddr < *data_start))
|
||||
*data_start = phdr.p_vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* The "relocate_section_addresses" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_relocate_section_addresses (struct so_list *so,
|
||||
struct target_section *sec)
|
||||
{
|
||||
CORE_ADDR offset = 0;
|
||||
|
||||
/* If we haven't computed the text & data segment addresses, do so now.
|
||||
We do this here, because we now have direct access to the associated
|
||||
bfd, whereas we would have had to open our own if we wanted to do it
|
||||
while processing the library-load event. */
|
||||
if (so->lm_info->text_start == 0 && so->lm_info->data_start == 0)
|
||||
ia64_hpux_find_start_vma (sec->the_bfd_section->owner,
|
||||
&so->lm_info->text_start,
|
||||
&so->lm_info->data_start);
|
||||
|
||||
/* Determine the relocation offset based on which segment
|
||||
the section belongs to. */
|
||||
if ((so->lm_info->text_start < so->lm_info->data_start
|
||||
&& sec->addr < so->lm_info->data_start)
|
||||
|| (so->lm_info->text_start > so->lm_info->data_start
|
||||
&& sec->addr >= so->lm_info->text_start))
|
||||
offset = so->lm_info->module_desc.text_base - so->lm_info->text_start;
|
||||
else if ((so->lm_info->text_start < so->lm_info->data_start
|
||||
&& sec->addr >= so->lm_info->data_start)
|
||||
|| (so->lm_info->text_start > so->lm_info->data_start
|
||||
&& sec->addr < so->lm_info->text_start))
|
||||
offset = so->lm_info->module_desc.data_base - so->lm_info->data_start;
|
||||
|
||||
/* And now apply the relocation. */
|
||||
sec->addr += offset;
|
||||
sec->endaddr += offset;
|
||||
|
||||
/* Best effort to set addr_high/addr_low. This is used only by
|
||||
'info sharedlibrary'. */
|
||||
if (so->addr_low == 0 || sec->addr < so->addr_low)
|
||||
so->addr_low = sec->addr;
|
||||
|
||||
if (so->addr_high == 0 || sec->endaddr > so->addr_high)
|
||||
so->addr_high = sec->endaddr;
|
||||
}
|
||||
|
||||
/* The "free_so" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_free_so (struct so_list *so)
|
||||
{
|
||||
xfree (so->lm_info);
|
||||
}
|
||||
|
||||
/* The "clear_solib" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_clear_solib (void)
|
||||
{
|
||||
struct so_list *so;
|
||||
|
||||
while (so_list_head != NULL)
|
||||
{
|
||||
so = so_list_head;
|
||||
so_list_head = so_list_head->next;
|
||||
|
||||
ia64_hpux_free_so (so);
|
||||
xfree (so);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assuming the inferior just stopped on an EXEC event, return
|
||||
the address of the load_info_t structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
ia64_hpux_get_load_info_addr (void)
|
||||
{
|
||||
struct type *data_ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
|
||||
CORE_ADDR addr;
|
||||
int status;
|
||||
|
||||
/* The address of the load_info_t structure is stored in the 4th
|
||||
argument passed to the initial thread of the process (in other
|
||||
words, in argv[3]). So get the address of these arguments,
|
||||
and extract the 4th one. */
|
||||
status = ttrace (TT_PROC_GET_ARGS, ptid_get_pid (inferior_ptid),
|
||||
0, (uintptr_t) &addr, sizeof (CORE_ADDR), 0);
|
||||
if (status == -1 && errno)
|
||||
perror_with_name (_("Unable to get argument list"));
|
||||
return (read_memory_typed_address (addr + 3 * 8, data_ptr_type));
|
||||
}
|
||||
|
||||
/* A structure used to aggregate some information extracted from
|
||||
the dynamic section of the main executable. */
|
||||
|
||||
struct dld_info
|
||||
{
|
||||
ULONGEST dld_flags;
|
||||
CORE_ADDR load_map;
|
||||
};
|
||||
|
||||
/* Scan the ".dynamic" section referenced by ABFD and DYN_SECT,
|
||||
and extract the information needed to fill in INFO. */
|
||||
|
||||
static void
|
||||
ia64_hpux_read_dynamic_info (struct gdbarch *gdbarch, bfd *abfd,
|
||||
asection *dyn_sect, struct dld_info *info)
|
||||
{
|
||||
int sect_size;
|
||||
char *buf;
|
||||
char *buf_end;
|
||||
|
||||
/* Make sure that info always has initialized data, even if we fail
|
||||
to read the syn_sect section. */
|
||||
memset (info, 0, sizeof (struct dld_info));
|
||||
|
||||
sect_size = bfd_section_size (abfd, dyn_sect);
|
||||
buf = alloca (sect_size);
|
||||
buf_end = buf + sect_size;
|
||||
|
||||
if (bfd_seek (abfd, dyn_sect->filepos, SEEK_SET) != 0
|
||||
|| bfd_bread (buf, sect_size, abfd) != sect_size)
|
||||
error (_("failed to read contents of .dynamic section"));
|
||||
|
||||
for (; buf < buf_end; buf += sizeof (Elf64_Dyn))
|
||||
{
|
||||
Elf64_Dyn *dynp = (Elf64_Dyn *) buf;
|
||||
Elf64_Sxword d_tag;
|
||||
|
||||
d_tag = bfd_h_get_64 (abfd, &dynp->d_tag);
|
||||
switch (d_tag)
|
||||
{
|
||||
case DT_HP_DLD_FLAGS:
|
||||
info->dld_flags = bfd_h_get_64 (abfd, &dynp->d_un);
|
||||
break;
|
||||
|
||||
case DT_HP_LOAD_MAP:
|
||||
{
|
||||
CORE_ADDR load_map_addr = bfd_h_get_64 (abfd, &dynp->d_un.d_ptr);
|
||||
|
||||
if (target_read_memory (load_map_addr,
|
||||
(gdb_byte *) &info->load_map,
|
||||
sizeof (info->load_map)) != 0)
|
||||
error (_("failed to read load map at %s"),
|
||||
paddress (gdbarch, load_map_addr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrapper around target_read_memory used with libdl. */
|
||||
|
||||
static void *
|
||||
ia64_hpux_read_tgt_mem (void *buffer, uint64_t ptr, size_t bufsiz, int ident)
|
||||
{
|
||||
if (target_read_memory (ptr, (gdb_byte *) buffer, bufsiz) != 0)
|
||||
return 0;
|
||||
else
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Create a new so_list object for a shared library, and store that
|
||||
new so_list object in our SO_LIST_HEAD list.
|
||||
|
||||
SO_INDEX is an index specifying the placement of the loaded shared
|
||||
library in the dynamic loader's search list. Normally, this index
|
||||
is strictly positive, but an index of -1 refers to the loader itself.
|
||||
|
||||
Return nonzero if the so_list object could be created. A null
|
||||
return value with a positive SO_INDEX normally means that there are
|
||||
no more entries in the dynamic loader's search list at SO_INDEX or
|
||||
beyond. */
|
||||
|
||||
static int
|
||||
ia64_hpux_add_so_from_dld_info (struct dld_info info, int so_index)
|
||||
{
|
||||
struct load_module_desc module_desc;
|
||||
uint64_t so_handle;
|
||||
char *so_path;
|
||||
struct so_list *so;
|
||||
|
||||
so_handle = dlgetmodinfo (so_index, &module_desc, sizeof (module_desc),
|
||||
ia64_hpux_read_tgt_mem, 0, info.load_map);
|
||||
|
||||
if (so_handle == 0)
|
||||
/* No such entry. We probably reached the end of the list. */
|
||||
return 0;
|
||||
|
||||
so_path = dlgetname (&module_desc, sizeof (module_desc),
|
||||
ia64_hpux_read_tgt_mem, 0, info.load_map);
|
||||
if (so_path == NULL)
|
||||
{
|
||||
/* Should never happen, but let's not crash if it does. */
|
||||
warning (_("unable to get shared library name, symbols not loaded"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a new so_list and insert it at the start of our list.
|
||||
The order is not extremely important, but it's less work to do so
|
||||
at the end of the list. */
|
||||
so = new_so_list (so_path, module_desc);
|
||||
so->next = so_list_head;
|
||||
so_list_head = so;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Assuming we just attached to a process, update our list of shared
|
||||
libraries (SO_LIST_HEAD) as well as GDB's list. */
|
||||
|
||||
static void
|
||||
ia64_hpux_solib_add_after_attach (void)
|
||||
{
|
||||
bfd *abfd;
|
||||
asection *dyn_sect;
|
||||
struct dld_info info;
|
||||
int i;
|
||||
|
||||
if (symfile_objfile == NULL)
|
||||
return;
|
||||
|
||||
abfd = symfile_objfile->obfd;
|
||||
dyn_sect = bfd_get_section_by_name (abfd, ".dynamic");
|
||||
|
||||
if (dyn_sect == NULL || bfd_section_size (abfd, dyn_sect) == 0)
|
||||
return;
|
||||
|
||||
ia64_hpux_read_dynamic_info (get_objfile_arch (symfile_objfile), abfd,
|
||||
dyn_sect, &info);
|
||||
|
||||
if ((info.dld_flags & DT_HP_DEBUG_PRIVATE) == 0)
|
||||
{
|
||||
warning (_(
|
||||
"The shared libraries were not privately mapped; setting a breakpoint\n\
|
||||
in a shared library will not work until you rerun the program.\n\
|
||||
Use the following command to enable debugging of shared libraries.\n\
|
||||
chatr +dbg enable a.out"));
|
||||
}
|
||||
|
||||
/* Read the symbols of the dynamic loader (dld.so). */
|
||||
ia64_hpux_add_so_from_dld_info (info, -1);
|
||||
|
||||
/* Read the symbols of all the other shared libraries. */
|
||||
for (i = 1; ; i++)
|
||||
if (!ia64_hpux_add_so_from_dld_info (info, i))
|
||||
break; /* End of list. */
|
||||
|
||||
/* Resync the library list at the core level. */
|
||||
solib_add (NULL, 1, ¤t_target, auto_solib_add);
|
||||
}
|
||||
|
||||
/* The "create_inferior_hook" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_solib_create_inferior_hook (int from_tty)
|
||||
{
|
||||
CORE_ADDR load_info_addr;
|
||||
load_info_t load_info;
|
||||
|
||||
/* Initially, we were thinking about adding a check that the program
|
||||
(accessible through symfile_objfile) was linked against some shared
|
||||
libraries, by searching for a ".dynamic" section. However, could
|
||||
this break in the case of a statically linked program that later
|
||||
uses dlopen? Programs that are fully statically linked are very
|
||||
rare, and we will worry about them when we encounter one that
|
||||
causes trouble. */
|
||||
|
||||
/* Set the LI_TRACE flag in the load_info_t structure. This enables
|
||||
notifications when shared libraries are being mapped. */
|
||||
load_info_addr = ia64_hpux_get_load_info_addr ();
|
||||
read_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
|
||||
load_info.li_flags |= LI_TRACE;
|
||||
write_memory (load_info_addr, (gdb_byte *) &load_info, sizeof (load_info));
|
||||
|
||||
/* If we just attached to our process, some shard libraries have
|
||||
already been mapped. Find which ones they are... */
|
||||
if (current_inferior ()->attach_flag)
|
||||
ia64_hpux_solib_add_after_attach ();
|
||||
}
|
||||
|
||||
/* The "special_symbol_handling" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static void
|
||||
ia64_hpux_special_symbol_handling (void)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
/* The "current_sos" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static struct so_list *
|
||||
ia64_hpux_current_sos (void)
|
||||
{
|
||||
/* Return a deep copy of our own list. */
|
||||
struct so_list *new_head = NULL, *prev_new_so = NULL;
|
||||
struct so_list *our_so;
|
||||
|
||||
for (our_so = so_list_head; our_so != NULL; our_so = our_so->next)
|
||||
{
|
||||
struct so_list *new_so;
|
||||
|
||||
new_so = new_so_list (our_so->so_name, our_so->lm_info->module_desc);
|
||||
if (prev_new_so != NULL)
|
||||
prev_new_so->next = new_so;
|
||||
prev_new_so = new_so;
|
||||
if (new_head == NULL)
|
||||
new_head = new_so;
|
||||
}
|
||||
|
||||
return new_head;
|
||||
}
|
||||
|
||||
/* The "open_symbol_file_object" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static int
|
||||
ia64_hpux_open_symbol_file_object (void *from_ttyp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The "in_dynsym_resolve_code" target_so_ops routine for ia64-hpux. */
|
||||
|
||||
static int
|
||||
ia64_hpux_in_dynsym_resolve_code (CORE_ADDR pc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If FADDR is the address of a function inside one of the shared
|
||||
libraries, return the shared library linkage address. */
|
||||
|
||||
CORE_ADDR
|
||||
ia64_hpux_get_solib_linkage_addr (CORE_ADDR faddr)
|
||||
{
|
||||
struct so_list *so = so_list_head;
|
||||
|
||||
while (so != NULL)
|
||||
{
|
||||
struct load_module_desc module_desc = so->lm_info->module_desc;
|
||||
|
||||
if (module_desc.text_base <= faddr
|
||||
&& (module_desc.text_base + module_desc.text_size) > faddr)
|
||||
return module_desc.linkage_ptr;
|
||||
|
||||
so = so->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a new target_so_ops structure suitable for ia64-hpux, and
|
||||
return its address. */
|
||||
|
||||
static struct target_so_ops *
|
||||
ia64_hpux_target_so_ops (void)
|
||||
{
|
||||
struct target_so_ops *ops = XCNEW (struct target_so_ops);
|
||||
|
||||
ops->relocate_section_addresses = ia64_hpux_relocate_section_addresses;
|
||||
ops->free_so = ia64_hpux_free_so;
|
||||
ops->clear_solib = ia64_hpux_clear_solib;
|
||||
ops->solib_create_inferior_hook = ia64_hpux_solib_create_inferior_hook;
|
||||
ops->special_symbol_handling = ia64_hpux_special_symbol_handling;
|
||||
ops->current_sos = ia64_hpux_current_sos;
|
||||
ops->open_symbol_file_object = ia64_hpux_open_symbol_file_object;
|
||||
ops->in_dynsym_resolve_code = ia64_hpux_in_dynsym_resolve_code;
|
||||
ops->bfd_open = solib_bfd_open;
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
/* Prevent warning from -Wmissing-prototypes. */
|
||||
void _initialize_solib_ia64_hpux (void);
|
||||
|
||||
void
|
||||
_initialize_solib_ia64_hpux (void)
|
||||
{
|
||||
ia64_hpux_so_ops = ia64_hpux_target_so_ops ();
|
||||
}
|
@ -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
|
654
gdb/solib-pa64.c
654
gdb/solib-pa64.c
@ -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
|
@ -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
|
891
gdb/solib-som.c
891
gdb/solib-som.c
@ -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;
|
||||
}
|
@ -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
|
||||
|
547
gdb/somread.c
547
gdb/somread.c
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user