mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Roland McGrath <roland@redhat.com>
To: Andrew Morton <akpm@osdl.org>, Andi Kleen <ak@suse.de>,
	Linus Torvalds <torvalds@osdl.org>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Jim Paradis <jparadis@redhat.com>,
	Andrew Cagney <cagney@redhat.com>
Subject: [PATCH] x86-64 singlestep through sigreturn system call
Date: Mon, 12 Jul 2004 17:22:30 -0700	[thread overview]
Message-ID: <200407130022.i6D0MUdI023333@magilla.sf.frob.com> (raw)

With Davide Libenzi's patch for i386 and my follow-on patch for x86-64's
ia32 support, single-stepping through any system call correctly traps
immediately on return to user mode.  I still don't know why the same
problem doesn't arise for `syscall'/`sysret' on native 64-bit x86-64, and
would like someone to point me at what I misunderstood in the chip manuals.

But, there is a problem in the case of the rt_sigreturn system call on
native x86-64.  When using PTRACE_SINGLESTEP to step into an rt_sigreturn
system call and the sigcontext being restored does not have TF set in its
%eflags, then we miss the single-step trap.  This makes gdb unhappy.

Here is a test program to run under gdb.  Set a breakpoint on "keeper".
When SIGSEGV hits, just continue to let the program handle it.  When you
get into "keeper", do "display/i $pc" to see what's going on and then do
"stepi" repeatedly to get out of the handler and into the signal handler
trampoline as it makes the rt_sigreturn system call.  When you step into
the `syscall' instruction, you will lose control.  Rather than stopping
immediately, the program will reexecute the faulting instruction and take a
second SIGSEGV.

	#include <signal.h>
	#include <stdlib.h>
	#include <string.h>

	extern void
	keeper (int sig)
	{
	}

	volatile long v1 = 0;
	volatile long v2 = 0;
	volatile long v3 = 0;

	extern long
	bowler (void)
	{
	  /* Try to read address zero.  Do it in a slightly convoluted way so
	     that more than one instruction is used.  */
	  return *(char *) (v1 + v2 + v3);
	}

	int
	main ()
	{
	  static volatile int i;

	  struct sigaction act;
	  memset (&act, 0, sizeof act);
	  act.sa_handler = keeper;
	  sigaction (SIGSEGV, &act, NULL);

	  bowler ();
	  return 0;
	}


This patch fixes the problem by forcing a fake single-step trap at the end
of rt_sigreturn when PTRACE_SINGLESTEP was used to enter the system call.


Thanks,
Roland


Signed-off-by: Roland McGrath <roland@redhat.com>


Index: linux-2.6/arch/x86_64/kernel/signal.c
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/arch/x86_64/kernel/signal.c,v
retrieving revision 1.23
diff -b -p -u -r1.23 signal.c
--- linux-2.6/arch/x86_64/kernel/signal.c 31 May 2004 03:08:04 -0000 1.23
+++ linux-2.6/arch/x86_64/kernel/signal.c 12 Jul 2004 22:14:07 -0000
@@ -92,6 +92,7 @@ static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax)
 {
 	unsigned int err = 0;
+	unsigned int caller_eflags;
 
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -112,6 +113,7 @@ restore_sigcontext(struct pt_regs *regs,
 	{
 		unsigned int tmpflags;
 		err |= __get_user(tmpflags, &sc->eflags);
+		caller_eflags = regs->eflags;
 		regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
 		regs->orig_rax = -1;		/* disable syscall checks */
 	}
@@ -128,6 +130,22 @@ restore_sigcontext(struct pt_regs *regs,
 	}
 
 	err |= __get_user(*prax, &sc->rax);
+
+	if (!err && unlikely(caller_eflags & X86_EFLAGS_TF) &&
+	    (current->ptrace & (PT_PTRACED|PT_DTRACE)) == (PT_PTRACED|PT_DTRACE)) {
+		/*
+		 * If ptrace single-stepped into the sigreturn system call,
+		 * then fake a single-step trap before we resume the restored
+		 * context.
+		 */
+		siginfo_t info;
+		info.si_signo = SIGTRAP;
+		info.si_errno = 0;
+		info.si_code = TRAP_BRKPT;
+		info.si_addr = (void *)regs->rip;
+		force_sig_info(SIGTRAP, &info, current);
+	}
+
 	return err;
 
 badframe:

             reply	other threads:[~2004-07-13  0:24 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-13  0:22 Roland McGrath [this message]
2004-07-13  7:23 ` Andi Kleen
2004-07-15  0:56   ` Roland McGrath
2004-07-15  5:46     ` Andi Kleen
2004-07-15 21:13       ` Roland McGrath
2004-07-15 22:06         ` Andi Kleen
2004-07-15 23:57           ` Roland McGrath
     [not found] <2imAA-4n7-49@gated-at.bofh.it>
     [not found] ` <2iosE-5Kb-17@gated-at.bofh.it>
2004-07-17 11:12   ` Andi Kleen
2004-07-22  2:16     ` Roland McGrath
2004-07-22  6:11       ` Andrew Morton
2004-07-22 22:58         ` Roland McGrath

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200407130022.i6D0MUdI023333@magilla.sf.frob.com \
    --to=roland@redhat.com \
    --cc=ak@suse.de \
    --cc=akpm@osdl.org \
    --cc=cagney@redhat.com \
    --cc=jparadis@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®