Two test cases

Denys Vlasenko dvlasenk at redhat.com
Fri Dec 5 15:21:57 UTC 2008


On Fri, 2008-12-05 at 11:10 +0800, Wenji Huang wrote:
> There are two test cases I collected/updated those work fine
> on mainline 2.6.28-rc7. But fail on 2.6.28-rc7+latest utrace patch.
> 
> $ ./sigstep
> sigstep: sigstep.c:63: main: Assertion `0' failed.
> sigstep: sigstep.c:86: main: Assertion `((((__extension__ (((union { 
> __typeof(status) __in; int __i; }) { .__in = (status) }).__i))) & 
> 0xff00) >> 8) == 5' failed.
> Aborted

Works for me on 2.6.27.5-41.fc9.x86_64:

# gcc -Os sigstep.c
# ./a.out; echo $?
0
# cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 15
model name      : Intel(R) Core(TM)2 Duo CPU     T7500  @ 2.20GHz
stepping        : 11
cpu MHz         : 800.000
cache size      : 4096 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 10
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge
mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe
syscall nx lm constant_tsc arch_perfmon pebs bts rep_good nopl pni
monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm ida
bogomips        : 4388.95
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

On which machine does it fail for you?


ptrace is a somewhat delicate beast, and there are some things
which are not done in the testcase correctly
(if you know that I am wrong, do not hesitate to point this out):

> #include <stdio.h>
> #include <string.h>
> #include <signal.h>
> #include <sys/time.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <sys/ptrace.h>
> #include <linux/ptrace.h>
> #include <errno.h>
> #include <assert.h>
> #include <stdlib.h>
> #include <unistd.h>
> 
> 
> static volatile int done;
> struct sigaction action;
> 
> static void
> handler (int sig)
> {
>   raise(SIGUSR2);
>   done = 1;
> } /* handler */
> 
> int main()
> {
>         pid_t pid,child;
> 	int status;
> 	long l;
> 
>         child = fork ();
>         assert (child >= 0);
>         if (child == 0) {
>                   l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
>   		  assert(l==0);

I think it's customary to put "raise(SIGSTOP)" *immediately*
after PTRACE_TRACEME. Then waitpid() for SIGSTOP in parent.
You may achieve this by simply moving PTRACE_TRACEME down,
to raise(SIGSTOP).

> 		  /* Set up the signal handler.  */
> 		  memset (&action, 0, sizeof (action));
> 		  action.sa_handler = handler;
> 		  sigaction(SIGUSR1, &action, NULL);
> 
> 		  raise(SIGSTOP);
> 		  /* Wait.  */
> 		  while (!done);
> 		  assert(0); /* unreachable */
> 	}
>         else {
> 	        pid = waitpid(child, &status, 0);
>         	assert(pid==child);
> 	        assert(WIFSTOPPED(status));
>         	assert(WSTOPSIG(status) == SIGSTOP);
> 
>         	l = ptrace(PTRACE_CONT, child, 0, SIGUSR1);
> 	        assert(l==0);

> 	        pid = waitpid(child, &status, 0); /* stop at handler */
>         	assert(pid==child);
> 	        assert(WIFSTOPPED(status));
>         	assert(WSTOPSIG(status) == SIGUSR2);
> 
>         	l = ptrace(PTRACE_SINGLESTEP, child, 0, 0);/* step in handler */
> 	        assert(l==0);

We are stepping over what instruction here? "done = 1"?
1. What if returning from raise(SIGUSR2) needs
   some instructions too in this arch and/or libc?
2. Does "done = 1;" compile into single instruction?

> 		/* update the value */	
>         	pid = waitpid(child, &status, 0);
> 	        assert(pid==child);
>         	assert(WIFSTOPPED(status));
> 	        assert(WSTOPSIG(status) == SIGTRAP);

Above line is line 86. You have assertion failure here. So, what signal
do you get instead of SIGTRAP?

> 		/* return from handler */

Comment is wrong. How do you know that return from handler is a single
instruction? Why do you even want to return from handler if you
plan to SIGKILL it immediately? Will it still work in mainline
and fail on patched kernel if you skip this PTRACE_SINGLESTEP?
If yes, will it still work/fail if you also replace
ptrace(PTRACE_CONT, ... SIGKILL) with plain kill(child, SIGKILL);?

> 	        l = ptrace(PTRACE_SINGLESTEP, child, 0, 0);
>         	assert(l==0);
>        
> 	        pid = waitpid(child, &status, 0); 
> 	        assert(pid==child);
>         	assert(WIFSTOPPED(status));
> 	        assert(WSTOPSIG(status) == SIGTRAP);
> 
>         	l = ptrace(PTRACE_CONT, child, 0, SIGKILL);
> 	        assert(l==0);
> 
>         	pid = waitpid(pid, &status, 0);
> 	        assert(child==pid);
> 		assert(WTERMSIG(status)==SIGKILL);
> 	}
> return 0;
> }

--
vda





More information about the utrace-devel mailing list