From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10801 invoked by alias); 8 Apr 2006 06:19:16 -0000 Received: (qmail 10792 invoked by uid 22791); 8 Apr 2006 06:19:14 -0000 X-Spam-Check-By: sourceware.org Received: from dsl027-180-168.sfo1.dsl.speakeasy.net (HELO sunset.davemloft.net) (216.27.180.168) by sourceware.org (qpsmtpd/0.31) with ESMTP; Sat, 08 Apr 2006 06:18:45 +0000 Received: from localhost ([127.0.0.1] ident=davem) by sunset.davemloft.net with esmtp (Exim 4.60) (envelope-from ) id 1FS6mR-0001td-QJ for gdb-patches@sources.redhat.com; Fri, 07 Apr 2006 23:18:43 -0700 Date: Sat, 08 Apr 2006 06:19:00 -0000 Message-Id: <20060407.231843.63374146.davem@davemloft.net> To: gdb-patches@sources.redhat.com Subject: [PATCH]: Fix signal handler stepping on Linux/Sparc From: "David S. Miller" Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2006-04/txt/msg00093.txt.bz2 When we step over the system call trap instruction, GDB does not currently step correctly if this for a sigreturn system call on Linux/SPARC. Thankfully the sparc generic tdep code has a way to support this cleanly, by providing a software single step handler for trap instructions that the target can override. It seems that perhaps some other Linux targets don't handle this right too. MIPS is the most likely platform that gets this wrong in the same exact way, as I don't see any handling of system call instructions in the software single-step handler which MIPS/Linux uses. Alpha I think is in the same boat as MIPS and would need handling in the software single-step code to get this right. It just assumes that the next PC is PC + 4 if it isn't looking at a branch or a jump. Other platforms, such as i386, s390, and I believe ppc, have hardware single stepping so don't need explicit support like this for stepping over a sigreturn() system call properly. Anyways, this gets most of gdb.base/sigstep.exp to pass on Linux/Sparc. There are still a few failures in that testcase, which I need to look into. Tested sparc-linux-gnu and sparc64-linux-gnu. Ok to apply? 2006-04-07 David S. Miller * sparc-linux-tdep.c (sparc32_linux_step_trap): New. (sparc32_linux_init_abi): Hook it into tdep->step_trap. * sparc64-linux-tdep.c (sparc64_linux_step_trap): New. (sparc64_linux_init_abi): Hook it into tdep->step_trap. * Makefile.in: Update dependencies. --- ./sparc-linux-tdep.c.~1~ 2006-04-05 13:27:08.000000000 -0700 +++ ./sparc-linux-tdep.c 2006-04-07 22:48:00.000000000 -0700 @@ -126,6 +126,49 @@ sparc32_linux_sigframe_init (const struc trad_frame_set_id (this_cache, frame_id_build (base, func)); } +/* Return the address of a system call's alternative return + address. */ + +static CORE_ADDR +sparc32_linux_step_trap (unsigned long insn) +{ + if (insn == 0x91d02010) + { + ULONGEST sc_num; + + regcache_cooked_read_unsigned (current_regcache, + SPARC_G1_REGNUM, &sc_num); + + /* __NR_rt_sigreturn is 101 and __NR_sigreturn is 216 */ + if (sc_num == 101 || sc_num == 216) + { + ULONGEST sp, pc_offset; + + regcache_cooked_read_unsigned (current_regcache, + SPARC_SP_REGNUM, &sp); + + /* The kernel puts the sigreturn registers on the stack, + and this is where the signal unwinding state is take from + when returning from a signal. + + For __NR_sigreturn, this register area sits 96 bytes from + the base of the stack. The saved PC sits 4 bytes into the + sigreturn register save area. + + For __NR_rt_sigreturn a siginfo_t, which is 128 bytes, sits + right before the sigreturn register save area. */ + + pc_offset = 96 + 4; + if (sc_num == 101) + pc_offset += 128; + + return read_memory_unsigned_integer (sp + pc_offset, 4); + } + } + + return 0; +} + static void sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -152,6 +195,9 @@ sparc32_linux_init_abi (struct gdbarch_i set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + /* Make sure we can single-step over signal return system calls. */ + tdep->step_trap = sparc32_linux_step_trap; + /* Hook in the DWARF CFI frame unwinder. */ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); } --- ./sparc64-linux-tdep.c.~1~ 2006-04-05 12:19:12.000000000 -0700 +++ ./sparc64-linux-tdep.c 2006-04-07 23:03:14.000000000 -0700 @@ -22,7 +22,9 @@ #include "defs.h" #include "frame.h" #include "frame-unwind.h" +#include "regcache.h" #include "gdbarch.h" +#include "gdbcore.h" #include "osabi.h" #include "solib-svr4.h" #include "symtab.h" @@ -98,6 +100,36 @@ sparc64_linux_sigframe_init (const struc trad_frame_set_id (this_cache, frame_id_build (base, func)); } +/* Return the address of a system call's alternative return + address. */ + +static CORE_ADDR +sparc64_linux_step_trap (unsigned long insn) +{ + if (insn == 0x91d0206d) + { + ULONGEST sp; + + regcache_cooked_read_unsigned (current_regcache, + SPARC_SP_REGNUM, &sp); + if (sp & 1) + sp += BIAS; + + /* The kernel puts the sigreturn registers on the stack, + and this is where the signal unwinding state is take from + when returning from a signal. + + A siginfo_t sits 192 bytes from the base of the stack. This + siginfo_t is 128 bytes, and is followed by the sigreturn + register save area. The saved PC sits at a 136 byte offset + into there. */ + + return read_memory_unsigned_integer (sp + 192 + 128 + 136, 8); + } + + return 0; +} + static void sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -120,6 +152,9 @@ sparc64_linux_init_abi (struct gdbarch_i /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + + /* Make sure we can single-step over signal return system calls. */ + tdep->step_trap = sparc64_linux_step_trap; } --- ./Makefile.in.~1~ 2006-04-05 14:51:11.000000000 -0700 +++ ./Makefile.in 2006-04-07 23:03:32.000000000 -0700 @@ -2616,8 +2616,9 @@ sparc64-linux-nat.o: sparc64-linux-nat.c $(gregset_h) $(sparc64_tdep_h) $(sparc_tdep_h) \ $(sparc_nat_h) $(inferior_h) $(target_h) $(linux_nat_h) sparc64-linux-tdep.o: sparc64-linux-tdep.c $(defs_h) $(frame_h) \ - $(frame_unwind_h) $(gdbarch_h) $(osabi_h) $(solib_svr4_h) \ - $(symtab_h) $(trad_frame_h) $(tramp_frame_h) $(sparc64_tdep_h) + $(frame_unwind_h) $(regcache_h) $(gdbarch_h) $(gdbcore_h) \ + $(osabi_h) $(solib_svr4_h) $(symtab_h) $(trad_frame_h) \ + $(tramp_frame_h) $(sparc64_tdep_h) sparc64-nat.o: sparc64-nat.c $(defs_h) $(gdbarch_h) $(sparc64_tdep_h) \ $(sparc_nat_h) sparc64nbsd-nat.o: sparc64nbsd-nat.c $(defs_h) $(regcache_h) $(target_h) \