Commit ab65ba0a authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

crtools: dump pending signals (v4)

PTRACE_PEEKSIGINFO is used for received pending signals,
then all signal are sent back and saved in a image.

v2: rework according with the new kernel interface
v3: rework according with the newrest kernel interface
v4: fix error handling
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 84176c08
......@@ -28,6 +28,7 @@
#include "protobuf/core.pb-c.h"
#include "protobuf/file-lock.pb-c.h"
#include "protobuf/rlimit.pb-c.h"
#include "protobuf/siginfo.pb-c.h"
#include "asm/types.h"
#include "list.h"
......@@ -1165,6 +1166,63 @@ err:
return ret;
}
static int dump_signal_queue(pid_t tid, int fd, bool group)
{
struct ptrace_peeksiginfo_args arg;
siginfo_t siginfo[32]; /* One page or all non-rt signals */
int ret, i = 0, j, nr;
arg.nr = sizeof(siginfo) / sizeof(siginfo_t);
arg.flags = 0;
if (group)
arg.flags |= PTRACE_PEEKSIGINFO_SHARED;
for (; ; ) {
arg.off = i;
ret = ptrace(PTRACE_PEEKSIGINFO, tid, &arg, siginfo);
if (ret < 0) {
if (errno == EIO) {
pr_warn("ptrace doesn't support PTRACE_PEEKSIGINFO\n");
ret = 0;
} else
pr_perror("ptrace");
break;
}
if (ret == 0)
break;
nr = ret;
for (j = 0; j < nr; j++) {
SiginfoEntry sie = SIGINFO_ENTRY__INIT;
sie.siginfo.len = sizeof(siginfo_t);
sie.siginfo.data = (void *) (siginfo + j);
ret = pb_write_one(fd, &sie, PB_SIGINFO);
if (ret < 0)
break;
i++;
}
}
return ret;
}
static int dump_thread_signals(struct pid *tid)
{
int fd, ret;
fd = open_image(CR_FD_PSIGNAL, O_DUMP, tid->virt);
if (fd < 0)
return -1;
ret = dump_signal_queue(tid->real, fd, false);
close(fd);
return ret;
}
static struct proc_pid_stat pps_buf;
static int dump_task_threads(struct parasite_ctl *parasite_ctl,
......@@ -1174,12 +1232,14 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
for (i = 0; i < item->nr_threads; i++) {
/* Leader is already dumped */
if (item->pid.real == item->threads[i].real) {
if (item->pid.real == item->threads[i].real)
item->threads[i].virt = item->pid.virt;
continue;
else {
if (dump_task_thread(parasite_ctl, &item->threads[i]))
return -1;
}
if (dump_task_thread(parasite_ctl, &item->threads[i]))
if (dump_thread_signals(&item->threads[i]))
return -1;
}
......@@ -1429,6 +1489,12 @@ static int dump_one_task(struct pstree_item *item)
goto err;
}
ret = dump_signal_queue(pid, fdset_fd(cr_fdset, CR_FD_SIGNAL), true);
if (ret) {
pr_err("Can't dump pending signals (pid: %d)\n", pid);
goto err_cure;
}
close_cr_fdset(&cr_fdset);
err:
close_pid_proc();
......
#ifndef __CR_SEIZE_H__
#define __CR_SEIZE_H__
#include <linux/types.h>
#include <sys/ptrace.h>
/* some constants for ptrace */
......@@ -14,6 +15,18 @@
#define PTRACE_LISTEN 0x4208
#ifndef PTRACE_PEEKSIGINFO
#define PTRACE_PEEKSIGINFO 0x4209
struct ptrace_peeksiginfo_args {
__u64 off; /* from which siginfo to start */
__u32 flags;
__u32 nr; /* how may siginfos to take */
};
/* Read signals from a shared (process wide) queue */
#define PTRACE_PEEKSIGINFO_SHARED (1 << 0)
#endif
#define PTRACE_SEIZE_DEVEL 0x80000000
#define PTRACE_EVENT_FORK 1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment