[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: Q: what user_enable_single_step() actually means?



Thanks Roland.

But now I am even more confused...

On 09/20, Roland McGrath wrote:
>
> > 	- PTRACE_SINGLESTEP does user_enable_single_step()
> >
> > 	- when the tracee returns to user mode, the next instruction
> > 	  causes exception, do_debug()->send_sigtrap() sends SIGTRAP
> >
> > 	- the tracee notices the signal and reports this SIGTRAP
>
> Correct.  But if the tracee is inside the syscall path at the time, then
> it's a little different.  TIF_SINGLESTEP being set means it will go to the
> syscall_trace_leave path and send a signal before it actually returns to
> user mode.

I am not sure... I can hardly read entry_64.S, but I am not sure
system_call_fastpath: path calls syscall_trace_leave() on exit...
OK, I added printk to syscall_trace_leave(), please see below.

> > At least. Is it true that X86_EFLAGS_TF should provoke the exception/do_debug?
>
> Yes.  You can even set it yourself in userland with:
>
> 	pushf
> 	orl $0x100, (%rsp) /* or (%esp) */
> 	popf
>
> and see the signal.

Yes, this works.

> > But, whatever I did this doesn't work. So, what user_enable_single_step()
> > actually means?
>
> It works very well in the vanilla kernel
> ...
> I tried your prctl hack on the vanilla kernel and a test program does
> indeed get a SIGTRAP.  (This is an x86_64 kernel on an Intel chip, trying
> both 32-bit and 64-bit test programs.)

I used the vanilla kernel too. It doesn't work for me. Under KVM at least...

OK, the kernel patch:

	--- TTT/kernel/sys.c~TF_FBG	2009-06-17 14:11:26.000000000 +0200
	+++ TTT/kernel/sys.c	2009-09-21 20:03:27.000000000 +0200
	@@ -1428,6 +1428,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsi
	 
		error = 0;
		switch (option) {
	+		case 666:
	+			printk(KERN_INFO "prctl: before=%lX\n", task_pt_regs(current)->flags);
	+			user_enable_single_step(current);
	+			printk(KERN_INFO "prctl: after=%lX\n", task_pt_regs(current)->flags);
	+			break;
	+
			case PR_SET_PDEATHSIG:
				if (!valid_signal(arg2)) {
					error = -EINVAL;
	--- TTT/arch/x86/kernel/ptrace.c~TF_FBG	2009-06-11 14:16:46.000000000 +0200
	+++ TTT/arch/x86/kernel/ptrace.c	2009-09-21 20:22:52.000000000 +0200
	@@ -1520,6 +1520,8 @@ asmregparm long syscall_trace_enter(stru
	 
	 asmregparm void syscall_trace_leave(struct pt_regs *regs)
	 {
	+	printk(KERN_INFO "trace_leave enter\n");
	+
		if (unlikely(current->audit_context))
			audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
	 
	@@ -1543,6 +1545,8 @@ asmregparm void syscall_trace_leave(stru
		 * system call instruction.
		 */
		if (test_thread_flag(TIF_SINGLESTEP) &&
	-	    tracehook_consider_fatal_signal(current, SIGTRAP))
	+	    tracehook_consider_fatal_signal(current, SIGTRAP)) {
	+	    	printk(KERN_INFO "trace_leave sends SIGTRAP\n");
			send_sigtrap(current, regs, 0, TRAP_BRKPT);
	+	}
	 }

version:

	$ uname -a
	Linux myhost 2.6.31-00008-g41b61a1-dirty #2 SMP PREEMPT Mon Sep 21 20:23:05 CEST 2009 x86_64 QEMU Virtual CPU version 0.9.1 GenuineIntel GNU/Linux


The 1ts test:

	int main(void)
	{
		assert(0 == prctl(666));

		for (;;)
			;

		return 0;
	}

it doesn't get SIGTRAP, and syscall_trace_leave() is not called.

	$ dmesg -c
	prctl: before=10246
	prctl: after=10346

The same for this test:

	int main(void)
	{
		assert(0 == prctl(666));

		pause();

		return 0;
	}

However,

	int main(void)
	{
		assert(0 == prctl(666));

		printf("after prctl\n");

		return 0;
	}

dies with "Trace/breakpoint trap", dmesg says:

	prctl: before=10246
	prctl: after=10346
	trace_leave enter

I guess "trace_leave enter" corresponds to the next syscall, not to prtcl().

This test

	int main(void)
	{
		printf("before prctl\n");

		assert(0 == prctl(666));

		printf("after prctl\n");

		return 0;
	}

gets SIGTRAP too, but printf() succeeds:

	before prctl
	after prctl
	Trace/breakpoint trap

The final test-case:

	static inline unsigned long getflags(void)
	{
		unsigned long flags;

		asm volatile("pushf ; pop %0\n"
				: "=rm" (flags)
				: /* no input */
				: "memory");
		return flags;
	}

	int main(void)
	{
		unsigned long flags;

		printf("user_enable_single_step()...\n");
		assert(0 == prctl(666));

		flags = getflags();
		printf("flags=%lX\n", flags);

		for (;;)
			;

		return 0;
	}

Result:

	user_enable_single_step()...
	flags=246
	Trace/breakpoint trap

dmesg is the same:

	prctl: before=10246
	prctl: after=10346
	trace_leave enter

Oleg.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]