From: "stephane eranian" <eranian@googlemail.com>
To: linux-ia64@vger.kernel.org
Subject: ptrace problem with 2.6.25 on Itanium
Date: Thu, 24 Apr 2008 10:39:47 +0000 [thread overview]
Message-ID: <7c86c4470804240339p77639b4ejee73baec305d74c5@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1788 bytes --]
Hello everyone,
I am running into a new problem with perfmon on Itanium and 2.6.25.
The pfmon tool is able to monitor across fork(). For that it relies on
ptrace() to receive notifications on fork. This works fine on X86 and 2.6.25
however it is currently broken on IA-64.
Normally, on fork(), the ptracing parent (here pfmon) receives 2 notifications:
1. SIGTRAP with event PTRACE_EVENT_FORK to indicate a new process
is being created. New pid is extracted via PTRACE_GETEVENTMSG
2. SIGSTOP with for new pid indicating that child is ready to
execute its first
instruction
The first message allow the tool to create the data structure to for
new process,
the second marks the point where a perfmon context can actually be attached.
With 2.6.25 on Itanium, the notifications are received out of order,
i.e., the SIGTOP
first and the FORK notification next. Of course, the tool is confused
because until
it sees the FORK event, it does not know the new process.
This situation never happens on X86 with the same kernel.
To demonstrate the problem, I have attached a simple test program. You need
to pass the name of a command that creates child processes. Look at the order
between the FORK and SIGSTOP notifications. There is a forktest program in
pfmon/tests.
I don't have time to track this down. However, I am highly suspicious of this
new TIF_RESTORE_RSE and the arch_ptrace_stop_needed() code. The do_fork()
routine does indeed set SIGSTOP, before it call ptrace_notify(). But this does
not impact X86, which, by the way, does not define arch_ptrace_stop_needed().
I don't have an older kernel handy to run the test. Hopefully someone
on this list
will try this on 2.6.24 or older.
I am not on this mailing list anymore, so please CC me on your reply.
[-- Attachment #2: task_ptrace.c --]
[-- Type: application/octet-stream, Size: 3911 bytes --]
#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
/*
* This belongs to some LIBC header files for 2.6
*/
#ifndef PTRACE_SETOPTIONS
/* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
#define PTRACE_GETSIGINFO 0x4202
#define PTRACE_SETSIGINFO 0x4203
/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010
#define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040
/* Wait extended result codes for the above trace pt_options. */
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#endif /* PTRACE_OPTIONS */
static void fatal_error(char *fmt,...) __attribute__((noreturn));
static void
fatal_error(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
int
child(char **arg)
{
/*
* will cause the program to stop before executing the first
* user level instruction. We can only attach (load) a context
* if the task is in the STOPPED state.
*/
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
/*
* execute the requested command
*/
execvp(arg[0], arg);
fatal_error("cannot exec: %s\n", arg[0]);
/* not reached */
}
int
parent(char **arg)
{
unsigned long ptrace_flags = 0, sig;
int event, status, ret, wait_type;
pid_t pid, new_pid;
ptrace_flags |= PTRACE_O_TRACEFORK;
/*
* Create the child task
*/
pid = fork();
switch(pid) {
case -1:
fatal_error("Cannot fork process\n");
case 0:
exit(child(arg));
}
/*
* wait for the child to exec
*/
waitpid(pid, &status, WUNTRACED);
/*
* check if process exited early
*/
if (WIFEXITED(status))
fatal_error("command %s exited too early with status %d\n", arg[0], WEXITSTATUS(status));
ptrace_flags |= PTRACE_O_TRACEEXEC;
ptrace_flags |= PTRACE_O_TRACEFORK;
ret = ptrace(PTRACE_SETOPTIONS, pid, NULL, (void *)ptrace_flags);
if (ret)
fatal_error("ptrace setopions=%d\n", errno);
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
if (ret)
fatal_error("ptrace cont=%d\n", errno);
wait_type = WUNTRACED|WNOHANG|__WALL;
for (;;) {
pid = wait4(-1, &status, wait_type, NULL);
if (pid == 0)
continue;
if (pid < 1)
break;
printf("pid=%d errno=%d exited=%d stopped=%d signaled=%d stopsig=%-2d\n",
pid, errno,
WIFEXITED(status),
WIFSTOPPED(status),
WIFSIGNALED(status),
WSTOPSIG(status));
if (WIFEXITED(status) || WIFSIGNALED(status)) {
printf("EXITED [%d]\n", pid);
continue;
}
sig = WSTOPSIG(status);
if (sig == SIGTRAP) {
sig = 0;
event = status >> 16;
switch(event) {
case PTRACE_EVENT_FORK:
ret = ptrace(PTRACE_GETEVENTMSG, pid, NULL, (void *)&new_pid);
if (ret)
fatal_error("ptrace getmsg=%d\n", errno);
printf("FORK new_pid [%ld]\n", new_pid);
ret = ptrace(PTRACE_SETOPTIONS, pid, NULL, (void *)ptrace_flags);
if (ret)
fatal_error("ptrace options newpid=%d\n", errno);
break;
default:
printf("unexpected event %d\n", event);
}
} else if (sig == SIGSTOP) {
printf("SIGSTOP from [%d]\n", pid);
sig = 0;
}
ret = ptrace(PTRACE_CONT, pid, NULL, (void *)sig);
if (ret)
fatal_error("ptrace cont=%d\n", errno);
}
/*
* simply wait for completion
*/
waitpid(pid, &status, 0);
return 0;
}
int
main(int argc, char **argv)
{
if (argc < 2) {
fatal_error("You must specify a command to execute\n");
}
return parent(argv+1);
}
next reply other threads:[~2008-04-24 10:39 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-04-24 10:39 stephane eranian [this message]
2008-04-24 12:04 ` ptrace problem with 2.6.25 on Itanium Petr Tesarik
2008-04-24 12:14 ` stephane eranian
2008-04-24 12:27 ` Petr Tesarik
2008-04-28 2:30 ` Roland McGrath
2008-04-28 10:01 ` Petr Tesarik
2008-04-30 19:32 ` stephane eranian
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=7c86c4470804240339p77639b4ejee73baec305d74c5@mail.gmail.com \
--to=eranian@googlemail.com \
--cc=linux-ia64@vger.kernel.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