+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).
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
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 \
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 \
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 \
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 \
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 \
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 \
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 \
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 \
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 \
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 \
@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
+++ /dev/null
-# Host: ia64 running HP-UX
-NATDEPFILES= fork-child.o inf-ttrace.o ia64-hpux-nat.o \
- solib-ia64-hpux.o
+++ /dev/null
-# Host: PA-RISC HP-UX
-NATDEPFILES= fork-child.o inf-ptrace.o inf-ttrace.o \
- hppa-hpux-nat.o
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; }
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}"
# 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,
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}"
vax-*-bsd* | \
vax-*-netbsd* | \
vax-*-ultrix* | \
+ hppa*-*-hpux* | \
+ ia64-*-hpux* | \
null)
echo "*** Configuration $host is obsolete." >&2
echo "*** Support has been REMOVED." >&2
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 ;;
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 ;;
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
mips*-*-pe | \
rs6000-*-lynxos* | \
sh*-*-pe | \
+ hppa*-*-hpux* | \
+ ia64-*-hpux* | \
null)
echo "*** Configuration $targ is obsolete." >&2
echo "*** Support has been REMOVED." >&2
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 \
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 \
+++ /dev/null
-/* 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);
-}
-
-\f
-
-/* 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);
-}
+++ /dev/null
-/* Target-dependent code for HP-UX on PA-RISC.
-
- Copyright (C) 2002-2015 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "defs.h"
-#include "arch-utils.h"
-#include "gdbcore.h"
-#include "osabi.h"
-#include "frame.h"
-#include "frame-unwind.h"
-#include "trad-frame.h"
-#include "symtab.h"
-#include "objfiles.h"
-#include "inferior.h"
-#include "infcall.h"
-#include "observer.h"
-#include "hppa-tdep.h"
-#include "solib-som.h"
-#include "solib-pa64.h"
-#include "regset.h"
-#include "regcache.h"
-
-#define IS_32BIT_TARGET(_gdbarch) \
- ((gdbarch_tdep (_gdbarch))->bytes_per_address == 4)
-
-/* Bit in the `ss_flag' member of `struct save_state' that indicates
- that the 64-bit register values are live. From
- <machine/save_state.h>. */
-#define HPPA_HPUX_SS_WIDEREGS 0x40
-
-/* Offsets of various parts of `struct save_state'. From
- <machine/save_state.h>. */
-#define HPPA_HPUX_SS_FLAGS_OFFSET 0
-#define HPPA_HPUX_SS_NARROW_OFFSET 4
-#define HPPA_HPUX_SS_FPBLOCK_OFFSET 256
-#define HPPA_HPUX_SS_WIDE_OFFSET 640
-
-/* The size of `struct save_state. */
-#define HPPA_HPUX_SAVE_STATE_SIZE 1152
-
-/* The size of `struct pa89_save_state', which corresponds to PA-RISC
- 1.1, the lowest common denominator that we support. */
-#define HPPA_HPUX_PA89_SAVE_STATE_SIZE 512
-
-
-/* Forward declarations. */
-extern void _initialize_hppa_hpux_tdep (void);
-extern initialize_file_ftype _initialize_hppa_hpux_tdep;
-
-/* Return one if PC is in the call path of a trampoline, else return zero.
-
- Note we return one for *any* call trampoline (long-call, arg-reloc), not
- just shared library trampolines (import, export). */
-
-static int
-hppa32_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct bound_minimal_symbol minsym;
- struct unwind_table_entry *u;
-
- /* First see if PC is in one of the two C-library trampolines. */
- if (pc == hppa_symbol_address("$$dyncall")
- || pc == hppa_symbol_address("_sr4export"))
- return 1;
-
- minsym = lookup_minimal_symbol_by_pc (pc);
- if (minsym.minsym
- && strcmp (MSYMBOL_LINKAGE_NAME (minsym.minsym), ".stub") == 0)
- return 1;
-
- /* Get the unwind descriptor corresponding to PC, return zero
- if no unwind was found. */
- u = find_unwind_entry (pc);
- if (!u)
- return 0;
-
- /* If this isn't a linker stub, then return now. */
- if (u->stub_unwind.stub_type == 0)
- return 0;
-
- /* By definition a long-branch stub is a call stub. */
- if (u->stub_unwind.stub_type == LONG_BRANCH)
- return 1;
-
- /* The call and return path execute the same instructions within
- an IMPORT stub! So an IMPORT stub is both a call and return
- trampoline. */
- if (u->stub_unwind.stub_type == IMPORT)
- return 1;
-
- /* Parameter relocation stubs always have a call path and may have a
- return path. */
- if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
- || u->stub_unwind.stub_type == EXPORT)
- {
- CORE_ADDR addr;
-
- /* Search forward from the current PC until we hit a branch
- or the end of the stub. */
- for (addr = pc; addr <= u->region_end; addr += 4)
- {
- unsigned long insn;
-
- insn = read_memory_integer (addr, 4, byte_order);
-
- /* Does it look like a bl? If so then it's the call path, if
- we find a bv or be first, then we're on the return path. */
- if ((insn & 0xfc00e000) == 0xe8000000)
- return 1;
- else if ((insn & 0xfc00e001) == 0xe800c000
- || (insn & 0xfc000000) == 0xe0000000)
- return 0;
- }
-
- /* Should never happen. */
- warning (_("Unable to find branch in parameter relocation stub."));
- return 0;
- }
-
- /* Unknown stub type. For now, just return zero. */
- return 0;
-}
-
-static int
-hppa64_hpux_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-
- /* PA64 has a completely different stub/trampoline scheme. Is it
- better? Maybe. It's certainly harder to determine with any
- certainty that we are in a stub because we can not refer to the
- unwinders to help.
-
- The heuristic is simple. Try to lookup the current PC value in th
- minimal symbol table. If that fails, then assume we are not in a
- stub and return.
-
- Then see if the PC value falls within the section bounds for the
- section containing the minimal symbol we found in the first
- step. If it does, then assume we are not in a stub and return.
-
- Finally peek at the instructions to see if they look like a stub. */
- struct bound_minimal_symbol minsym;
- asection *sec;
- CORE_ADDR addr;
- int insn;
-
- minsym = lookup_minimal_symbol_by_pc (pc);
- if (! minsym.minsym)
- return 0;
-
- sec = MSYMBOL_OBJ_SECTION (minsym.objfile, minsym.minsym)->the_bfd_section;
-
- if (bfd_get_section_vma (sec->owner, sec) <= pc
- && pc < (bfd_get_section_vma (sec->owner, sec)
- + bfd_section_size (sec->owner, sec)))
- return 0;
-
- /* We might be in a stub. Peek at the instructions. Stubs are 3
- instructions long. */
- insn = read_memory_integer (pc, 4, byte_order);
-
- /* Find out where we think we are within the stub. */
- if ((insn & 0xffffc00e) == 0x53610000)
- addr = pc;
- else if ((insn & 0xffffffff) == 0xe820d000)
- addr = pc - 4;
- else if ((insn & 0xffffc00e) == 0x537b0000)
- addr = pc - 8;
- else
- return 0;
-
- /* Now verify each insn in the range looks like a stub instruction. */
- insn = read_memory_integer (addr, 4, byte_order);
- if ((insn & 0xffffc00e) != 0x53610000)
- return 0;
-
- /* Now verify each insn in the range looks like a stub instruction. */
- insn = read_memory_integer (addr + 4, 4, byte_order);
- if ((insn & 0xffffffff) != 0xe820d000)
- return 0;
-
- /* Now verify each insn in the range looks like a stub instruction. */
- insn = read_memory_integer (addr + 8, 4, byte_order);
- if ((insn & 0xffffc00e) != 0x537b0000)
- return 0;
-
- /* Looks like a stub. */
- return 1;
-}
-
-/* Return one if PC is in the return path of a trampoline, else return zero.
-
- Note we return one for *any* call trampoline (long-call, arg-reloc), not
- just shared library trampolines (import, export). */
-
-static int
-hppa_hpux_in_solib_return_trampoline (struct gdbarch *gdbarch,
- CORE_ADDR pc, const char *name)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct unwind_table_entry *u;
-
- /* Get the unwind descriptor corresponding to PC, return zero
- if no unwind was found. */
- u = find_unwind_entry (pc);
- if (!u)
- return 0;
-
- /* If this isn't a linker stub or it's just a long branch stub, then
- return zero. */
- if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH)
- return 0;
-
- /* The call and return path execute the same instructions within
- an IMPORT stub! So an IMPORT stub is both a call and return
- trampoline. */
- if (u->stub_unwind.stub_type == IMPORT)
- return 1;
-
- /* Parameter relocation stubs always have a call path and may have a
- return path. */
- if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
- || u->stub_unwind.stub_type == EXPORT)
- {
- CORE_ADDR addr;
-
- /* Search forward from the current PC until we hit a branch
- or the end of the stub. */
- for (addr = pc; addr <= u->region_end; addr += 4)
- {
- unsigned long insn;
-
- insn = read_memory_integer (addr, 4, byte_order);
-
- /* Does it look like a bl? If so then it's the call path, if
- we find a bv or be first, then we're on the return path. */
- if ((insn & 0xfc00e000) == 0xe8000000)
- return 0;
- else if ((insn & 0xfc00e001) == 0xe800c000
- || (insn & 0xfc000000) == 0xe0000000)
- return 1;
- }
-
- /* Should never happen. */
- warning (_("Unable to find branch in parameter relocation stub."));
- return 0;
- }
-
- /* Unknown stub type. For now, just return zero. */
- return 0;
-
-}
-
-/* Figure out if PC is in a trampoline, and if so find out where
- the trampoline will jump to. If not in a trampoline, return zero.
-
- Simple code examination probably is not a good idea since the code
- sequences in trampolines can also appear in user code.
-
- We use unwinds and information from the minimal symbol table to
- determine when we're in a trampoline. This won't work for ELF
- (yet) since it doesn't create stub unwind entries. Whether or
- not ELF will create stub unwinds or normal unwinds for linker
- stubs is still being debated.
-
- This should handle simple calls through dyncall or sr4export,
- long calls, argument relocation stubs, and dyncall/sr4export
- calling an argument relocation stub. It even handles some stubs
- used in dynamic executables. */
-
-static CORE_ADDR
-hppa_hpux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
-{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int word_size = gdbarch_ptr_bit (gdbarch) / 8;
- long orig_pc = pc;
- long prev_inst, curr_inst, loc;
- struct bound_minimal_symbol msym;
- struct unwind_table_entry *u;
-
- /* Addresses passed to dyncall may *NOT* be the actual address
- of the function. So we may have to do something special. */
- if (pc == hppa_symbol_address("$$dyncall"))
- {
- pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22);
-
- /* If bit 30 (counting from the left) is on, then pc is the address of
- the PLT entry for this function, not the address of the function
- itself. Bit 31 has meaning too, but only for MPE. */
- if (pc & 0x2)
- pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, word_size,
- byte_order);
- }
- if (pc == hppa_symbol_address("$$dyncall_external"))
- {
- pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22);
- pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, word_size, byte_order);
- }
- else if (pc == hppa_symbol_address("_sr4export"))
- pc = (CORE_ADDR) get_frame_register_unsigned (frame, 22);
-
- /* Get the unwind descriptor corresponding to PC, return zero
- if no unwind was found. */
- u = find_unwind_entry (pc);
- if (!u)
- return 0;
-
- /* If this isn't a linker stub, then return now. */
- /* elz: attention here! (FIXME) because of a compiler/linker
- error, some stubs which should have a non zero stub_unwind.stub_type
- have unfortunately a value of zero. So this function would return here
- as if we were not in a trampoline. To fix this, we go look at the partial
- symbol information, which reports this guy as a stub.
- (FIXME): Unfortunately, we are not that lucky: it turns out that the
- partial symbol information is also wrong sometimes. This is because
- when it is entered (somread.c::som_symtab_read()) it can happen that
- if the type of the symbol (from the som) is Entry, and the symbol is
- in a shared library, then it can also be a trampoline. This would be OK,
- except that I believe the way they decide if we are ina shared library
- does not work. SOOOO..., even if we have a regular function w/o
- trampolines its minimal symbol can be assigned type mst_solib_trampoline.
- Also, if we find that the symbol is a real stub, then we fix the unwind
- descriptor, and define the stub type to be EXPORT.
- Hopefully this is correct most of the times. */
- if (u->stub_unwind.stub_type == 0)
- {
-
-/* elz: NOTE (FIXME!) once the problem with the unwind information is fixed
- we can delete all the code which appears between the lines. */
-/*--------------------------------------------------------------------------*/
- msym = lookup_minimal_symbol_by_pc (pc);
-
- if (msym.minsym == NULL
- || MSYMBOL_TYPE (msym.minsym) != mst_solib_trampoline)
- return orig_pc == pc ? 0 : pc & ~0x3;
-
- else if (msym.minsym != NULL
- && MSYMBOL_TYPE (msym.minsym) == mst_solib_trampoline)
- {
- struct objfile *objfile;
- struct minimal_symbol *msymbol;
- int function_found = 0;
-
- /* Go look if there is another minimal symbol with the same name as
- this one, but with type mst_text. This would happen if the msym
- is an actual trampoline, in which case there would be another
- symbol with the same name corresponding to the real function. */
-
- ALL_MSYMBOLS (objfile, msymbol)
- {
- if (MSYMBOL_TYPE (msymbol) == mst_text
- && strcmp (MSYMBOL_LINKAGE_NAME (msymbol),
- MSYMBOL_LINKAGE_NAME (msym.minsym)) == 0)
- {
- function_found = 1;
- break;
- }
- }
-
- if (function_found)
- /* The type of msym is correct (mst_solib_trampoline), but
- the unwind info is wrong, so set it to the correct value. */
- u->stub_unwind.stub_type = EXPORT;
- else
- /* The stub type info in the unwind is correct (this is not a
- trampoline), but the msym type information is wrong, it
- should be mst_text. So we need to fix the msym, and also
- get out of this function. */
- {
- MSYMBOL_TYPE (msym.minsym) = mst_text;
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
- }
-
-/*--------------------------------------------------------------------------*/
- }
-
- /* It's a stub. Search for a branch and figure out where it goes.
- Note we have to handle multi insn branch sequences like ldil;ble.
- Most (all?) other branches can be determined by examining the contents
- of certain registers and the stack. */
-
- loc = pc;
- curr_inst = 0;
- prev_inst = 0;
- while (1)
- {
- /* Make sure we haven't walked outside the range of this stub. */
- if (u != find_unwind_entry (loc))
- {
- warning (_("Unable to find branch in linker stub"));
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
-
- prev_inst = curr_inst;
- curr_inst = read_memory_integer (loc, 4, byte_order);
-
- /* Does it look like a branch external using %r1? Then it's the
- branch from the stub to the actual function. */
- if ((curr_inst & 0xffe0e000) == 0xe0202000)
- {
- /* Yup. See if the previous instruction loaded
- a value into %r1. If so compute and return the jump address. */
- if ((prev_inst & 0xffe00000) == 0x20200000)
- return (hppa_extract_21 (prev_inst)
- + hppa_extract_17 (curr_inst)) & ~0x3;
- else
- {
- warning (_("Unable to find ldil X,%%r1 "
- "before ble Y(%%sr4,%%r1)."));
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
- }
-
- /* Does it look like a be 0(sr0,%r21)? OR
- Does it look like a be, n 0(sr0,%r21)? OR
- Does it look like a bve (r21)? (this is on PA2.0)
- Does it look like a bve, n(r21)? (this is also on PA2.0)
- That's the branch from an
- import stub to an export stub.
-
- It is impossible to determine the target of the branch via
- simple examination of instructions and/or data (consider
- that the address in the plabel may be the address of the
- bind-on-reference routine in the dynamic loader).
-
- So we have try an alternative approach.
-
- Get the name of the symbol at our current location; it should
- be a stub symbol with the same name as the symbol in the
- shared library.
-
- Then lookup a minimal symbol with the same name; we should
- get the minimal symbol for the target routine in the shared
- library as those take precedence of import/export stubs. */
- if ((curr_inst == 0xe2a00000) ||
- (curr_inst == 0xe2a00002) ||
- (curr_inst == 0xeaa0d000) ||
- (curr_inst == 0xeaa0d002))
- {
- struct bound_minimal_symbol stubsym;
- struct bound_minimal_symbol libsym;
-
- stubsym = lookup_minimal_symbol_by_pc (loc);
- if (stubsym.minsym == NULL)
- {
- warning (_("Unable to find symbol for 0x%lx"), loc);
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
-
- libsym = lookup_minimal_symbol (MSYMBOL_LINKAGE_NAME (stubsym.minsym),
- NULL, NULL);
- if (libsym.minsym == NULL)
- {
- warning (_("Unable to find library symbol for %s."),
- MSYMBOL_PRINT_NAME (stubsym.minsym));
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
-
- return MSYMBOL_VALUE (libsym.minsym);
- }
-
- /* Does it look like bl X,%rp or bl X,%r0? Another way to do a
- branch from the stub to the actual function. */
- /*elz */
- else if ((curr_inst & 0xffe0e000) == 0xe8400000
- || (curr_inst & 0xffe0e000) == 0xe8000000
- || (curr_inst & 0xffe0e000) == 0xe800A000)
- return (loc + hppa_extract_17 (curr_inst) + 8) & ~0x3;
-
- /* Does it look like bv (rp)? Note this depends on the
- current stack pointer being the same as the stack
- pointer in the stub itself! This is a branch on from the
- stub back to the original caller. */
- /*else if ((curr_inst & 0xffe0e000) == 0xe840c000) */
- else if ((curr_inst & 0xffe0f000) == 0xe840c000)
- {
- /* Yup. See if the previous instruction loaded
- rp from sp - 8. */
- if (prev_inst == 0x4bc23ff1)
- {
- CORE_ADDR sp;
- sp = get_frame_register_unsigned (frame, HPPA_SP_REGNUM);
- return read_memory_integer (sp - 8, 4, byte_order) & ~0x3;
- }
- else
- {
- warning (_("Unable to find restore of %%rp before bv (%%rp)."));
- return orig_pc == pc ? 0 : pc & ~0x3;
- }
- }
-
- /* elz: added this case to capture the new instruction
- at the end of the return part of an export stub used by
- the PA2.0: BVE, n (rp) */
- else if ((curr_inst & 0xffe0f000) == 0xe840d000)
- {
- return (read_memory_integer
- (get_frame_register_unsigned (frame, HPPA_SP_REGNUM) - 24,
- word_size, byte_order)) & ~0x3;
- }
-
- /* What about be,n 0(sr0,%rp)? It's just another way we return to
- the original caller from the stub. Used in dynamic executables. */
- else if (curr_inst == 0xe0400002)
- {
- /* The value we jump to is sitting in sp - 24. But that's
- loaded several instructions before the be instruction.
- I guess we could check for the previous instruction being
- mtsp %r1,%sr0 if we want to do sanity checking. */
- return (read_memory_integer
- (get_frame_register_unsigned (frame, HPPA_SP_REGNUM) - 24,
- word_size, byte_order)) & ~0x3;
- }
-
- /* Haven't found the branch yet, but we're still in the stub.
- Keep looking. */
- loc += 4;
- }
-}
-
-static void
-hppa_skip_permanent_breakpoint (struct regcache *regcache)
-{
- /* To step over a breakpoint instruction on the PA takes some
- fiddling with the instruction address queue.
-
- When we stop at a breakpoint, the IA queue front (the instruction
- we're executing now) points at the breakpoint instruction, and
- the IA queue back (the next instruction to execute) points to
- whatever instruction we would execute after the breakpoint, if it
- were an ordinary instruction. This is the case even if the
- breakpoint is in the delay slot of a branch instruction.
-
- Clearly, to step past the breakpoint, we need to set the queue
- front to the back. But what do we put in the back? What
- instruction comes after that one? Because of the branch delay
- slot, the next insn is always at the back + 4. */
-
- ULONGEST pcoq_tail, pcsq_tail;
- regcache_cooked_read_unsigned (regcache, HPPA_PCOQ_TAIL_REGNUM, &pcoq_tail);
- regcache_cooked_read_unsigned (regcache, HPPA_PCSQ_TAIL_REGNUM, &pcsq_tail);
-
- regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, pcoq_tail);
- regcache_cooked_write_unsigned (regcache, HPPA_PCSQ_HEAD_REGNUM, pcsq_tail);
-
- regcache_cooked_write_unsigned (regcache,
- HPPA_PCOQ_TAIL_REGNUM, pcoq_tail + 4);
- /* We can leave the tail's space the same, since there's no jump. */
-}
-
-
-/* Signal frames. */
-struct hppa_hpux_sigtramp_unwind_cache
-{
- CORE_ADDR base;
- struct trad_frame_saved_reg *saved_regs;
-};
-
-static int hppa_hpux_tramp_reg[] = {
- HPPA_SAR_REGNUM,
- HPPA_PCOQ_HEAD_REGNUM,
- HPPA_PCSQ_HEAD_REGNUM,
- HPPA_PCOQ_TAIL_REGNUM,
- HPPA_PCSQ_TAIL_REGNUM,
- HPPA_EIEM_REGNUM,
- HPPA_IIR_REGNUM,
- HPPA_ISR_REGNUM,
- HPPA_IOR_REGNUM,
- HPPA_IPSW_REGNUM,
- -1,
- HPPA_SR4_REGNUM,
- HPPA_SR4_REGNUM + 1,
- HPPA_SR4_REGNUM + 2,
- HPPA_SR4_REGNUM + 3,
- HPPA_SR4_REGNUM + 4,
- HPPA_SR4_REGNUM + 5,
- HPPA_SR4_REGNUM + 6,
- HPPA_SR4_REGNUM + 7,
- HPPA_RCR_REGNUM,
- HPPA_PID0_REGNUM,
- HPPA_PID1_REGNUM,
- HPPA_CCR_REGNUM,
- HPPA_PID2_REGNUM,
- HPPA_PID3_REGNUM,
- HPPA_TR0_REGNUM,
- HPPA_TR0_REGNUM + 1,
- HPPA_TR0_REGNUM + 2,
- HPPA_CR27_REGNUM
-};
-
-static struct hppa_hpux_sigtramp_unwind_cache *
-hppa_hpux_sigtramp_frame_unwind_cache (struct frame_info *this_frame,
- void **this_cache)
-
-{
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct hppa_hpux_sigtramp_unwind_cache *info;
- unsigned int flag;
- CORE_ADDR sp, scptr, off;
- int i, incr, szoff;
-
- if (*this_cache)
- return *this_cache;
-
- info = FRAME_OBSTACK_ZALLOC (struct hppa_hpux_sigtramp_unwind_cache);
- *this_cache = info;
- info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
-
- sp = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM);
-
- if (IS_32BIT_TARGET (gdbarch))
- scptr = sp - 1352;
- else
- scptr = sp - 1520;
-
- off = scptr;
-
- /* See /usr/include/machine/save_state.h for the structure of the
- save_state_t structure. */
-
- flag = read_memory_unsigned_integer (scptr + HPPA_HPUX_SS_FLAGS_OFFSET,
- 4, byte_order);
-
- if (!(flag & HPPA_HPUX_SS_WIDEREGS))
- {
- /* Narrow registers. */
- off = scptr + HPPA_HPUX_SS_NARROW_OFFSET;
- incr = 4;
- szoff = 0;
- }
- else
- {
- /* Wide registers. */
- off = scptr + HPPA_HPUX_SS_WIDE_OFFSET + 8;
- incr = 8;
- szoff = (tdep->bytes_per_address == 4 ? 4 : 0);
- }
-
- for (i = 1; i < 32; i++)
- {
- info->saved_regs[HPPA_R0_REGNUM + i].addr = off + szoff;
- off += incr;
- }
-
- for (i = 0; i < ARRAY_SIZE (hppa_hpux_tramp_reg); i++)
- {
- if (hppa_hpux_tramp_reg[i] > 0)
- info->saved_regs[hppa_hpux_tramp_reg[i]].addr = off + szoff;
-
- off += incr;
- }
-
- /* TODO: fp regs */
-
- info->base = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM);
-
- return info;
-}
-
-static void
-hppa_hpux_sigtramp_frame_this_id (struct frame_info *this_frame,
- void **this_prologue_cache,
- struct frame_id *this_id)
-{
- struct hppa_hpux_sigtramp_unwind_cache *info
- = hppa_hpux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache);
-
- *this_id = frame_id_build (info->base, get_frame_pc (this_frame));
-}
-
-static struct value *
-hppa_hpux_sigtramp_frame_prev_register (struct frame_info *this_frame,
- void **this_prologue_cache,
- int regnum)
-{
- struct hppa_hpux_sigtramp_unwind_cache *info
- = hppa_hpux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache);
-
- return hppa_frame_prev_register_helper (this_frame,
- info->saved_regs, regnum);
-}
-
-static int
-hppa_hpux_sigtramp_unwind_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_cache)
-{
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct unwind_table_entry *u;
- CORE_ADDR pc = get_frame_pc (this_frame);
-
- u = find_unwind_entry (pc);
-
- /* If this is an export stub, try to get the unwind descriptor for
- the actual function itself. */
- if (u && u->stub_unwind.stub_type == EXPORT)
- {
- gdb_byte buf[HPPA_INSN_SIZE];
- unsigned long insn;
-
- if (!safe_frame_unwind_memory (this_frame, u->region_start,
- buf, sizeof buf))
- return 0;
-
- insn = extract_unsigned_integer (buf, sizeof buf, byte_order);
- if ((insn & 0xffe0e000) == 0xe8400000)
- u = find_unwind_entry(u->region_start + hppa_extract_17 (insn) + 8);
- }
-
- if (u && u->HP_UX_interrupt_marker)
- return 1;
-
- return 0;
-}
-
-static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = {
- SIGTRAMP_FRAME,
- default_frame_unwind_stop_reason,
- hppa_hpux_sigtramp_frame_this_id,
- hppa_hpux_sigtramp_frame_prev_register,
- NULL,
- hppa_hpux_sigtramp_unwind_sniffer
-};
-
-static CORE_ADDR
-hppa32_hpux_find_global_pointer (struct gdbarch *gdbarch,
- struct value *function)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR faddr;
-
- faddr = value_as_address (function);
-
- /* Is this a plabel? If so, dereference it to get the gp value. */
- if (faddr & 2)
- {
- int status;
- gdb_byte buf[4];
-
- faddr &= ~3;
-
- status = target_read_memory (faddr + 4, buf, sizeof (buf));
- if (status == 0)
- return extract_unsigned_integer (buf, sizeof (buf), byte_order);
- }
-
- return gdbarch_tdep (gdbarch)->solib_get_got_by_pc (faddr);
-}
-
-static CORE_ADDR
-hppa64_hpux_find_global_pointer (struct gdbarch *gdbarch,
- struct value *function)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR faddr;
- gdb_byte buf[32];
-
- faddr = value_as_address (function);
-
- if (pc_in_section (faddr, ".opd"))
- {
- target_read_memory (faddr, buf, sizeof (buf));
- return extract_unsigned_integer (&buf[24], 8, byte_order);
- }
- else
- {
- return gdbarch_tdep (gdbarch)->solib_get_got_by_pc (faddr);
- }
-}
-
-static unsigned int ldsid_pattern[] = {
- 0x000010a0, /* ldsid (rX),rY */
- 0x00001820, /* mtsp rY,sr0 */
- 0xe0000000 /* be,n (sr0,rX) */
-};
-
-static CORE_ADDR
-hppa_hpux_search_pattern (struct gdbarch *gdbarch,
- CORE_ADDR start, CORE_ADDR end,
- unsigned int *patterns, int count)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int num_insns = (end - start + HPPA_INSN_SIZE) / HPPA_INSN_SIZE;
- unsigned int *insns;
- gdb_byte *buf;
- int offset, i;
-
- buf = alloca (num_insns * HPPA_INSN_SIZE);
- insns = alloca (num_insns * sizeof (unsigned int));
-
- read_memory (start, buf, num_insns * HPPA_INSN_SIZE);
- for (i = 0; i < num_insns; i++, buf += HPPA_INSN_SIZE)
- insns[i] = extract_unsigned_integer (buf, HPPA_INSN_SIZE, byte_order);
-
- for (offset = 0; offset <= num_insns - count; offset++)
- {
- for (i = 0; i < count; i++)
- {
- if ((insns[offset + i] & patterns[i]) != patterns[i])
- break;
- }
- if (i == count)
- break;
- }
-
- if (offset <= num_insns - count)
- return start + offset * HPPA_INSN_SIZE;
- else
- return 0;
-}
-
-static CORE_ADDR
-hppa32_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc,
- int *argreg)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct objfile *obj;
- struct obj_section *sec;
- struct hppa_objfile_private *priv;
- struct frame_info *frame;
- struct unwind_table_entry *u;
- CORE_ADDR addr, rp;
- gdb_byte buf[4];
- unsigned int insn;
-
- sec = find_pc_section (pc);
- obj = sec->objfile;
- priv = objfile_data (obj, hppa_objfile_priv_data);
-
- if (!priv)
- priv = hppa_init_objfile_priv_data (obj);
- if (!priv)
- error (_("Internal error creating objfile private data."));
-
- /* Use the cached value if we have one. */
- if (priv->dummy_call_sequence_addr != 0)
- {
- *argreg = priv->dummy_call_sequence_reg;
- return priv->dummy_call_sequence_addr;
- }
-
- /* First try a heuristic; if we are in a shared library call, our return
- pointer is likely to point at an export stub. */
- frame = get_current_frame ();
- rp = frame_unwind_register_unsigned (frame, 2);
- u = find_unwind_entry (rp);
- if (u && u->stub_unwind.stub_type == EXPORT)
- {
- addr = hppa_hpux_search_pattern (gdbarch,
- u->region_start, u->region_end,
- ldsid_pattern,
- ARRAY_SIZE (ldsid_pattern));
- if (addr)
- goto found_pattern;
- }
-
- /* Next thing to try is to look for an export stub. */
- if (priv->unwind_info)
- {
- int i;
-
- for (i = 0; i < priv->unwind_info->last; i++)
- {
- struct unwind_table_entry *u;
- u = &priv->unwind_info->table[i];
- if (u->stub_unwind.stub_type == EXPORT)
- {
- addr = hppa_hpux_search_pattern (gdbarch,
- u->region_start, u->region_end,
- ldsid_pattern,
- ARRAY_SIZE (ldsid_pattern));
- if (addr)
- {
- goto found_pattern;
- }
- }
- }
- }
-
- /* Finally, if this is the main executable, try to locate a sequence
- from noshlibs */
- addr = hppa_symbol_address ("noshlibs");
- sec = find_pc_section (addr);
-
- if (sec && sec->objfile == obj)
- {
- CORE_ADDR start, end;
-
- find_pc_partial_function (addr, NULL, &start, &end);
- if (start != 0 && end != 0)
- {
- addr = hppa_hpux_search_pattern (gdbarch, start, end, ldsid_pattern,
- ARRAY_SIZE (ldsid_pattern));
- if (addr)
- goto found_pattern;
- }
- }
-
- /* Can't find a suitable sequence. */
- return 0;
-
-found_pattern:
- target_read_memory (addr, buf, sizeof (buf));
- insn = extract_unsigned_integer (buf, sizeof (buf), byte_order);
- priv->dummy_call_sequence_addr = addr;
- priv->dummy_call_sequence_reg = (insn >> 21) & 0x1f;
-
- *argreg = priv->dummy_call_sequence_reg;
- return priv->dummy_call_sequence_addr;
-}
-
-static CORE_ADDR
-hppa64_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc,
- int *argreg)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct objfile *obj;
- struct obj_section *sec;
- struct hppa_objfile_private *priv;
- CORE_ADDR addr;
- struct minimal_symbol *msym;
-
- sec = find_pc_section (pc);
- obj = sec->objfile;
- priv = objfile_data (obj, hppa_objfile_priv_data);
-
- if (!priv)
- priv = hppa_init_objfile_priv_data (obj);
- if (!priv)
- error (_("Internal error creating objfile private data."));
-
- /* Use the cached value if we have one. */
- if (priv->dummy_call_sequence_addr != 0)
- {
- *argreg = priv->dummy_call_sequence_reg;
- return priv->dummy_call_sequence_addr;
- }
-
- /* FIXME: Without stub unwind information, locating a suitable sequence is
- fairly difficult. For now, we implement a very naive and inefficient
- scheme; try to read in blocks of code, and look for a "bve,n (rp)"
- instruction. These are likely to occur at the end of functions, so
- we only look at the last two instructions of each function. */
- ALL_OBJFILE_MSYMBOLS (obj, msym)
- {
- CORE_ADDR begin, end;
- const char *name;
- gdb_byte buf[2 * HPPA_INSN_SIZE];
- int offset;
-
- find_pc_partial_function (MSYMBOL_VALUE_ADDRESS (obj, msym), &name,
- &begin, &end);
-
- if (name == NULL || begin == 0 || end == 0)
- continue;
-
- if (target_read_memory (end - sizeof (buf), buf, sizeof (buf)) == 0)
- {
- for (offset = 0; offset < sizeof (buf); offset++)
- {
- unsigned int insn;
-
- insn = extract_unsigned_integer (buf + offset,
- HPPA_INSN_SIZE, byte_order);
- if (insn == 0xe840d002) /* bve,n (rp) */
- {
- addr = (end - sizeof (buf)) + offset;
- goto found_pattern;
- }
- }
- }
- }
-
- /* Can't find a suitable sequence. */
- return 0;
-
-found_pattern:
- priv->dummy_call_sequence_addr = addr;
- /* Right now we only look for a "bve,l (rp)" sequence, so the register is
- always HPPA_RP_REGNUM. */
- priv->dummy_call_sequence_reg = HPPA_RP_REGNUM;
-
- *argreg = priv->dummy_call_sequence_reg;
- return priv->dummy_call_sequence_addr;
-}
-
-static CORE_ADDR
-hppa_hpux_find_import_stub_for_addr (CORE_ADDR funcaddr)
-{
- struct objfile *objfile;
- struct bound_minimal_symbol funsym;
- struct bound_minimal_symbol stubsym;
- CORE_ADDR stubaddr;
-
- funsym = lookup_minimal_symbol_by_pc (funcaddr);
- stubaddr = 0;
-
- ALL_OBJFILES (objfile)
- {
- stubsym = lookup_minimal_symbol_solib_trampoline
- (MSYMBOL_LINKAGE_NAME (funsym.minsym), objfile);
-
- if (stubsym.minsym)
- {
- struct unwind_table_entry *u;
-
- u = find_unwind_entry (MSYMBOL_VALUE (stubsym.minsym));
- if (u == NULL
- || (u->stub_unwind.stub_type != IMPORT
- && u->stub_unwind.stub_type != IMPORT_SHLIB))
- continue;
-
- stubaddr = MSYMBOL_VALUE (stubsym.minsym);
-
- /* If we found an IMPORT stub, then we can stop searching;
- if we found an IMPORT_SHLIB, we want to continue the search
- in the hopes that we will find an IMPORT stub. */
- if (u->stub_unwind.stub_type == IMPORT)
- break;
- }
- }
-
- return stubaddr;
-}
-
-static int
-hppa_hpux_sr_for_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
-{
- int sr;
- /* The space register to use is encoded in the top 2 bits of the address. */
- sr = addr >> (gdbarch_tdep (gdbarch)->bytes_per_address * 8 - 2);
- return sr + 4;
-}
-
-static CORE_ADDR
-hppa_hpux_find_dummy_bpaddr (CORE_ADDR addr)
-{
- /* In order for us to restore the space register to its starting state,
- we need the dummy trampoline to return to an instruction address in
- the same space as where we started the call. We used to place the
- breakpoint near the current pc, however, this breaks nested dummy calls
- as the nested call will hit the breakpoint address and terminate
- prematurely. Instead, we try to look for an address in the same space to
- put the breakpoint.
-
- This is similar in spirit to putting the breakpoint at the "entry point"
- of an executable. */
-
- struct obj_section *sec;
- struct unwind_table_entry *u;
- struct minimal_symbol *msym;
- CORE_ADDR func;
-
- sec = find_pc_section (addr);
- if (sec)
- {
- /* First try the lowest address in the section; we can use it as long
- as it is "regular" code (i.e. not a stub). */
- u = find_unwind_entry (obj_section_addr (sec));
- if (!u || u->stub_unwind.stub_type == 0)
- return obj_section_addr (sec);
-
- /* Otherwise, we need to find a symbol for a regular function. We
- do this by walking the list of msymbols in the objfile. The symbol
- we find should not be the same as the function that was passed in. */
-
- /* FIXME: this is broken, because we can find a function that will be
- called by the dummy call target function, which will still not
- work. */
-
- find_pc_partial_function (addr, NULL, &func, NULL);
- ALL_OBJFILE_MSYMBOLS (sec->objfile, msym)
- {
- u = find_unwind_entry (MSYMBOL_VALUE_ADDRESS (sec->objfile, msym));
- if (func != MSYMBOL_VALUE_ADDRESS (sec->objfile, msym)
- && (!u || u->stub_unwind.stub_type == 0))
- return MSYMBOL_VALUE_ADDRESS (sec->objfile, msym);
- }
- }
-
- warning (_("Cannot find suitable address to place dummy breakpoint; nested "
- "calls may fail."));
- return addr - 4;
-}
-
-static CORE_ADDR
-hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
- CORE_ADDR funcaddr,
- struct value **args, int nargs,
- struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
- struct regcache *regcache)
-{
- CORE_ADDR pc, stubaddr;
- int argreg = 0;
-
- pc = regcache_read_pc (regcache);
-
- /* Note: we don't want to pass a function descriptor here; push_dummy_call
- fills in the PIC register for us. */
- funcaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funcaddr, NULL);
-
- /* The simple case is where we call a function in the same space that we are
- currently in; in that case we don't really need to do anything. */
- if (hppa_hpux_sr_for_addr (gdbarch, pc)
- == hppa_hpux_sr_for_addr (gdbarch, funcaddr))
- {
- /* Intraspace call. */
- *bp_addr = hppa_hpux_find_dummy_bpaddr (pc);
- *real_pc = funcaddr;
- regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, *bp_addr);
-
- return sp;
- }
-
- /* In order to make an interspace call, we need to go through a stub.
- gcc supplies an appropriate stub called "__gcc_plt_call", however, if
- an application is compiled with HP compilers then this stub is not
- available. We used to fallback to "__d_plt_call", however that stub
- is not entirely useful for us because it doesn't do an interspace
- return back to the caller. Also, on hppa64-hpux, there is no
- __gcc_plt_call available. In order to keep the code uniform, we
- instead don't use either of these stubs, but instead write our own
- onto the stack.
-
- A problem arises since the stack is located in a different space than
- code, so in order to branch to a stack stub, we will need to do an
- interspace branch. Previous versions of gdb did this by modifying code
- at the current pc and doing single-stepping to set the pcsq. Since this
- is highly undesirable, we use a different scheme:
-
- All we really need to do the branch to the stub is a short instruction
- sequence like this:
-
- PA1.1:
- ldsid (rX),r1
- mtsp r1,sr0
- be,n (sr0,rX)
-
- PA2.0:
- bve,n (sr0,rX)
-
- Instead of writing these sequences ourselves, we can find it in
- the instruction stream that belongs to the current space. While this
- seems difficult at first, we are actually guaranteed to find the sequences
- in several places:
-
- For 32-bit code:
- - in export stubs for shared libraries
- - in the "noshlibs" routine in the main module
-
- For 64-bit code:
- - at the end of each "regular" function
-
- We cache the address of these sequences in the objfile's private data
- since these operations can potentially be quite expensive.
-
- So, what we do is:
- - write a stack trampoline
- - look for a suitable instruction sequence in the current space
- - point the sequence at the trampoline
- - set the return address of the trampoline to the current space
- (see hppa_hpux_find_dummy_call_bpaddr)
- - set the continuing address of the "dummy code" as the sequence. */
-
- if (IS_32BIT_TARGET (gdbarch))
- {
-#define INSN(I1, I2, I3, I4) 0x ## I1, 0x ## I2, 0x ## I3, 0x ## I4
- static const gdb_byte hppa32_tramp[] = {
- INSN(0f,df,12,91), /* stw r31,-8(,sp) */
- INSN(02,c0,10,a1), /* ldsid (,r22),r1 */
- INSN(00,01,18,20), /* mtsp r1,sr0 */
- INSN(e6,c0,00,00), /* be,l 0(sr0,r22),%sr0,%r31 */
- INSN(08,1f,02,42), /* copy r31,rp */
- INSN(0f,d1,10,82), /* ldw -8(,sp),rp */
- INSN(00,40,10,a1), /* ldsid (,rp),r1 */
- INSN(00,01,18,20), /* mtsp r1,sr0 */
- INSN(e0,40,00,00), /* be 0(sr0,rp) */
- INSN(08,00,02,40) /* nop */
- };
-
- /* for hppa32, we must call the function through a stub so that on
- return it can return to the space of our trampoline. */
- stubaddr = hppa_hpux_find_import_stub_for_addr (funcaddr);
- if (stubaddr == 0)
- error (_("Cannot call external function not referenced by application "
- "(no import stub).\n"));
- regcache_cooked_write_unsigned (regcache, 22, stubaddr);
-
- write_memory (sp, hppa32_tramp, sizeof (hppa32_tramp));
-
- *bp_addr = hppa_hpux_find_dummy_bpaddr (pc);
- regcache_cooked_write_unsigned (regcache, 31, *bp_addr);
-
- *real_pc = hppa32_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg);
- if (*real_pc == 0)
- error (_("Cannot make interspace call from here."));
-
- regcache_cooked_write_unsigned (regcache, argreg, sp);
-
- sp += sizeof (hppa32_tramp);
- }
- else
- {
- static const gdb_byte hppa64_tramp[] = {
- INSN(ea,c0,f0,00), /* bve,l (r22),%r2 */
- INSN(0f,df,12,d1), /* std r31,-8(,sp) */
- INSN(0f,d1,10,c2), /* ldd -8(,sp),rp */
- INSN(e8,40,d0,02), /* bve,n (rp) */
- INSN(08,00,02,40) /* nop */
- };
-#undef INSN
-
- /* for hppa64, we don't need to call through a stub; all functions
- return via a bve. */
- regcache_cooked_write_unsigned (regcache, 22, funcaddr);
- write_memory (sp, hppa64_tramp, sizeof (hppa64_tramp));
-
- *bp_addr = pc - 4;
- regcache_cooked_write_unsigned (regcache, 31, *bp_addr);
-
- *real_pc = hppa64_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg);
- if (*real_pc == 0)
- error (_("Cannot make interspace call from here."));
-
- regcache_cooked_write_unsigned (regcache, argreg, sp);
-
- sp += sizeof (hppa64_tramp);
- }
-
- sp = gdbarch_frame_align (gdbarch, sp);
-
- return sp;
-}
-
-\f
-
-static void
-hppa_hpux_supply_ss_narrow (struct regcache *regcache,
- int regnum, const gdb_byte *save_state)
-{
- const gdb_byte *ss_narrow = save_state + HPPA_HPUX_SS_NARROW_OFFSET;
- int i, offset = 0;
-
- for (i = HPPA_R1_REGNUM; i < HPPA_FP0_REGNUM; i++)
- {
- if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, ss_narrow + offset);
-
- offset += 4;
- }
-}
-
-static void
-hppa_hpux_supply_ss_fpblock (struct regcache *regcache,
- int regnum, const gdb_byte *save_state)
-{
- const gdb_byte *ss_fpblock = save_state + HPPA_HPUX_SS_FPBLOCK_OFFSET;
- int i, offset = 0;
-
- /* FIXME: We view the floating-point state as 64 single-precision
- registers for 32-bit code, and 32 double-precision register for
- 64-bit code. This distinction is artificial and should be
- eliminated. If that ever happens, we should remove the if-clause
- below. */
-
- if (register_size (get_regcache_arch (regcache), HPPA_FP0_REGNUM) == 4)
- {
- for (i = HPPA_FP0_REGNUM; i < HPPA_FP0_REGNUM + 64; i++)
- {
- if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, ss_fpblock + offset);
-
- offset += 4;
- }
- }
- else
- {
- for (i = HPPA_FP0_REGNUM; i < HPPA_FP0_REGNUM + 32; i++)
- {
- if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, ss_fpblock + offset);
-
- offset += 8;
- }
- }
-}
-
-static void
-hppa_hpux_supply_ss_wide (struct regcache *regcache,
- int regnum, const gdb_byte *save_state)
-{
- const gdb_byte *ss_wide = save_state + HPPA_HPUX_SS_WIDE_OFFSET;
- int i, offset = 8;
-
- if (register_size (get_regcache_arch (regcache), HPPA_R1_REGNUM) == 4)
- offset += 4;
-
- for (i = HPPA_R1_REGNUM; i < HPPA_FP0_REGNUM; i++)
- {
- if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, ss_wide + offset);
-
- offset += 8;
- }
-}
-
-static void
-hppa_hpux_supply_save_state (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *regs, size_t len)
-{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- const gdb_byte *proc_info = regs;
- const gdb_byte *save_state = proc_info + 8;
- ULONGEST flags;
-
- flags = extract_unsigned_integer (save_state + HPPA_HPUX_SS_FLAGS_OFFSET,
- 4, byte_order);
- if (regnum == -1 || regnum == HPPA_FLAGS_REGNUM)
- {
- size_t size = register_size (gdbarch, HPPA_FLAGS_REGNUM);
- gdb_byte buf[8];
-
- store_unsigned_integer (buf, size, byte_order, flags);
- regcache_raw_supply (regcache, HPPA_FLAGS_REGNUM, buf);
- }
-
- /* If the SS_WIDEREGS flag is set, we really do need the full
- `struct save_state'. */
- if (flags & HPPA_HPUX_SS_WIDEREGS && len < HPPA_HPUX_SAVE_STATE_SIZE)
- error (_("Register set contents too small"));
-
- if (flags & HPPA_HPUX_SS_WIDEREGS)
- hppa_hpux_supply_ss_wide (regcache, regnum, save_state);
- else
- hppa_hpux_supply_ss_narrow (regcache, regnum, save_state);
-
- hppa_hpux_supply_ss_fpblock (regcache, regnum, save_state);
-}
-
-/* HP-UX register set. */
-
-static const struct regset hppa_hpux_regset =
-{
- NULL,
- hppa_hpux_supply_save_state,
- NULL,
- REGSET_VARIABLE_SIZE
-};
-
-static void
-hppa_hpux_iterate_over_regset_sections (struct gdbarch *gdbarch,
- iterate_over_regset_sections_cb *cb,
- void *cb_data,
- const struct regcache *regcache)
-{
- cb (".reg", HPPA_HPUX_PA89_SAVE_STATE_SIZE + 8, &hppa_hpux_regset,
- NULL, cb_data);
-}
-\f
-
-/* Bit in the `ss_flag' member of `struct save_state' that indicates
- the state was saved from a system call. From
- <machine/save_state.h>. */
-#define HPPA_HPUX_SS_INSYSCALL 0x02
-
-static CORE_ADDR
-hppa_hpux_read_pc (struct regcache *regcache)
-{
- ULONGEST flags;
-
- /* If we're currently in a system call return the contents of %r31. */
- regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags);
- if (flags & HPPA_HPUX_SS_INSYSCALL)
- {
- ULONGEST pc;
- regcache_cooked_read_unsigned (regcache, HPPA_R31_REGNUM, &pc);
- return pc & ~0x3;
- }
-
- return hppa_read_pc (regcache);
-}
-
-static void
-hppa_hpux_write_pc (struct regcache *regcache, CORE_ADDR pc)
-{
- ULONGEST flags;
-
- /* If we're currently in a system call also write PC into %r31. */
- regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags);
- if (flags & HPPA_HPUX_SS_INSYSCALL)
- regcache_cooked_write_unsigned (regcache, HPPA_R31_REGNUM, pc | 0x3);
-
- hppa_write_pc (regcache, pc);
-}
-
-static CORE_ADDR
-hppa_hpux_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- ULONGEST flags;
-
- /* If we're currently in a system call return the contents of %r31. */
- flags = frame_unwind_register_unsigned (next_frame, HPPA_FLAGS_REGNUM);
- if (flags & HPPA_HPUX_SS_INSYSCALL)
- return frame_unwind_register_unsigned (next_frame, HPPA_R31_REGNUM) & ~0x3;
-
- return hppa_unwind_pc (gdbarch, next_frame);
-}
-\f
-
-/* Given the current value of the pc, check to see if it is inside a stub, and
- if so, change the value of the pc to point to the caller of the stub.
- THIS_FRAME is the current frame in the current list of frames.
- BASE contains to stack frame base of the current frame.
- SAVE_REGS is the register file stored in the frame cache. */
-static void
-hppa_hpux_unwind_adjust_stub (struct frame_info *this_frame, CORE_ADDR base,
- struct trad_frame_saved_reg *saved_regs)
-{
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int word_size = gdbarch_ptr_bit (gdbarch) / 8;
- struct value *pcoq_head_val;
- ULONGEST pcoq_head;
- CORE_ADDR stubpc;
- struct unwind_table_entry *u;
-
- pcoq_head_val = trad_frame_get_prev_register (this_frame, saved_regs,
- HPPA_PCOQ_HEAD_REGNUM);
- pcoq_head =
- extract_unsigned_integer (value_contents_all (pcoq_head_val),
- register_size (gdbarch, HPPA_PCOQ_HEAD_REGNUM),
- byte_order);
-
- u = find_unwind_entry (pcoq_head);
- if (u && u->stub_unwind.stub_type == EXPORT)
- {
- stubpc = read_memory_integer (base - 24, word_size, byte_order);
- trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc);
- }
- else if (hppa_symbol_address ("__gcc_plt_call")
- == get_pc_function_start (pcoq_head))
- {
- stubpc = read_memory_integer (base - 8, word_size, byte_order);
- trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc);
- }
-}
-
-static void
-hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- if (IS_32BIT_TARGET (gdbarch))
- tdep->in_solib_call_trampoline = hppa32_hpux_in_solib_call_trampoline;
- else
- tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline;
-
- tdep->unwind_adjust_stub = hppa_hpux_unwind_adjust_stub;
-
- set_gdbarch_in_solib_return_trampoline
- (gdbarch, hppa_hpux_in_solib_return_trampoline);
- set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code);
-
- set_gdbarch_push_dummy_code (gdbarch, hppa_hpux_push_dummy_code);
- set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
-
- set_gdbarch_read_pc (gdbarch, hppa_hpux_read_pc);
- set_gdbarch_write_pc (gdbarch, hppa_hpux_write_pc);
- set_gdbarch_unwind_pc (gdbarch, hppa_hpux_unwind_pc);
- set_gdbarch_skip_permanent_breakpoint
- (gdbarch, hppa_skip_permanent_breakpoint);
-
- set_gdbarch_iterate_over_regset_sections
- (gdbarch, hppa_hpux_iterate_over_regset_sections);
-
- frame_unwind_append_unwinder (gdbarch, &hppa_hpux_sigtramp_frame_unwind);
-}
-
-static void
-hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- tdep->is_elf = 0;
-
- tdep->find_global_pointer = hppa32_hpux_find_global_pointer;
-
- hppa_hpux_init_abi (info, gdbarch);
- som_solib_select (gdbarch);
-}
-
-static void
-hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- tdep->is_elf = 1;
- tdep->find_global_pointer = hppa64_hpux_find_global_pointer;
-
- hppa_hpux_init_abi (info, gdbarch);
- pa64_solib_select (gdbarch);
-}
-
-static enum gdb_osabi
-hppa_hpux_core_osabi_sniffer (bfd *abfd)
-{
- if (strcmp (bfd_get_target (abfd), "hpux-core") == 0)
- return GDB_OSABI_HPUX_SOM;
- else if (strcmp (bfd_get_target (abfd), "elf64-hppa") == 0)
- {
- asection *section;
-
- section = bfd_get_section_by_name (abfd, ".kernel");
- if (section)
- {
- bfd_size_type size;
- char *contents;
-
- size = bfd_section_size (abfd, section);
- contents = alloca (size);
- if (bfd_get_section_contents (abfd, section, contents,
- (file_ptr) 0, size)
- && strcmp (contents, "HP-UX") == 0)
- return GDB_OSABI_HPUX_ELF;
- }
- }
-
- return GDB_OSABI_UNKNOWN;
-}
-
-void
-_initialize_hppa_hpux_tdep (void)
-{
- /* BFD doesn't set a flavour for HP-UX style core files. It doesn't
- set the architecture either. */
- gdbarch_register_osabi_sniffer (bfd_arch_unknown,
- bfd_target_unknown_flavour,
- hppa_hpux_core_osabi_sniffer);
- gdbarch_register_osabi_sniffer (bfd_arch_hppa,
- bfd_target_elf_flavour,
- hppa_hpux_core_osabi_sniffer);
-
- gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_HPUX_SOM,
- hppa_hpux_som_init_abi);
- gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w, GDB_OSABI_HPUX_ELF,
- hppa_hpux_elf_init_abi);
-}
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
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;
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);
}
\f
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);
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);
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* Low-level child interface to ttrace.
-
- Copyright (C) 2004-2015 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "defs.h"
-
-/* The ttrace(2) system call didn't exist before HP-UX 10.30. Don't
- try to compile this code unless we have it. */
-#ifdef HAVE_TTRACE
-
-#include "command.h"
-#include "gdbcore.h"
-#include "gdbthread.h"
-#include "inferior.h"
-#include "terminal.h"
-#include "target.h"
-#include <sys/mman.h>
-#include <sys/ttrace.h>
-#include <signal.h>
-
-#include "inf-child.h"
-#include "inf-ttrace.h"
-#include "common/filestuff.h"
-
-\f
-
-/* HP-UX uses a threading model where each user-space thread
- corresponds to a kernel thread. These kernel threads are called
- lwps. The ttrace(2) interface gives us almost full control over
- the threads, which makes it very easy to support them in GDB. We
- identify the threads by process ID and lwp ID. The ttrace(2) also
- provides us with a thread's user ID (in the `tts_user_tid' member
- of `ttstate_t') but we don't use that (yet) as it isn't necessary
- to uniquely label the thread. */
-
-/* Number of active lwps. */
-static int inf_ttrace_num_lwps;
-\f
-
-/* On HP-UX versions that have the ttrace(2) system call, we can
- implement "hardware" watchpoints by fiddling with the protection of
- pages in the address space that contain the variable being watched.
- In order to implement this, we keep a dictionary of pages for which
- we have changed the protection. */
-
-struct inf_ttrace_page
-{
- CORE_ADDR addr; /* Page address. */
- int prot; /* Protection. */
- int refcount; /* Reference count. */
- struct inf_ttrace_page *next;
- struct inf_ttrace_page *prev;
-};
-
-struct inf_ttrace_page_dict
-{
- struct inf_ttrace_page buckets[128];
- int pagesize; /* Page size. */
- int count; /* Number of pages in this dictionary. */
-} inf_ttrace_page_dict;
-
-struct inf_ttrace_private_thread_info
-{
- int dying;
-};
-
-/* Number of lwps that are currently in a system call. */
-static int inf_ttrace_num_lwps_in_syscall;
-
-/* Flag to indicate whether we should re-enable page protections after
- the next wait. */
-static int inf_ttrace_reenable_page_protections;
-
-/* Enable system call events for process PID. */
-
-static void
-inf_ttrace_enable_syscall_events (pid_t pid)
-{
- ttevent_t tte;
- ttstate_t tts;
-
- gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
-
- if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
-
- if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
- (uintptr_t)&tts, sizeof tts, 0) == -1)
- perror_with_name (("ttrace"));
-
- if (tts.tts_flags & TTS_INSYSCALL)
- inf_ttrace_num_lwps_in_syscall++;
-
- /* FIXME: Handle multiple threads. */
-}
-
-/* Disable system call events for process PID. */
-
-static void
-inf_ttrace_disable_syscall_events (pid_t pid)
-{
- ttevent_t tte;
-
- gdb_assert (inf_ttrace_page_dict.count == 0);
-
- if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
-
- if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- inf_ttrace_num_lwps_in_syscall = 0;
-}
-
-/* Get information about the page at address ADDR for process PID from
- the dictionary. */
-
-static struct inf_ttrace_page *
-inf_ttrace_get_page (pid_t pid, CORE_ADDR addr)
-{
- const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
- const int pagesize = inf_ttrace_page_dict.pagesize;
- int bucket;
- struct inf_ttrace_page *page;
-
- bucket = (addr / pagesize) % num_buckets;
- page = &inf_ttrace_page_dict.buckets[bucket];
- while (page)
- {
- if (page->addr == addr)
- break;
-
- page = page->next;
- }
-
- return page;
-}
-
-/* Add the page at address ADDR for process PID to the dictionary. */
-
-static struct inf_ttrace_page *
-inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
-{
- const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
- const int pagesize = inf_ttrace_page_dict.pagesize;
- int bucket;
- struct inf_ttrace_page *page;
- struct inf_ttrace_page *prev = NULL;
-
- bucket = (addr / pagesize) % num_buckets;
- page = &inf_ttrace_page_dict.buckets[bucket];
- while (page)
- {
- if (page->addr == addr)
- break;
-
- prev = page;
- page = page->next;
- }
-
- if (!page)
- {
- int prot;
-
- if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
- addr, 0, (uintptr_t)&prot) == -1)
- perror_with_name (("ttrace"));
-
- page = XNEW (struct inf_ttrace_page);
- page->addr = addr;
- page->prot = prot;
- page->refcount = 0;
- page->next = NULL;
-
- page->prev = prev;
- prev->next = page;
-
- inf_ttrace_page_dict.count++;
- if (inf_ttrace_page_dict.count == 1)
- inf_ttrace_enable_syscall_events (pid);
-
- if (inf_ttrace_num_lwps_in_syscall == 0)
- {
- if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
- addr, pagesize, prot & ~PROT_WRITE) == -1)
- perror_with_name (("ttrace"));
- }
- }
-
- return page;
-}
-
-/* Insert the page at address ADDR of process PID to the dictionary. */
-
-static void
-inf_ttrace_insert_page (pid_t pid, CORE_ADDR addr)
-{
- struct inf_ttrace_page *page;
-
- page = inf_ttrace_get_page (pid, addr);
- if (!page)
- page = inf_ttrace_add_page (pid, addr);
-
- page->refcount++;
-}
-
-/* Remove the page at address ADDR of process PID from the dictionary. */
-
-static void
-inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
-{
- const int pagesize = inf_ttrace_page_dict.pagesize;
- struct inf_ttrace_page *page;
-
- page = inf_ttrace_get_page (pid, addr);
- page->refcount--;
-
- gdb_assert (page->refcount >= 0);
-
- if (page->refcount == 0)
- {
- if (inf_ttrace_num_lwps_in_syscall == 0)
- {
- if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
- addr, pagesize, page->prot) == -1)
- perror_with_name (("ttrace"));
- }
-
- inf_ttrace_page_dict.count--;
- if (inf_ttrace_page_dict.count == 0)
- inf_ttrace_disable_syscall_events (pid);
-
- page->prev->next = page->next;
- if (page->next)
- page->next->prev = page->prev;
-
- xfree (page);
- }
-}
-
-/* Mask the bits in PROT from the page protections that are currently
- in the dictionary for process PID. */
-
-static void
-inf_ttrace_mask_page_protections (pid_t pid, int prot)
-{
- const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
- const int pagesize = inf_ttrace_page_dict.pagesize;
- int bucket;
-
- for (bucket = 0; bucket < num_buckets; bucket++)
- {
- struct inf_ttrace_page *page;
-
- page = inf_ttrace_page_dict.buckets[bucket].next;
- while (page)
- {
- if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
- page->addr, pagesize, page->prot & ~prot) == -1)
- perror_with_name (("ttrace"));
-
- page = page->next;
- }
- }
-}
-
-/* Write-protect the pages in the dictionary for process PID. */
-
-static void
-inf_ttrace_enable_page_protections (pid_t pid)
-{
- inf_ttrace_mask_page_protections (pid, PROT_WRITE);
-}
-
-/* Restore the protection of the pages in the dictionary for process
- PID. */
-
-static void
-inf_ttrace_disable_page_protections (pid_t pid)
-{
- inf_ttrace_mask_page_protections (pid, 0);
-}
-
-/* Insert a "hardware" watchpoint for LEN bytes at address ADDR of
- type TYPE. */
-
-static int
-inf_ttrace_insert_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
- struct expression *cond)
-{
- const int pagesize = inf_ttrace_page_dict.pagesize;
- pid_t pid = ptid_get_pid (inferior_ptid);
- CORE_ADDR page_addr;
- int num_pages;
- int page;
-
- gdb_assert (type == hw_write);
-
- page_addr = (addr / pagesize) * pagesize;
- num_pages = (len + pagesize - 1) / pagesize;
-
- for (page = 0; page < num_pages; page++, page_addr += pagesize)
- inf_ttrace_insert_page (pid, page_addr);
-
- return 1;
-}
-
-/* Remove a "hardware" watchpoint for LEN bytes at address ADDR of
- type TYPE. */
-
-static int
-inf_ttrace_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int type,
- struct expression *cond)
-{
- const int pagesize = inf_ttrace_page_dict.pagesize;
- pid_t pid = ptid_get_pid (inferior_ptid);
- CORE_ADDR page_addr;
- int num_pages;
- int page;
-
- gdb_assert (type == hw_write);
-
- page_addr = (addr / pagesize) * pagesize;
- num_pages = (len + pagesize - 1) / pagesize;
-
- for (page = 0; page < num_pages; page++, page_addr += pagesize)
- inf_ttrace_remove_page (pid, page_addr);
-
- return 1;
-}
-
-static int
-inf_ttrace_can_use_hw_breakpoint (struct target_ops *self,
- int type, int len, int ot)
-{
- return (type == bp_hardware_watchpoint);
-}
-
-static int
-inf_ttrace_region_ok_for_hw_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len)
-{
- return 1;
-}
-
-/* Return non-zero if the current inferior was (potentially) stopped
- by hitting a "hardware" watchpoint. */
-
-static int
-inf_ttrace_stopped_by_watchpoint (struct target_ops *ops)
-{
- pid_t pid = ptid_get_pid (inferior_ptid);
- lwpid_t lwpid = ptid_get_lwp (inferior_ptid);
- ttstate_t tts;
-
- if (inf_ttrace_page_dict.count > 0)
- {
- if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
- (uintptr_t)&tts, sizeof tts, 0) == -1)
- perror_with_name (("ttrace"));
-
- if (tts.tts_event == TTEVT_SIGNAL
- && tts.tts_u.tts_signal.tts_signo == SIGBUS)
- {
- const int pagesize = inf_ttrace_page_dict.pagesize;
- void *addr = tts.tts_u.tts_signal.tts_siginfo.si_addr;
- CORE_ADDR page_addr = ((uintptr_t)addr / pagesize) * pagesize;
-
- if (inf_ttrace_get_page (pid, page_addr))
- return 1;
- }
- }
-
- return 0;
-}
-\f
-
-/* Target hook for follow_fork. On entry and at return inferior_ptid
- is the ptid of the followed inferior. */
-
-static int
-inf_ttrace_follow_fork (struct target_ops *ops, int follow_child,
- int detach_fork)
-{
- struct thread_info *tp = inferior_thread ();
-
- gdb_assert (tp->pending_follow.kind == TARGET_WAITKIND_FORKED
- || tp->pending_follow.kind == TARGET_WAITKIND_VFORKED);
-
- if (follow_child)
- {
- struct thread_info *ti;
-
- /* The child will start out single-threaded. */
- inf_ttrace_num_lwps = 1;
- inf_ttrace_num_lwps_in_syscall = 0;
-
- ti = inferior_thread ();
- ti->priv =
- xmalloc (sizeof (struct inf_ttrace_private_thread_info));
- memset (ti->priv, 0,
- sizeof (struct inf_ttrace_private_thread_info));
- }
- else
- {
- pid_t child_pid;
-
- /* Following parent. Detach child now. */
- child_pid = ptid_get_pid (tp->pending_follow.value.related_pid);
- if (ttrace (TT_PROC_DETACH, child_pid, 0, 0, 0, 0) == -1)
- perror_with_name (("ttrace"));
- }
-
- return 0;
-}
-\f
-
-/* File descriptors for pipes used as semaphores during initial
- startup of an inferior. */
-static int inf_ttrace_pfd1[2];
-static int inf_ttrace_pfd2[2];
-
-static void
-do_cleanup_pfds (void *dummy)
-{
- close (inf_ttrace_pfd1[0]);
- close (inf_ttrace_pfd1[1]);
- close (inf_ttrace_pfd2[0]);
- close (inf_ttrace_pfd2[1]);
-
- unmark_fd_no_cloexec (inf_ttrace_pfd1[0]);
- unmark_fd_no_cloexec (inf_ttrace_pfd1[1]);
- unmark_fd_no_cloexec (inf_ttrace_pfd2[0]);
- unmark_fd_no_cloexec (inf_ttrace_pfd2[1]);
-}
-
-static void
-inf_ttrace_prepare (void)
-{
- if (pipe (inf_ttrace_pfd1) == -1)
- perror_with_name (("pipe"));
-
- if (pipe (inf_ttrace_pfd2) == -1)
- {
- close (inf_ttrace_pfd1[0]);
- close (inf_ttrace_pfd2[0]);
- perror_with_name (("pipe"));
- }
-
- mark_fd_no_cloexec (inf_ttrace_pfd1[0]);
- mark_fd_no_cloexec (inf_ttrace_pfd1[1]);
- mark_fd_no_cloexec (inf_ttrace_pfd2[0]);
- mark_fd_no_cloexec (inf_ttrace_pfd2[1]);
-}
-
-/* Prepare to be traced. */
-
-static void
-inf_ttrace_me (void)
-{
- struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
- char c;
-
- /* "Trace me, Dr. Memory!" */
- if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
- perror_with_name (("ttrace"));
-
- /* Tell our parent that we are ready to be traced. */
- if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
- perror_with_name (("write"));
-
- /* Wait until our parent has set the initial event mask. */
- if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
- perror_with_name (("read"));
-
- do_cleanups (old_chain);
-}
-
-/* Start tracing PID. */
-
-static void
-inf_ttrace_him (struct target_ops *ops, int pid)
-{
- struct cleanup *old_chain = make_cleanup (do_cleanup_pfds, 0);
- ttevent_t tte;
- char c;
-
- /* Wait until our child is ready to be traced. */
- if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
- perror_with_name (("read"));
-
- /* Set the initial event mask. */
- memset (&tte, 0, sizeof (tte));
- tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
- tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
-#ifdef TTEVT_BPT_SSTEP
- tte.tte_events |= TTEVT_BPT_SSTEP;
-#endif
- tte.tte_opts |= TTEO_PROC_INHERIT;
- if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- /* Tell our child that we have set the initial event mask. */
- if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
- perror_with_name (("write"));
-
- do_cleanups (old_chain);
-
- if (!target_is_pushed (ops))
- push_target (ops);
-
- startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
-
- /* On some targets, there must be some explicit actions taken after
- the inferior has been started up. */
- target_post_startup_inferior (pid_to_ptid (pid));
-}
-
-static void
-inf_ttrace_create_inferior (struct target_ops *ops, char *exec_file,
- char *allargs, char **env, int from_tty)
-{
- int pid;
-
- gdb_assert (inf_ttrace_num_lwps == 0);
- gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
- gdb_assert (inf_ttrace_page_dict.count == 0);
- gdb_assert (inf_ttrace_reenable_page_protections == 0);
-
- pid = fork_inferior (exec_file, allargs, env, inf_ttrace_me, NULL,
- inf_ttrace_prepare, NULL, NULL);
-
- inf_ttrace_him (ops, pid);
-}
-
-static void
-inf_ttrace_mourn_inferior (struct target_ops *ops)
-{
- const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
- int bucket;
-
- inf_ttrace_num_lwps = 0;
- inf_ttrace_num_lwps_in_syscall = 0;
-
- for (bucket = 0; bucket < num_buckets; bucket++)
- {
- struct inf_ttrace_page *page;
- struct inf_ttrace_page *next;
-
- page = inf_ttrace_page_dict.buckets[bucket].next;
- while (page)
- {
- next = page->next;
- xfree (page);
- page = next;
- }
- }
- inf_ttrace_page_dict.count = 0;
-
- inf_child_mourn_inferior (ops);
-}
-
-/* Assuming we just attached the debugger to a new inferior, create
- a new thread_info structure for each thread, and add it to our
- list of threads. */
-
-static void
-inf_ttrace_create_threads_after_attach (int pid)
-{
- int status;
- ptid_t ptid;
- ttstate_t tts;
- struct thread_info *ti;
-
- status = ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
- (uintptr_t) &tts, sizeof (ttstate_t), 0);
- if (status < 0)
- perror_with_name (_("TT_PROC_GET_FIRST_LWP_STATE ttrace call failed"));
- gdb_assert (tts.tts_pid == pid);
-
- /* Add the stopped thread. */
- ptid = ptid_build (pid, tts.tts_lwpid, 0);
- ti = add_thread (ptid);
- ti->priv = xzalloc (sizeof (struct inf_ttrace_private_thread_info));
- inf_ttrace_num_lwps++;
-
- /* We use the "first stopped thread" as the currently active thread. */
- inferior_ptid = ptid;
-
- /* Iterative over all the remaining threads. */
-
- for (;;)
- {
- ptid_t ptid;
-
- status = ttrace (TT_PROC_GET_NEXT_LWP_STATE, pid, 0,
- (uintptr_t) &tts, sizeof (ttstate_t), 0);
- if (status < 0)
- perror_with_name (_("TT_PROC_GET_NEXT_LWP_STATE ttrace call failed"));
- if (status == 0)
- break; /* End of list. */
-
- ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
- ti = add_thread (ptid);
- ti->priv = xzalloc (sizeof (struct inf_ttrace_private_thread_info));
- inf_ttrace_num_lwps++;
- }
-}
-
-static void
-inf_ttrace_attach (struct target_ops *ops, const char *args, int from_tty)
-{
- char *exec_file;
- pid_t pid;
- ttevent_t tte;
- struct inferior *inf;
-
- pid = parse_pid_to_attach (args);
-
- if (pid == getpid ()) /* Trying to masturbate? */
- error (_("I refuse to debug myself!"));
-
- if (from_tty)
- {
- exec_file = get_exec_file (0);
-
- if (exec_file)
- printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
- target_pid_to_str (pid_to_ptid (pid)));
- else
- printf_unfiltered (_("Attaching to %s\n"),
- target_pid_to_str (pid_to_ptid (pid)));
-
- gdb_flush (gdb_stdout);
- }
-
- gdb_assert (inf_ttrace_num_lwps == 0);
- gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
-
- if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
- perror_with_name (("ttrace"));
-
- inf = current_inferior ();
- inferior_appeared (inf, pid);
- inf->attach_flag = 1;
-
- /* Set the initial event mask. */
- memset (&tte, 0, sizeof (tte));
- tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT | TTEVT_FORK | TTEVT_VFORK;
- tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
-#ifdef TTEVT_BPT_SSTEP
- tte.tte_events |= TTEVT_BPT_SSTEP;
-#endif
- tte.tte_opts |= TTEO_PROC_INHERIT;
- if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
- (uintptr_t)&tte, sizeof tte, 0) == -1)
- perror_with_name (("ttrace"));
-
- if (!target_is_pushed (ops))
- push_target (ops);
-
- inf_ttrace_create_threads_after_attach (pid);
-}
-
-static void
-inf_ttrace_detach (struct target_ops *ops, const char *args, int from_tty)
-{
- pid_t pid = ptid_get_pid (inferior_ptid);
- int sig = 0;
-
- if (from_tty)
- {
- char *exec_file = get_exec_file (0);
- if (exec_file == 0)
- exec_file = "";
- printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
- target_pid_to_str (pid_to_ptid (pid)));
- gdb_flush (gdb_stdout);
- }
- if (args)
- sig = atoi (args);
-
- /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
- can pass a signal number here. Does this really work? */
- if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
- perror_with_name (("ttrace"));
-
- inf_ttrace_num_lwps = 0;
- inf_ttrace_num_lwps_in_syscall = 0;
-
- inferior_ptid = null_ptid;
- detach_inferior (pid);
-
- inf_child_maybe_unpush_target (ops);
-}
-
-static void
-inf_ttrace_kill (struct target_ops *ops)
-{
- pid_t pid = ptid_get_pid (inferior_ptid);
-
- if (pid == 0)
- return;
-
- if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
- perror_with_name (("ttrace"));
- /* ??? Is it necessary to call ttrace_wait() here? */
-
- target_mourn_inferior ();
-}
-
-/* Check is a dying thread is dead by now, and delete it from GDBs
- thread list if so. */
-static int
-inf_ttrace_delete_dead_threads_callback (struct thread_info *info, void *arg)
-{
- lwpid_t lwpid;
- struct inf_ttrace_private_thread_info *p;
-
- if (is_exited (info->ptid))
- return 0;
-
- lwpid = ptid_get_lwp (info->ptid);
- p = (struct inf_ttrace_private_thread_info *) info->priv;
-
- /* Check if an lwp that was dying is still there or not. */
- if (p->dying && (kill (lwpid, 0) == -1))
- /* It's gone now. */
- delete_thread (info->ptid);
-
- return 0;
-}
-
-/* Resume the lwp pointed to by INFO, with REQUEST, and pass it signal
- SIG. */
-
-static void
-inf_ttrace_resume_lwp (struct thread_info *info, ttreq_t request, int sig)
-{
- pid_t pid = ptid_get_pid (info->ptid);
- lwpid_t lwpid = ptid_get_lwp (info->ptid);
-
- if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
- {
- struct inf_ttrace_private_thread_info *p
- = (struct inf_ttrace_private_thread_info *) info->priv;
- if (p->dying && errno == EPROTO)
- /* This is expected, it means the dying lwp is really gone
- by now. If ttrace had an event to inform the debugger
- the lwp is really gone, this wouldn't be needed. */
- delete_thread (info->ptid);
- else
- /* This was really unexpected. */
- perror_with_name (("ttrace"));
- }
-}
-
-/* Callback for iterate_over_threads. */
-
-static int
-inf_ttrace_resume_callback (struct thread_info *info, void *arg)
-{
- if (!ptid_equal (info->ptid, inferior_ptid) && !is_exited (info->ptid))
- inf_ttrace_resume_lwp (info, TT_LWP_CONTINUE, 0);
-
- return 0;
-}
-
-static void
-inf_ttrace_resume (struct target_ops *ops,
- ptid_t ptid, int step, enum gdb_signal signal)
-{
- int resume_all;
- ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE;
- int sig = gdb_signal_to_host (signal);
- struct thread_info *info;
-
- /* A specific PTID means `step only this process id'. */
- resume_all = (ptid_equal (ptid, minus_one_ptid));
-
- /* If resuming all threads, it's the current thread that should be
- handled specially. */
- if (resume_all)
- ptid = inferior_ptid;
-
- info = find_thread_ptid (ptid);
- inf_ttrace_resume_lwp (info, request, sig);
-
- if (resume_all)
- /* Let all the other threads run too. */
- iterate_over_threads (inf_ttrace_resume_callback, NULL);
-}
-
-static ptid_t
-inf_ttrace_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *ourstatus, int options)
-{
- pid_t pid = ptid_get_pid (ptid);
- lwpid_t lwpid = ptid_get_lwp (ptid);
- ttstate_t tts;
- struct thread_info *ti;
- ptid_t related_ptid;
-
- /* Until proven otherwise. */
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-
- if (pid == -1)
- pid = lwpid = 0;
-
- gdb_assert (pid != 0 || lwpid == 0);
-
- do
- {
- set_sigint_trap ();
-
- if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
- perror_with_name (("ttrace_wait"));
-
- clear_sigint_trap ();
- }
- while (tts.tts_event == TTEVT_NONE);
-
- /* Now that we've waited, we can re-enable the page protections. */
- if (inf_ttrace_reenable_page_protections)
- {
- gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
- inf_ttrace_enable_page_protections (tts.tts_pid);
- inf_ttrace_reenable_page_protections = 0;
- }
-
- ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
-
- if (inf_ttrace_num_lwps == 0)
- {
- struct thread_info *ti;
-
- inf_ttrace_num_lwps = 1;
-
- /* This is the earliest we hear about the lwp member of
- INFERIOR_PTID, after an attach or fork_inferior. */
- gdb_assert (ptid_get_lwp (inferior_ptid) == 0);
-
- /* We haven't set the private member on the main thread yet. Do
- it now. */
- ti = find_thread_ptid (inferior_ptid);
- gdb_assert (ti != NULL && ti->priv == NULL);
- ti->priv =
- xmalloc (sizeof (struct inf_ttrace_private_thread_info));
- memset (ti->priv, 0,
- sizeof (struct inf_ttrace_private_thread_info));
-
- /* Notify the core that this ptid changed. This changes
- inferior_ptid as well. */
- thread_change_ptid (inferior_ptid, ptid);
- }
-
- switch (tts.tts_event)
- {
-#ifdef TTEVT_BPT_SSTEP
- case TTEVT_BPT_SSTEP:
- /* Make it look like a breakpoint. */
- ourstatus->kind = TARGET_WAITKIND_STOPPED;
- ourstatus->value.sig = GDB_SIGNAL_TRAP;
- break;
-#endif
-
- case TTEVT_EXEC:
- ourstatus->kind = TARGET_WAITKIND_EXECD;
- ourstatus->value.execd_pathname =
- xmalloc (tts.tts_u.tts_exec.tts_pathlen + 1);
- if (ttrace (TT_PROC_GET_PATHNAME, tts.tts_pid, 0,
- (uintptr_t)ourstatus->value.execd_pathname,
- tts.tts_u.tts_exec.tts_pathlen, 0) == -1)
- perror_with_name (("ttrace"));
- ourstatus->value.execd_pathname[tts.tts_u.tts_exec.tts_pathlen] = 0;
-
- /* At this point, all inserted breakpoints are gone. Doing this
- as soon as we detect an exec prevents the badness of deleting
- a breakpoint writing the current "shadow contents" to lift
- the bp. That shadow is NOT valid after an exec. */
- mark_breakpoints_out ();
- break;
-
- case TTEVT_EXIT:
- store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
- inf_ttrace_num_lwps = 0;
- break;
-
- case TTEVT_FORK:
- related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
- tts.tts_u.tts_fork.tts_flwpid, 0);
-
- ourstatus->kind = TARGET_WAITKIND_FORKED;
- ourstatus->value.related_pid = related_ptid;
-
- /* Make sure the other end of the fork is stopped too. */
- if (ttrace_wait (tts.tts_u.tts_fork.tts_fpid,
- tts.tts_u.tts_fork.tts_flwpid,
- TTRACE_WAITOK, &tts, sizeof tts) == -1)
- perror_with_name (("ttrace_wait"));
-
- gdb_assert (tts.tts_event == TTEVT_FORK);
- if (tts.tts_u.tts_fork.tts_isparent)
- {
- related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
- tts.tts_u.tts_fork.tts_flwpid, 0);
- ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
- ourstatus->value.related_pid = related_ptid;
- }
- break;
-
- case TTEVT_VFORK:
- if (tts.tts_u.tts_fork.tts_isparent)
- ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
- else
- {
- related_ptid = ptid_build (tts.tts_u.tts_fork.tts_fpid,
- tts.tts_u.tts_fork.tts_flwpid, 0);
-
- ourstatus->kind = TARGET_WAITKIND_VFORKED;
- ourstatus->value.related_pid = related_ptid;
- }
- break;
-
- case TTEVT_LWP_CREATE:
- lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
- ptid = ptid_build (tts.tts_pid, lwpid, 0);
- ti = add_thread (ptid);
- ti->priv =
- xmalloc (sizeof (struct inf_ttrace_private_thread_info));
- memset (ti->priv, 0,
- sizeof (struct inf_ttrace_private_thread_info));
- inf_ttrace_num_lwps++;
- ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
- /* Let the lwp_create-caller thread continue. */
- ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
- ptid_get_lwp (ptid), TT_NOPC, 0, 0);
- /* Return without stopping the whole process. */
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- return ptid;
-
- case TTEVT_LWP_EXIT:
- if (print_thread_events)
- printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (ptid));
- ti = find_thread_ptid (ptid);
- gdb_assert (ti != NULL);
- ((struct inf_ttrace_private_thread_info *)ti->priv)->dying = 1;
- inf_ttrace_num_lwps--;
- /* Let the thread really exit. */
- ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
- ptid_get_lwp (ptid), TT_NOPC, 0, 0);
- /* Return without stopping the whole process. */
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- return ptid;
-
- case TTEVT_LWP_TERMINATE:
- lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
- ptid = ptid_build (tts.tts_pid, lwpid, 0);
- if (print_thread_events)
- printf_unfiltered(_("[%s has been terminated]\n"),
- target_pid_to_str (ptid));
- ti = find_thread_ptid (ptid);
- gdb_assert (ti != NULL);
- ((struct inf_ttrace_private_thread_info *)ti->priv)->dying = 1;
- inf_ttrace_num_lwps--;
-
- /* Resume the lwp_terminate-caller thread. */
- ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
- ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid),
- ptid_get_lwp (ptid), TT_NOPC, 0, 0);
- /* Return without stopping the whole process. */
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- return ptid;
-
- case TTEVT_SIGNAL:
- ourstatus->kind = TARGET_WAITKIND_STOPPED;
- ourstatus->value.sig =
- gdb_signal_from_host (tts.tts_u.tts_signal.tts_signo);
- break;
-
- case TTEVT_SYSCALL_ENTRY:
- gdb_assert (inf_ttrace_reenable_page_protections == 0);
- inf_ttrace_num_lwps_in_syscall++;
- if (inf_ttrace_num_lwps_in_syscall == 1)
- {
- /* A thread has just entered a system call. Disable any
- page protections as the kernel can't deal with them. */
- inf_ttrace_disable_page_protections (tts.tts_pid);
- }
- ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
- ourstatus->value.syscall_number = tts.tts_scno;
- break;
-
- case TTEVT_SYSCALL_RETURN:
- if (inf_ttrace_num_lwps_in_syscall > 0)
- {
- /* If the last thread has just left the system call, this
- would be a logical place to re-enable the page
- protections, but that doesn't work. We can't re-enable
- them until we've done another wait. */
- inf_ttrace_reenable_page_protections =
- (inf_ttrace_num_lwps_in_syscall == 1);
- inf_ttrace_num_lwps_in_syscall--;
- }
- ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
- ourstatus->value.syscall_number = tts.tts_scno;
- break;
-
- default:
- gdb_assert (!"Unexpected ttrace event");
- break;
- }
-
- /* Make sure all threads within the process are stopped. */
- if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
- perror_with_name (("ttrace"));
-
- /* Now that the whole process is stopped, check if any dying thread
- is really dead by now. If a dying thread is still alive, it will
- be stopped too, and will still show up in `info threads', tagged
- with "(Exiting)". We could make `info threads' prune dead
- threads instead via inf_ttrace_thread_alive, but doing this here
- has the advantage that a frontend is notificed sooner of thread
- exits. Note that a dying lwp is still alive, it still has to be
- resumed, like any other lwp. */
- iterate_over_threads (inf_ttrace_delete_dead_threads_callback, NULL);
-
- return ptid;
-}
-
-/* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
- and transfer LEN bytes from WRITEBUF into the inferior's memory at
- ADDR. Either READBUF or WRITEBUF may be null, in which case the
- corresponding transfer doesn't happen. Return the number of bytes
- actually transferred (which may be zero if an error occurs). */
-
-static LONGEST
-inf_ttrace_xfer_memory (CORE_ADDR addr, ULONGEST len,
- void *readbuf, const void *writebuf)
-{
- pid_t pid = ptid_get_pid (inferior_ptid);
-
- /* HP-UX treats text space and data space differently. GDB however,
- doesn't really know the difference. Therefore we try both. Try
- text space before data space though because when we're writing
- into text space the instruction cache might need to be flushed. */
-
- if (readbuf
- && ttrace (TT_PROC_RDTEXT, pid, 0, addr, len, (uintptr_t)readbuf) == -1
- && ttrace (TT_PROC_RDDATA, pid, 0, addr, len, (uintptr_t)readbuf) == -1)
- return 0;
-
- if (writebuf
- && ttrace (TT_PROC_WRTEXT, pid, 0, addr, len, (uintptr_t)writebuf) == -1
- && ttrace (TT_PROC_WRDATA, pid, 0, addr, len, (uintptr_t)writebuf) == -1)
- return 0;
-
- return len;
-}
-
-static enum target_xfer_status
-inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
-{
- switch (object)
- {
- case TARGET_OBJECT_MEMORY:
- {
- LONGEST val = inf_ttrace_xfer_memory (offset, len, readbuf, writebuf);
-
- if (val == 0)
- return TARGET_XFER_EOF;
- else
- {
- *xfered_len = (ULONGEST) val;
- return TARGET_XFER_OK;
- }
- }
-
- case TARGET_OBJECT_UNWIND_TABLE:
- return TARGET_XFER_E_IO;
-
- case TARGET_OBJECT_AUXV:
- return TARGET_XFER_E_IO;
-
- case TARGET_OBJECT_WCOOKIE:
- return TARGET_XFER_E_IO;
-
- default:
- return TARGET_XFER_E_IO;
- }
-}
-
-/* Print status information about what we're accessing. */
-
-static void
-inf_ttrace_files_info (struct target_ops *ignore)
-{
- struct inferior *inf = current_inferior ();
- printf_filtered (_("\tUsing the running image of %s %s.\n"),
- inf->attach_flag ? "attached" : "child",
- target_pid_to_str (inferior_ptid));
-}
-
-static int
-inf_ttrace_thread_alive (struct target_ops *ops, ptid_t ptid)
-{
- return 1;
-}
-
-/* Return a string describing the state of the thread specified by
- INFO. */
-
-static char *
-inf_ttrace_extra_thread_info (struct target_ops *self,
- struct thread_info *info)
-{
- struct inf_ttrace_private_thread_info* priv =
- (struct inf_ttrace_private_thread_info *) info->priv;
-
- if (priv != NULL && priv->dying)
- return "Exiting";
-
- return NULL;
-}
-
-static char *
-inf_ttrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
-{
- pid_t pid = ptid_get_pid (ptid);
- lwpid_t lwpid = ptid_get_lwp (ptid);
- static char buf[128];
-
- if (lwpid == 0)
- xsnprintf (buf, sizeof buf, "process %ld",
- (long) pid);
- else
- xsnprintf (buf, sizeof buf, "process %ld, lwp %ld",
- (long) pid, (long) lwpid);
- return buf;
-}
-\f
-
-/* Implement the get_ada_task_ptid target_ops method. */
-
-static ptid_t
-inf_ttrace_get_ada_task_ptid (struct target_ops *self, long lwp, long thread)
-{
- return ptid_build (ptid_get_pid (inferior_ptid), lwp, 0);
-}
-
-\f
-struct target_ops *
-inf_ttrace_target (void)
-{
- struct target_ops *t = inf_child_target ();
-
- t->to_attach = inf_ttrace_attach;
- t->to_detach = inf_ttrace_detach;
- t->to_resume = inf_ttrace_resume;
- t->to_wait = inf_ttrace_wait;
- t->to_files_info = inf_ttrace_files_info;
- t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
- t->to_insert_watchpoint = inf_ttrace_insert_watchpoint;
- t->to_remove_watchpoint = inf_ttrace_remove_watchpoint;
- t->to_stopped_by_watchpoint = inf_ttrace_stopped_by_watchpoint;
- t->to_region_ok_for_hw_watchpoint =
- inf_ttrace_region_ok_for_hw_watchpoint;
- t->to_kill = inf_ttrace_kill;
- t->to_create_inferior = inf_ttrace_create_inferior;
- t->to_follow_fork = inf_ttrace_follow_fork;
- t->to_mourn_inferior = inf_ttrace_mourn_inferior;
- t->to_thread_alive = inf_ttrace_thread_alive;
- t->to_extra_thread_info = inf_ttrace_extra_thread_info;
- t->to_pid_to_str = inf_ttrace_pid_to_str;
- t->to_xfer_partial = inf_ttrace_xfer_partial;
- t->to_get_ada_task_ptid = inf_ttrace_get_ada_task_ptid;
-
- return t;
-}
-#endif
-\f
-
-/* Prevent warning from -Wmissing-prototypes. */
-void _initialize_inf_ttrace (void);
-
-void
-_initialize_inf_ttrace (void)
-{
-#ifdef HAVE_TTRACE
- inf_ttrace_page_dict.pagesize = getpagesize();
-#endif
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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 ();
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/* 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
-
+++ /dev/null
-/* 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;
- }
-}
-\f
-
-
-/* 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);
-}