This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[RFA] Add sparc-linux-tdep
- From: "David S. Miller" <davem at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Sat, 20 Apr 2002 21:54:14 -0700 (PDT)
- Subject: [RFA] Add sparc-linux-tdep
[ Assuming the Sparc OS tdep changes get approved. ]
This makes use of Sparc OS tdep for Linux/Sparc. It adds signal frame
recognition and also dynamic linker support. It also takes care of
the "long double is 8 bytes" issue.
Everything that can be multi-arch'd is. I've noted the in comments
labelled "TODO" in sparc-linux-tdep.c which routines still cannot be
generically multi-arch'd so that I can take care of this later.
2002-04-20 David S. Miller <davem@redhat.com>
* sparc-linux-tdep.c: New file.
* Makefile.in (ALLDEPFILES): Add sparc-linux-tdep.c
(sparc-linux-tdep.o): New dependencies.
(sparc-tdep.o): Add sparc-tdep.h dependency
* config/sparc/tm-linux.h (SIGCONTEXT_PC_OFFSET): Don't define.
(IN_SIGTRAMP, SKIP_SOLIB_RESOLVER, SKIP_PROLOGUE_FRAMELESS_P):
Define.
(sparc_linux_skip_prologue_frameless_p,
sparc_linux_skip_solib_resolver, sparc_linux_in_sigtramp):
Declare.
* config/sparc/tm-sp64linux.h (tm-sysv4.h): Don't include.
(tm-linux.h): Include this instead.
(SIGCONTEXT_PC_OFFSET, GDB_PTRACE_REGS64): Don't define.
(IN_SIGTRAMP, SKIP_SOLIB_RESOLVER, SKIP_PROLOGUE_FRAMELESS_P):
Define.
(sparc_linux_skip_prologue_frameless_p,
sparc_linux_skip_solib_resolver, sparc_linux_in_sigtramp):
Declare.
--- sparc-linux-tdep.c.~1~ Sat Apr 20 20:55:07 2002
+++ sparc-linux-tdep.c Sat Apr 20 21:50:48 2002
@@ -0,0 +1,508 @@
+/* Target-dependent code for GNU/Linux running on Sparc's, for GDB.
+
+ Copyright 2002 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "target.h"
+#include "value.h"
+#include "bfd.h"
+#include "gdb_string.h"
+#include "regcache.h"
+
+#include "gdbcore.h"
+
+#include "elf-bfd.h"
+
+#include "sparc-tdep.h"
+
+/* For sparc_linux_skip_solib_resolver. */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include "solib-svr4.h" /* For struct link_map_offsets. */
+
+/* Recognizing signal handler frames. */
+
+/* GNU/Linux has two flavors of signals. Normal signal handlers, and
+ "realtime" (RT) signals. The RT signals can provide additional
+ information to the signal handler if the SA_SIGINFO flag is set
+ when establishing a signal handler using `sigaction'. It is not
+ unlikely that future versions of GNU/Linux will support SA_SIGINFO
+ for normal signals too. */
+
+/* When the sparc Linux kernel calls a signal handler and the
+ SA_RESTORER flag isn't set, the return address points to a bit of
+ code on the stack. This function returns whether the PC appears to
+ be within this bit of code.
+
+ The instruction sequence for normal signals is
+ mov __NR_sigreturn, %g1 ! hex: 0x821020d8
+ ta 0x10 ! hex: 0x91d02010
+
+ Checking for the code sequence should be somewhat reliable, because
+ the effect is to call the system call sigreturn. This is unlikely
+ to occur anywhere other than a signal trampoline.
+
+ It kind of sucks that we have to read memory from the process in
+ order to identify a signal trampoline, but there doesn't seem to be
+ any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
+ only call us if no function name could be identified, which should
+ be the case since the code is on the stack. */
+
+#define LINUX_SIGTRAMP_WORD0 (0x821020d8) /* mov __NR_sigreturn, %g1 */
+#define LINUX_SIGTRAMP_WORD1 (0x91d02010) /* ta 0x10 */
+
+#define LINUX_SIGTRAMP_LEN (0x8)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+ the routine. Otherwise, return 0. */
+
+static CORE_ADDR
+sparc_linux_sigtramp_start (CORE_ADDR pc)
+{
+ unsigned int buf[LINUX_SIGTRAMP_LEN / sizeof(unsigned int)];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the three instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_SIGTRAMP_WORD0)
+ {
+ if (buf[0] != LINUX_SIGTRAMP_WORD1)
+ return 0;
+
+ pc -= 4;
+
+ if (read_memory_nobpt(pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (buf[0] != LINUX_SIGTRAMP_WORD0
+ || buf[1] != LINUX_SIGTRAMP_WORD1)
+ return 0;
+
+ return pc;
+}
+
+/* This function does the same for RT signals. Here the instruction
+ sequence is
+ mov __NR_rt_sigreturn, %g1 ! hex: 0x82102065
+ ta {0x10,0x6d} ! hex: 0x91d02010 or 0x91d0206d
+
+ The effect is to call the system call rt_sigreturn. The trap number
+ is variable based upon whether this is a 32-bit or 64-bit sparc binary.
+ Note that 64-bit binaries only use this RT signal return method. */
+
+#define LINUX_RT_SIGTRAMP_WORD0 (0x82102065)
+#define LINUX_RT_SIGTRAMP_WORD1_32 (0x91d02010)
+#define LINUX_RT_SIGTRAMP_WORD1_64 (0x91d0206d)
+
+#define LINUX_RT_SIGTRAMP_LEN 8
+
+/* If PC is in a RT sigtramp routine, return the address of the start
+ of the routine. Otherwise, return 0. */
+
+static CORE_ADDR
+sparc_linux_rt_sigtramp_start (CORE_ADDR pc)
+{
+ unsigned int buf[LINUX_RT_SIGTRAMP_LEN / sizeof(unsigned int)];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the two instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_RT_SIGTRAMP_WORD0)
+ {
+ if (buf[0] != LINUX_RT_SIGTRAMP_WORD1_32
+ && buf[0] != LINUX_RT_SIGTRAMP_WORD1_64)
+ return 0;
+
+ pc -= 4;
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (buf[0] != LINUX_RT_SIGTRAMP_WORD0
+ || (buf[1] != LINUX_RT_SIGTRAMP_WORD1_32
+ && buf[1] != LINUX_RT_SIGTRAMP_WORD1_64))
+ return 0;
+
+ return pc;
+}
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.
+
+ TODO Need to generically multi-arch this. */
+
+int
+sparc_linux_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ int ret;
+
+ if (name)
+ ret = (STREQ ("__sigreturn_stub", name) || STREQ ("__rt_sigreturn_stub", name));
+ else
+ ret = (sparc_linux_sigtramp_start (pc) != 0
+ || sparc_linux_rt_sigtramp_start (pc) != 0);
+
+ return ret;
+}
+
+/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
+ PC/SP of the associated sigcontext structure. */
+
+static CORE_ADDR
+sparc_linux_sigtramp_saved_pc (struct frame_info *frame)
+{
+ CORE_ADDR ret;
+ char *buf;
+
+ if (!frame->next)
+ return 0;
+
+ buf = alloca(SPARC_INTREG_SIZE);
+
+ if (sparc_linux_sigtramp_start (frame->pc) != 0)
+ {
+ /* Stack frame is:
+ standard 32-bit register window + slack 96 bytes
+ siginfo_t PC at offset 4 */
+
+ read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+
+ ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+ return ret;
+ }
+
+ if (sparc_linux_rt_sigtramp_start (frame->pc) != 0)
+ {
+ /* For 32-bit task, same as non-rt frame. For 64-bit task
+ the layout is:
+ standard 64-bit register window + slack 192 bytes
+ siginfo_t 128 bytes
+ pt_regs PC at offset 136 */
+ if (! GDB_TARGET_IS_SPARC64)
+ {
+ read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+ }
+ else
+ {
+ read_memory(frame->next->frame + (192 + 128 + 136), buf, SPARC_INTREG_SIZE);
+ }
+
+ ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+ return ret;
+ }
+
+ error ("Couldn't recognize signal trampoline.");
+ return 0;
+}
+
+extern CORE_ADDR sparc_frame_chain (struct frame_info *);
+
+static CORE_ADDR
+sparc_linux_frame_chain (struct frame_info *frame)
+{
+ if (frame->signal_handler_caller)
+ return frame->frame;
+
+ return sparc_frame_chain (frame);
+}
+
+extern CORE_ADDR sparc_frame_saved_pc (struct frame_info *);
+
+/* Return the saved program counter for FRAME. */
+
+static CORE_ADDR
+sparc_linux_frame_saved_pc (struct frame_info *frame)
+{
+ CORE_ADDR ret;
+
+ if (frame->signal_handler_caller)
+ ret = sparc_linux_sigtramp_saved_pc (frame);
+ else
+ ret = sparc_frame_saved_pc (frame);
+
+ return ret;
+}
+
+static CORE_ADDR
+sparc_linux_saved_pc_after_call (struct frame_info *frame)
+{
+ CORE_ADDR ret;
+
+ if (frame->signal_handler_caller)
+ ret = sparc_linux_sigtramp_saved_pc (frame);
+ else
+ ret = sparc_pc_adjust (read_register (RP_REGNUM));
+
+ return ret;
+}
+
+/* Calling functions in shared libraries. */
+
+/* Find the minimal symbol named NAME, and return both the minsym
+ struct and its objfile. This probably ought to be in minsym.c, but
+ everything there is trying to deal with things like C++ and
+ SOFUN_ADDRESS_MAYBE_TURQUOISE, ... Since this is so simple, it may
+ be considered too special-purpose for general consumption. */
+
+static struct minimal_symbol *
+find_minsym_and_objfile (char *name, struct objfile **objfile_p)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *msym;
+
+ ALL_OBJFILE_MSYMBOLS (objfile, msym)
+ {
+ if (SYMBOL_NAME (msym)
+ && STREQ (SYMBOL_NAME (msym), name))
+ {
+ *objfile_p = objfile;
+ return msym;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static CORE_ADDR
+skip_hurd_resolver (CORE_ADDR pc)
+{
+ /* The HURD dynamic linker is part of the GNU C library, so many
+ GNU/Linux distributions use it. (All ELF versions, as far as I
+ know.) An unresolved PLT entry points to "_dl_runtime_resolve",
+ which calls "fixup" to patch the PLT, and then passes control to
+ the function.
+
+ We look for the symbol `_dl_runtime_resolve', and find `fixup' in
+ the same objfile. If we are at the entry point of `fixup', then
+ we set a breakpoint at the return address (at the top of the
+ stack), and continue.
+
+ It's kind of gross to do all these checks every time we're
+ called, since they don't change once the executable has gotten
+ started. But this is only a temporary hack --- upcoming versions
+ of GNU/Linux will provide a portable, efficient interface for
+ debugging programs that use shared libraries. */
+
+ struct objfile *objfile;
+ struct minimal_symbol *resolver
+ = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
+
+ if (resolver)
+ {
+ struct minimal_symbol *fixup
+ = lookup_minimal_symbol ("fixup", NULL, objfile);
+
+ if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+ return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+
+ fixup = lookup_minimal_symbol("profile_fixup", NULL, objfile);
+ if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+ return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+ }
+
+ return 0;
+}
+
+/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
+ This function:
+ 1) decides whether a PLT has sent us into the linker to resolve
+ a function reference, and
+ 2) if so, tells us where to set a temporary breakpoint that will
+ trigger when the dynamic linker is done.
+
+ TODO Need to generically multi-arch this thing. */
+
+CORE_ADDR
+sparc_linux_skip_solib_resolver (CORE_ADDR pc)
+{
+ CORE_ADDR result;
+
+ /* Plug in functions for other kinds of resolvers here. */
+ result = skip_hurd_resolver (pc);
+ if (result)
+ return result;
+
+ return 0;
+}
+
+/* We need special processing here because 'fixup' in the dynamic linker
+ looks like it is frameless, but it really does get a frame from its
+ caller in the PLT (which does save).
+
+ Actually, any piece of code which has the same pettern, ie.:
+
+ place1: save
+ call place2
+ nop
+
+ place2: call place3
+ nop
+ jmp %reg
+ restore
+
+ place3: save
+ ...
+ ret
+ restore
+
+ is going to confuse SKIP_PROLOGUE_FRAMELESS_P. It is hard to
+ formulate a generic fix for this that would not break on sibcalls.
+
+ TODO Need to generically multi-arch this. */
+
+CORE_ADDR
+sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *resolver
+ = find_minsym_and_objfile ((GDB_TARGET_IS_SPARC64 ?
+ "_dl_runtime_resolve_0" :
+ "_dl_runtime_resolve"), &objfile);
+
+ if (resolver)
+ {
+ CORE_ADDR rpc = SYMBOL_VALUE_ADDRESS (resolver);
+ int resolver_size = 0x60;
+
+ /* This size includes all of the resolver instances present.
+ For example on sparc32 it includes _dl_runtime_resolve
+ and _dl_profile_resolve, and on sparc64 it includes
+ _dl_runtime_resolve_0 _dl_runtime_resolve_1 and
+ _dl_profile_resolve. It works because they are present
+ one right after another in the dynamic linker. */
+ if (GDB_TARGET_IS_SPARC64)
+ resolver_size = 0x100;
+
+ if (pc >= rpc && pc < (rpc + resolver_size))
+ return pc + 4;
+ }
+ return sparc_skip_prologue (pc, 1);
+}
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+ structure for native GNU/Linux Sparc targets using the struct offsets
+ defined in link.h (but without actual reference to that file).
+
+ This makes it possible to access GNU/Linux Sparc shared libraries from a
+ GDB that was built on a different host platform (for cross debugging).
+
+ It also is needed to handle GDB multi-arch properly. */
+
+static struct link_map_offsets *
+sparc_linux_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ if (! GDB_TARGET_IS_SPARC64)
+ {
+ lmo.r_debug_size = 8; /* The actual size is 20 bytes, but
+ this is all we need. */
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+ lmo.link_map_size = 20;
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+ else
+ {
+ lmo.r_debug_size = 16; /* The actual size is 40 bytes, but
+ this is all we need. */
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+ lmo.link_map_size = 40;
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 8;
+ lmo.l_next_offset = 24;
+ lmo.l_next_size = 8;
+ lmo.l_prev_offset = 32;
+ lmo.l_prev_size = 8;
+ }
+ }
+
+ return lmp;
+}
+
+static void
+sparc_linux_gdbarch_os_init(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ set_gdbarch_frame_chain (gdbarch, sparc_linux_frame_chain);
+ set_gdbarch_frame_saved_pc (gdbarch, sparc_linux_frame_saved_pc);
+ set_gdbarch_saved_pc_after_call (gdbarch, sparc_linux_saved_pc_after_call);
+
+ if (gdbarch_tdep (gdbarch)->intreg_size == 4)
+ {
+ /* Contrary to the v8 ABI, we use an 8-byte long double
+ in this configuration. */
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ }
+ else
+ {
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ }
+
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ sparc_linux_svr4_fetch_link_map_offsets);
+}
+
+void
+_initialize_sparc_linux_tdep (void)
+{
+ sparc_gdbarch_register_os_abi (ELFOSABI_LINUX, sparc_linux_gdbarch_os_init);
+}
--- Makefile.in.~2~ Sat Apr 20 20:04:36 2002
+++ Makefile.in Sat Apr 20 21:04:24 2002
@@ -1213,7 +1213,7 @@
ser-go32.c ser-pipe.c ser-tcp.c \
sh-tdep.c solib.c solib-svr4.c solib-sunos.c sparc-linux-nat.c \
sparc-nat.c \
- sparc-tdep.c sparcl-tdep.c sun3-nat.c \
+ sparc-tdep.c sparcl-tdep.c sparc-linux-tdep.c sun3-nat.c \
symm-tdep.c symm-nat.c \
vax-tdep.c \
vx-share/xdr_ld.c vx-share/xdr_ptrace.c vx-share/xdr_rdb.c \
@@ -2048,12 +2048,17 @@
sparc-linux-nat.o: sparc-linux-nat.c $(defs_h) $(regcache_h)
+sparc-linux-tdep.o: sparc-linux-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
+ $(inferior_h) $(obstack_h) $(target_h) $(value_h) $(bfd_h) \
+ $(gdb_string_h) $(regcache_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \
+ $(objdiles_h) $(solib_svr4_h) $(BFD_SRC)/elf-bfd.h sparc-tdep.h
+
sparc-nat.o: sparc-nat.c $(bfd_h) $(defs_h) $(inferior_h) $(gdbcore_h) \
$(target_h) $(regcache_h)
sparc-tdep.o: sparc-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \
$(inferior_h) $(objfiles_h) $(symfile_h) $(target_h) $(gdb_string_h) \
- $(arch_utils_h) $(regcache_h) $(BFD_SRC)/elf-bfd.h
+ $(arch_utils_h) $(regcache_h) $(BFD_SRC)/elf-bfd.h sparc-tdep.h
sparcl-tdep.o: sparcl-tdep.c $(defs_h) $(gdbcore_h) $(target_h) $(regcache_h)
--- config/sparc/tm-linux.h.~1~ Sat Apr 20 18:47:06 2002
+++ config/sparc/tm-linux.h Sat Apr 20 20:53:49 2002
@@ -27,8 +27,26 @@
#include "sparc/tm-sparc.h"
-#define SIGCONTEXT_PC_OFFSET 12
-
#include "tm-linux.h"
+
+/* When the sparc Linux kernel calls a signal handler, the return
+ address points to a bit of code on the stack. These definitions
+ are used to identify this bit of code as a signal trampoline in
+ order to support backtracing through calls to signal handlers. */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+/* When we call a function in a shared library, and the PLT sends us
+ into the dynamic linker to find the function's real address, we
+ need to skip over the dynamic linker call. This function decides
+ when to skip, and where to skip to. See the comments for
+ SKIP_SOLIB_RESOLVER at the top of infrun.c. */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
+
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
#endif /* TM_SPARCLINUX_H */
--- config/sparc/tm-sp64linux.h.~1~ Sat Apr 20 18:47:06 2002
+++ config/sparc/tm-sp64linux.h Sat Apr 20 20:54:24 2002
@@ -23,14 +23,31 @@ Foundation, Inc., 59 Temple Place - Suit
#include "sparc/tm-sp64.h"
-#define SIGCONTEXT_PC_OFFSET 16 /* See asm-sparc64/sigcontext.h */
-
/* We always want full V9 + Ultra VIS stuff... */
#undef TM_PRINT_INSN_MACH
#define TM_PRINT_INSN_MACH bfd_mach_sparc_v9a
-#define GDB_PTRACE_REGS64
+#include "tm-linux.h"
+
+
+/* When the sparc Linux kernel calls a signal handler, the return
+ address points to a bit of code on the stack. These definitions
+ are used to identify this bit of code as a signal trampoline in
+ order to support backtracing through calls to signal handlers. */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+/* When we call a function in a shared library, and the PLT sends us
+ into the dynamic linker to find the function's real address, we
+ need to skip over the dynamic linker call. This function decides
+ when to skip, and where to skip to. See the comments for
+ SKIP_SOLIB_RESOLVER at the top of infrun.c. */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
-#include "tm-sysv4.h"
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
-#endif TM_SPARC_LIN64_H
+#endif /* TM_SPARC_LIN64_H */