This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFA] Add sparc-linux-tdep
- From: Michael Snyder <msnyder at redhat dot com>
- To: "David S. Miller" <davem at redhat dot com>
- Cc: gdb-patches at sources dot redhat dot com
- Date: Tue, 23 Apr 2002 13:19:12 -0700
- Subject: Re: [RFA] Add sparc-linux-tdep
- Organization: Red Hat, Inc.
- References: <20020420.215414.01635851.davem@redhat.com>
"David S. Miller" wrote:
>
> [ Assuming the Sparc OS tdep changes get approved. ]
This is OK in principal; but I note that you have cloned
some functions from i386-linux-tdep and/or arm-linux-tdep,
and that now we have at least three duplicate versions of
these functions.
I wonder if it's time for some sort of "all-linux-nat.c"
module, where code that's needed by all native linux gdbs
can be kept?
I'll fire this question off as a new thread.
>
> 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 */