mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-02 15:25:21 +00:00
Revert "ctrools: Rewrite task/threads stopping engine"
This reverts commit 6da51eee3f
.
It breaks transition/file_read test case
This commit is contained in:
254
cr-dump.c
254
cr-dump.c
@@ -724,7 +724,7 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_threads(struct pstree_item *item, int pid_dir)
|
static int parse_threads(pid_t pid, int pid_dir, struct pstree_item *item)
|
||||||
{
|
{
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
@@ -733,7 +733,7 @@ static int parse_threads(struct pstree_item *item, int pid_dir)
|
|||||||
|
|
||||||
dir = opendir_proc(pid_dir, "task");
|
dir = opendir_proc(pid_dir, "task");
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
pr_perror("Can't open %d/task", item->pid);
|
pr_perror("Can't open %d/task", pid);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +762,7 @@ static int parse_threads(struct pstree_item *item, int pid_dir)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_children(struct pstree_item *item, int pid_dir)
|
static int parse_children(pid_t pid, int pid_dir, struct pstree_item *item)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char *tok;
|
char *tok;
|
||||||
@@ -774,7 +774,7 @@ static int parse_children(struct pstree_item *item, int pid_dir)
|
|||||||
file = fopen_proc(pid_dir, "task/%d/children", item->threads[i]);
|
file = fopen_proc(pid_dir, "task/%d/children", item->threads[i]);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
pr_perror("Can't open %d children %d",
|
pr_perror("Can't open %d children %d",
|
||||||
item->pid, item->threads[i]);
|
pid, item->threads[i]);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,154 +806,91 @@ err:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unseize_task_and_threads(struct pstree_item *item, enum cr_task_state st)
|
static struct pstree_item *add_pstree_entry(pid_t pid, int pid_dir, struct list_head *list)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < item->nr_threads; i++)
|
|
||||||
unseize_task(item->threads[i], st); /* item->pid will be here */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pstree_switch_state(struct list_head *list, struct cr_options *opts)
|
|
||||||
{
|
|
||||||
struct pstree_item *item;
|
|
||||||
|
|
||||||
list_for_each_entry(item, list, list) {
|
|
||||||
unseize_task_and_threads(item, opts->final_state);
|
|
||||||
if (opts->leader_only)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int seize_threads(struct pstree_item *item)
|
|
||||||
{
|
|
||||||
int i = 0, ret;
|
|
||||||
|
|
||||||
if ((item->state == TASK_DEAD) && (item->nr_threads > 1)) {
|
|
||||||
pr_err("Zombies with threads are not supported\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < item->nr_threads; i++) {
|
|
||||||
if (item->pid == item->threads[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pr_info("\tSeizing %d's %d thread\n", item->pid, item->threads[i]);
|
|
||||||
ret = seize_task(item->threads[i]);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (ret == TASK_SHOULD_BE_DEAD) {
|
|
||||||
pr_err("Potentially zombie thread not supported\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == TASK_STOPPED) {
|
|
||||||
pr_err("Stopped threads not supported\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
for (i--; i >= 0; i--) {
|
|
||||||
if (item->pid == item->threads[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
unseize_task(item->threads[i], CR_TASK_STOP /* FIXME */);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct pstree_item *collect_task(pid_t pid, struct list_head *list)
|
|
||||||
{
|
|
||||||
int ret, pid_dir;
|
|
||||||
struct pstree_item *item;
|
struct pstree_item *item;
|
||||||
|
|
||||||
item = xzalloc(sizeof(*item));
|
item = xzalloc(sizeof(*item));
|
||||||
if (!item)
|
if (!item)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ret = seize_task(pid);
|
if (parse_threads(pid, pid_dir, item))
|
||||||
if (ret < 0)
|
goto err_free;
|
||||||
|
|
||||||
|
if (parse_children(pid, pid_dir, item))
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
|
||||||
pr_info("Seized task %d, state %d\n", pid, ret);
|
|
||||||
item->pid = pid;
|
item->pid = pid;
|
||||||
item->state = ret;
|
|
||||||
|
|
||||||
pid_dir = open_pid_proc(pid);
|
|
||||||
if (pid_dir < 0)
|
|
||||||
goto err_free;
|
|
||||||
|
|
||||||
if (item->state == TASK_SHOULD_BE_DEAD) {
|
|
||||||
struct proc_pid_stat_small ps;
|
|
||||||
|
|
||||||
ret = parse_pid_stat_small(pid, pid_dir, &ps);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err_close;
|
|
||||||
|
|
||||||
if (ps.state != 'Z') {
|
|
||||||
pr_err("Unseizeable non-zombie %d found, state %c\n",
|
|
||||||
item->pid, ps.state);
|
|
||||||
goto err_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->state = TASK_DEAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = parse_threads(item, pid_dir);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err_close;
|
|
||||||
|
|
||||||
ret = seize_threads(item);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err_close;
|
|
||||||
|
|
||||||
ret = parse_children(item, pid_dir);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err_close;
|
|
||||||
|
|
||||||
if ((item->state == TASK_DEAD) && (item->nr_children > 0)) {
|
|
||||||
pr_err("Zombie with children?! O_o Run, run, run!\n");
|
|
||||||
goto err_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(pid_dir);
|
|
||||||
list_add_tail(&item->list, list);
|
list_add_tail(&item->list, list);
|
||||||
pr_info("Collected %d in %d state\n", item->pid, item->state);
|
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
err_close:
|
|
||||||
close(pid_dir);
|
|
||||||
err_free:
|
err_free:
|
||||||
xfree(item->children);
|
|
||||||
xfree(item->threads);
|
xfree(item->threads);
|
||||||
|
xfree(item->children);
|
||||||
xfree(item);
|
xfree(item);
|
||||||
err:
|
err:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_only)
|
static const int state_sigs[] = {
|
||||||
|
[CR_TASK_STOP] = SIGSTOP,
|
||||||
|
[CR_TASK_RUN] = SIGCONT,
|
||||||
|
[CR_TASK_KILL] = SIGKILL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ps_switch_state(int pid, enum cr_task_state state)
|
||||||
|
{
|
||||||
|
return kill(pid, state_sigs[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pstree_switch_state(struct list_head *list,
|
||||||
|
enum cr_task_state state, int leader_only)
|
||||||
{
|
{
|
||||||
struct pstree_item *item;
|
struct pstree_item *item;
|
||||||
int i;
|
|
||||||
|
|
||||||
pr_info("Collecting tasks starting from %d\n", pid);
|
/*
|
||||||
item = collect_task(pid, pstree_list);
|
* Since ptrace-seize doesn't work on frozen tasks
|
||||||
if (item == NULL)
|
* we stick with explicit tasks stopping via stop
|
||||||
return -1;
|
* signal, but in future it's aimed to switch to
|
||||||
|
* kernel freezer.
|
||||||
|
*/
|
||||||
|
|
||||||
if (leader_only)
|
list_for_each_entry(item, list, list) {
|
||||||
return 0;
|
kill(item->pid, state_sigs[state]);
|
||||||
|
if (leader_only)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < item->nr_children; i++)
|
static int collect_pstree(pid_t pid, struct list_head *pstree_list)
|
||||||
if (collect_pstree(item->children[i], pstree_list, 0) < 0)
|
{
|
||||||
return -1;
|
struct pstree_item *item;
|
||||||
|
unsigned long i;
|
||||||
|
int pid_dir;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
return 0;
|
pid_dir = open_pid_proc(pid);
|
||||||
|
if (pid_dir < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (ps_switch_state(pid, CR_TASK_STOP))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
item = add_pstree_entry(pid, pid_dir, pstree_list);
|
||||||
|
if (!item)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
for (i = 0; i < item->nr_children; i++) {
|
||||||
|
ret = collect_pstree(item->children[i], pstree_list);
|
||||||
|
if (ret)
|
||||||
|
goto err_close;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
err_close:
|
||||||
|
close(pid_dir);
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset *cr_fdset)
|
static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset *cr_fdset)
|
||||||
@@ -1148,12 +1085,25 @@ static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset)
|
|||||||
if (!core)
|
if (!core)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
ret = seize_task(pid);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to seize thread (pid: %d) with %d\n",
|
||||||
|
pid, ret);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
pr_info("Dumping GP/FPU registers ... ");
|
pr_info("Dumping GP/FPU registers ... ");
|
||||||
ret = get_task_regs(pid, core);
|
ret = get_task_regs(pid, core);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
pr_info("OK\n");
|
pr_info("OK\n");
|
||||||
|
|
||||||
|
ret = unseize_task(pid);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Can't unsieze thread (pid: %d)\n", pid);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
core->tc.task_state = TASK_ALIVE;
|
core->tc.task_state = TASK_ALIVE;
|
||||||
core->tc.exit_code = 0;
|
core->tc.exit_code = 0;
|
||||||
|
|
||||||
@@ -1172,6 +1122,16 @@ static int dump_one_zombie(struct pstree_item *item, struct proc_pid_stat *pps,
|
|||||||
{
|
{
|
||||||
struct core_entry *core;
|
struct core_entry *core;
|
||||||
|
|
||||||
|
if (item->nr_children) {
|
||||||
|
pr_err("Zombie %d with children.\n", item->pid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->nr_threads > 1) {
|
||||||
|
pr_err("Zombie %d with threads.\n", item->pid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
cr_fdset = cr_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset);
|
cr_fdset = cr_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset);
|
||||||
if (cr_fdset == NULL)
|
if (cr_fdset == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1231,11 +1191,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
|
|||||||
pr_info("Dumping task (pid: %d)\n", pid);
|
pr_info("Dumping task (pid: %d)\n", pid);
|
||||||
pr_info("========================================\n");
|
pr_info("========================================\n");
|
||||||
|
|
||||||
if (item->state == TASK_STOPPED) {
|
|
||||||
pr_err("Stopped tasks are not supported\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_dir = open_pid_proc(pid);
|
pid_dir = open_pid_proc(pid);
|
||||||
if (pid_dir < 0) {
|
if (pid_dir < 0) {
|
||||||
pr_perror("Can't open %d proc dir", pid);
|
pr_perror("Can't open %d proc dir", pid);
|
||||||
@@ -1247,8 +1202,17 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (item->state == TASK_DEAD)
|
switch (pps_buf.state) {
|
||||||
|
case 'Z':
|
||||||
return dump_one_zombie(item, &pps_buf, cr_fdset);
|
return dump_one_zombie(item, &pps_buf, cr_fdset);
|
||||||
|
case 'T':
|
||||||
|
/* Stopped -- can dump one */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -1;
|
||||||
|
pr_err("Task in bad state: %c\n", pps_buf.state);
|
||||||
|
goto err;
|
||||||
|
};
|
||||||
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
if (!cr_fdset_open(item->pid, CR_FD_DESC_TASK, cr_fdset))
|
if (!cr_fdset_open(item->pid, CR_FD_DESC_TASK, cr_fdset))
|
||||||
@@ -1260,6 +1224,13 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = seize_task(pid);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to seize task (pid: %d) with %d\n",
|
||||||
|
pid, ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = dump_task_core_seized(pid, pid_dir, &pps_buf, cr_fdset);
|
ret = dump_task_core_seized(pid, pid_dir, &pps_buf, cr_fdset);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
|
pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
|
||||||
@@ -1302,6 +1273,12 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = unseize_task(pid);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Can't unsieze (pid: %d) task\n", pid);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = dump_task_files(pid, pid_dir, cr_fdset);
|
ret = dump_task_files(pid, pid_dir, cr_fdset);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
|
pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
|
||||||
@@ -1349,7 +1326,7 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
|
|||||||
pr_info("Dumping process (pid: %d)\n", pid);
|
pr_info("Dumping process (pid: %d)\n", pid);
|
||||||
pr_info("========================================\n");
|
pr_info("========================================\n");
|
||||||
|
|
||||||
if (collect_pstree(pid, &pstree_list, opts->leader_only))
|
if (collect_pstree(pid, &pstree_list))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (opts->namespaces_flags) {
|
if (opts->namespaces_flags) {
|
||||||
@@ -1390,8 +1367,17 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
pstree_switch_state(&pstree_list, opts);
|
switch (opts->final_state) {
|
||||||
|
case CR_TASK_RUN:
|
||||||
|
case CR_TASK_KILL:
|
||||||
|
pstree_switch_state(&pstree_list,
|
||||||
|
opts->final_state, opts->leader_only);
|
||||||
|
case CR_TASK_STOP: /* they are already stopped */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
free_pstree(&pstree_list);
|
free_pstree(&pstree_list);
|
||||||
|
|
||||||
close_cr_fdset(&cr_fdset);
|
close_cr_fdset(&cr_fdset);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
11
crtools.c
11
crtools.c
@@ -289,7 +289,7 @@ int main(int argc, char *argv[])
|
|||||||
int action = -1;
|
int action = -1;
|
||||||
int log_inited = 0;
|
int log_inited = 0;
|
||||||
|
|
||||||
static const char short_opts[] = "dsf:p:t:hcD:o:n:";
|
static const char short_opts[] = "df:p:t:hcD:o:n:";
|
||||||
|
|
||||||
BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
|
BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE);
|
||||||
|
|
||||||
@@ -306,9 +306,6 @@ int main(int argc, char *argv[])
|
|||||||
for (opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx); opt != -1;
|
for (opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx); opt != -1;
|
||||||
opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx)) {
|
opt = getopt_long(argc - 1, argv + 1, short_opts, NULL, &idx)) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 's':
|
|
||||||
opts.final_state = CR_TASK_STOP;
|
|
||||||
break;
|
|
||||||
case 'p':
|
case 'p':
|
||||||
pid = atoi(optarg);
|
pid = atoi(optarg);
|
||||||
opts.leader_only = true;
|
opts.leader_only = true;
|
||||||
@@ -319,6 +316,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
opts.show_pages_content = true;
|
opts.show_pages_content = true;
|
||||||
|
opts.final_state = CR_TASK_RUN;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
opts.show_dump_file = optarg;
|
opts.show_dump_file = optarg;
|
||||||
@@ -400,9 +398,10 @@ usage:
|
|||||||
printk(" -p checkpoint/restore only a single process identified by pid\n");
|
printk(" -p checkpoint/restore only a single process identified by pid\n");
|
||||||
printk(" -t checkpoint/restore the whole process tree identified by pid\n");
|
printk(" -t checkpoint/restore the whole process tree identified by pid\n");
|
||||||
printk(" -f show contents of a checkpoint file\n");
|
printk(" -f show contents of a checkpoint file\n");
|
||||||
printk(" -c show contents of pages dumped in hexdump format\n");
|
printk(" -c in case of checkpoint -- continue running the process after\n"
|
||||||
|
" checkpoint complete, in case of showing file contents --\n"
|
||||||
|
" show contents of pages dumped in hexdump format\n");
|
||||||
printk(" -d detach after restore\n");
|
printk(" -d detach after restore\n");
|
||||||
printk(" -s leave tasks in stopped state after checkpoint instead of killing them\n");
|
|
||||||
printk(" -n checkpoint/restore namespaces - values must be separated by comma\n");
|
printk(" -n checkpoint/restore namespaces - values must be separated by comma\n");
|
||||||
printk(" supported: uts, ipc\n");
|
printk(" supported: uts, ipc\n");
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum cr_task_state {
|
enum cr_task_state {
|
||||||
|
CR_TASK_RUN,
|
||||||
CR_TASK_STOP,
|
CR_TASK_STOP,
|
||||||
CR_TASK_KILL,
|
CR_TASK_KILL,
|
||||||
};
|
};
|
||||||
@@ -138,7 +139,6 @@ struct vma_area {
|
|||||||
struct pstree_item {
|
struct pstree_item {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
pid_t pid; /* leader pid */
|
pid_t pid; /* leader pid */
|
||||||
int state; /* TASK_XXX constants */
|
|
||||||
u32 nr_children; /* number of children */
|
u32 nr_children; /* number of children */
|
||||||
u32 nr_threads; /* number of threads */
|
u32 nr_threads; /* number of threads */
|
||||||
u32 *threads; /* array of threads */
|
u32 *threads; /* array of threads */
|
||||||
|
@@ -317,10 +317,9 @@ struct core_entry {
|
|||||||
};
|
};
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define TASK_SHOULD_BE_DEAD 0x0
|
#define TASK_ALIVE 0x1
|
||||||
#define TASK_ALIVE 0x1
|
#define TASK_DEAD 0x2
|
||||||
#define TASK_DEAD 0x2
|
#define TASK_STOPPED 0x3 /* FIXME - implement */
|
||||||
#define TASK_STOPPED 0x3 /* FIXME - implement */
|
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
|
@@ -4,12 +4,6 @@
|
|||||||
#define PROC_TASK_COMM_LEN 32
|
#define PROC_TASK_COMM_LEN 32
|
||||||
#define PROC_TASK_COMM_LEN_FMT "(%31s"
|
#define PROC_TASK_COMM_LEN_FMT "(%31s"
|
||||||
|
|
||||||
struct proc_pid_stat_small {
|
|
||||||
int pid;
|
|
||||||
char comm[PROC_TASK_COMM_LEN];
|
|
||||||
char state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct proc_pid_stat {
|
struct proc_pid_stat {
|
||||||
int pid;
|
int pid;
|
||||||
char comm[PROC_TASK_COMM_LEN];
|
char comm[PROC_TASK_COMM_LEN];
|
||||||
@@ -78,7 +72,6 @@ struct proc_status_creds {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern int parse_pid_stat(pid_t pid, int pid_dir, struct proc_pid_stat *s);
|
extern int parse_pid_stat(pid_t pid, int pid_dir, struct proc_pid_stat *s);
|
||||||
extern int parse_pid_stat_small(pid_t pid, int pid_dir, struct proc_pid_stat_small *s);
|
|
||||||
extern int parse_maps(pid_t pid, int pid_dir, struct list_head *vma_area_list, bool use_map_files);
|
extern int parse_maps(pid_t pid, int pid_dir, struct list_head *vma_area_list, bool use_map_files);
|
||||||
extern int parse_pid_status(int pid_dir, struct proc_status_creds *);
|
extern int parse_pid_status(int pid_dir, struct proc_status_creds *);
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
#define PTRACE_O_TRACEEXIT 0x00000040
|
#define PTRACE_O_TRACEEXIT 0x00000040
|
||||||
|
|
||||||
extern int seize_task(pid_t pid);
|
extern int seize_task(pid_t pid);
|
||||||
extern int unseize_task(pid_t pid, enum cr_task_state st);
|
extern int unseize_task(pid_t pid);
|
||||||
extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes);
|
extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes);
|
||||||
extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes);
|
extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes);
|
||||||
extern int ptrace_show_area(pid_t pid, void *addr, long bytes);
|
extern int ptrace_show_area(pid_t pid, void *addr, long bytes);
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "crtools.h"
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
30
proc_parse.c
30
proc_parse.c
@@ -175,36 +175,6 @@ err_bogus_mapping:
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_pid_stat_small(pid_t pid, int pid_dir, struct proc_pid_stat_small *s)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
char *tok;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
f = fopen_proc(pid_dir, "stat");
|
|
||||||
if (f == NULL) {
|
|
||||||
pr_perror("Can't open %d's stat", pid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(s, 0, sizeof(*s));
|
|
||||||
n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c",
|
|
||||||
&s->pid, s->comm, &s->state);
|
|
||||||
|
|
||||||
if (n < 3) {
|
|
||||||
pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->comm[PROC_TASK_COMM_LEN-1] = '\0';
|
|
||||||
tok = strchr(s->comm, ')');
|
|
||||||
if (tok)
|
|
||||||
*tok = '\0';
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_pid_stat(pid_t pid, int pid_dir, struct proc_pid_stat *s)
|
int parse_pid_stat(pid_t pid, int pid_dir, struct proc_pid_stat *s)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
67
ptrace.c
67
ptrace.c
@@ -13,22 +13,14 @@
|
|||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "crtools.h"
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ptrace.h"
|
#include "ptrace.h"
|
||||||
|
|
||||||
int unseize_task(pid_t pid, enum cr_task_state st)
|
int unseize_task(pid_t pid)
|
||||||
{
|
{
|
||||||
if (st == CR_TASK_STOP)
|
return ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
||||||
return ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
|
||||||
else if (st == CR_TASK_KILL)
|
|
||||||
return ptrace(PTRACE_KILL, pid, NULL, NULL);
|
|
||||||
else {
|
|
||||||
BUG_ON(1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -38,61 +30,48 @@ int unseize_task(pid_t pid, enum cr_task_state st)
|
|||||||
* of it so the task would not know if it was saddled
|
* of it so the task would not know if it was saddled
|
||||||
* up with someone else.
|
* up with someone else.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int seize_task(pid_t pid)
|
int seize_task(pid_t pid)
|
||||||
{
|
{
|
||||||
siginfo_t si;
|
siginfo_t si;
|
||||||
int status;
|
int status;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
ret = ptrace(PTRACE_SEIZE, pid, NULL,
|
ret = ptrace(PTRACE_SEIZE, pid, NULL,
|
||||||
(void *)(unsigned long)PTRACE_SEIZE_DEVEL);
|
(void *)(unsigned long)PTRACE_SEIZE_DEVEL);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return TASK_SHOULD_BE_DEAD; /* Caller should verify it's really dead */
|
pr_perror("Can't seize task");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_perror("SEIZE %d: can't interrupt task", pid);
|
pr_perror("Can't interrupt task");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wait4(pid, &status, __WALL, NULL);
|
ret = -10;
|
||||||
if (ret < 0) {
|
if (wait4(pid, &status, __WALL, NULL) != pid)
|
||||||
pr_perror("SEIZE %d: can't wait task", pid);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != pid) {
|
ret = -20;
|
||||||
pr_err("SEIZE %d: wrong task attached (%d)\n", pid, ret);
|
if (!WIFSTOPPED(status))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
|
|
||||||
if (!WIFSTOPPED(status)) {
|
jerr_rc(ptrace(PTRACE_GETSIGINFO, pid, NULL, &si), ret, err_cont);
|
||||||
pr_err("SEIZE %d: task not stopped after seize\n", pid);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &si);
|
ret = -30;
|
||||||
if (ret < 0) {
|
if ((si.si_code >> 8) != PTRACE_EVENT_STOP)
|
||||||
pr_perror("SEIZE %d: can't read signfo", pid);
|
goto err_cont;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((si.si_code >> 8) != PTRACE_EVENT_STOP) {
|
jerr_rc(ptrace(PTRACE_SETOPTIONS, pid, NULL,
|
||||||
pr_err("SEIZE %d: wrong stop event received 0x%x\n", pid,
|
(void *)(unsigned long)PTRACE_O_TRACEEXIT), ret, err_cont);
|
||||||
(unsigned int)si.si_code);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (si.si_signo == SIGTRAP)
|
|
||||||
return TASK_ALIVE;
|
|
||||||
else if (si.si_signo == SIGSTOP)
|
|
||||||
return TASK_STOPPED;
|
|
||||||
|
|
||||||
pr_err("SEIZE %d: unsupported stop signal %d\n", pid, si.si_signo);
|
|
||||||
err:
|
err:
|
||||||
unseize_task(pid, CR_TASK_STOP);
|
return ret;
|
||||||
return -1;
|
|
||||||
|
err_cont:
|
||||||
|
kill(pid, SIGCONT);
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ptrace_show_area_r(pid_t pid, void *addr, long bytes)
|
int ptrace_show_area_r(pid_t pid, void *addr, long bytes)
|
||||||
|
Reference in New Issue
Block a user