Commit 485c4b50 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov

show: Rework show procedure

Added

 - ability to parse every single file crtools
   understands via magic number

 - dumped memory pages can be rendered in two
   modes -- as a simple set of pages' virtual addresses
   or in hexdummp fashion (via -c command line key).

For example

  ./crtools -s -c -f pages-2557.img

CR_FD_PAGES: pages-2557.img
----------------------------------------
    7fffb44ace20: 00 00 00 00 00 00 00 00  00 00 00 74 65 73 74 2f  |. . . . . . . .  . . . t e s t / |
    7fffb44ace30: 74 65 73 74 2d 73 69 67  61 63 74 69 6f 6e 00 48  |t e s t - s i g  a c t i o n . H |
    7fffb44ace40: 4f 53 54 4e 41 4d 45 3d  6c 6f 63 61 6c 68 6f 73  |O S T N A M E =  l o c a l h o s |
    7fffb44ace50: 74 2e 6c 6f 63 61 6c 64  6f 6d 61 69 6e 00 54 45  |t . l o c a l d  o m a i n . T E |
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
parent c06227ff
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
static char big_buffer[PATH_MAX]; static char big_buffer[PATH_MAX];
static char loc_buf[PAGE_SIZE]; static char loc_buf[PAGE_SIZE];
static void free_pstree(struct list_head *pstree_list) void free_pstree(struct list_head *pstree_list)
{ {
struct pstree_item *item, *p; struct pstree_item *item, *p;
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
# error No x86-32 support yet # error No x86-32 support yet
#endif #endif
#define PR_SYMBOL(sym) \
((sym < 32 || sym > 126) ? '.' : sym)
#define pr_regs4(s, n1, n2, n3, n4) \ #define pr_regs4(s, n1, n2, n3, n4) \
pr_info("%8s: %16lx " \ pr_info("%8s: %16lx " \
"%8s: %16lx " \ "%8s: %16lx " \
...@@ -54,32 +58,252 @@ ...@@ -54,32 +58,252 @@
static char local_buf[PAGE_SIZE]; static char local_buf[PAGE_SIZE];
static LIST_HEAD(pstree_list); static LIST_HEAD(pstree_list);
/* FIXME: same as dump -- unify */ static void show_shmem(char *name, int fd_shmem, bool show_header)
static void free_pstree(void)
{ {
struct pstree_item *item, *p; struct shmem_entry e;
list_for_each_entry_safe(item, p, &pstree_list, list) { if (show_header) {
xfree(item->children); pr_info("\n");
xfree(item); pr_info("CR_FD_SHMEM: %s\n", name);
pr_info("----------------------------------------\n");
}
while (1) {
int ret = read_ptr_safe_eof(fd_shmem, &e, out);
if (!ret)
goto out;
pr_info("0x%lx-0x%lx id %lu\n", e.start, e.end, e.shmid);
} }
INIT_LIST_HEAD(&pstree_list); out:
if (show_header)
pr_info("----------------------------------------\n");
} }
static void show_core_regs(struct cr_fdset *cr_fdset) static void show_files(char *name, int fd_files, bool show_header)
{ {
struct user_regs_entry regs; struct fdinfo_entry e;
struct desc_struct tls;
int fd_core, i;
fd_core = cr_fdset->desc[CR_FD_CORE].fd; if (show_header) {
if (fd_core < 0) { pr_info("\n");
pr_err("Negative fd passed %s\n", pr_info("CR_FD_FDINFO: %s\n", name);
cr_fdset->desc[CR_FD_CORE].name); pr_info("----------------------------------------\n");
goto err;
} }
while (1) {
int ret = read_ptr_safe_eof(fd_files, &e, out);
if (!ret)
goto out;
if (e.len) {
int ret = read(fd_files, local_buf, e.len);
if (ret != e.len) {
pr_perror("Can't read %d bytes\n", e.len);
goto out;
}
local_buf[e.len] = 0;
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx --> %s\n",
e.type, e.len, e.flags, e.pos, e.addr, local_buf);
} else
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx\n",
e.type, e.len, e.flags, e.pos, e.addr);
}
out:
if (show_header)
pr_info("----------------------------------------\n");
}
static void show_pipes(char *name, int fd_pipes, bool show_header)
{
struct pipe_entry e;
int ret;
if (show_header) {
pr_info("\n");
pr_info("CR_FD_PIPES: %s\n", name);
pr_info("----------------------------------------\n");
}
while (1) {
int ret = read_ptr_safe_eof(fd_pipes, &e, out);
if (!ret)
goto out;
pr_info("fd: %8lx pipeid: %8lx flags: %8lx bytes: %8lx\n",
e.fd, e.pipeid, e.flags, e.bytes);
if (e.bytes)
lseek(fd_pipes, e.bytes, SEEK_CUR);
}
out:
if (show_header)
pr_info("----------------------------------------\n");
}
static void show_vma(int fd_vma)
{
struct vma_area vma_area = {};
struct vma_entry ve;
pr_info("\n\t---[VMA areas]---\n");
while (1) {
read_ptr_safe(fd_vma, &ve, out);
if (final_vma_entry(&ve))
break;
/* Simply in a sake of fancy printing */
vma_area.vma = ve;
pr_info_vma(&vma_area);
}
out:
; /* to placate gcc */
}
static void show_pages(char *name, int fd_pages, bool show_header, bool show_content)
{
if (show_header) {
pr_info("\n");
pr_info("CR_FD_PAGES: %s\n", name);
pr_info("----------------------------------------\n");
}
if (show_content) {
while (1) {
struct page_entry e;
unsigned long addr;
int i, j;
read_ptr_safe(fd_pages, &e, out);
if (final_page_entry(&e))
break;
addr = e.va;
for (i = 0; i < PAGE_IMAGE_SIZE; i+= 16) {
pr_info("%16lx: ", addr + i);
for (j = 0; j < 8; j++)
pr_info("%02x ", e.data[i + j]);
pr_info(" ");
for (j = 8; j < 16; j++)
pr_info("%02x ", e.data[i + j]);
pr_info(" |");
for (j = 0; j < 8; j++)
pr_info("%c ", PR_SYMBOL(e.data[i + j]));
pr_info(" ");
for (j = 8; j < 16; j++)
pr_info("%c ", PR_SYMBOL(e.data[i + j]));
pr_info("|\n");
}
pr_info("\n --- End of page ---\n\n");
}
} else {
while (1) {
struct page_entry e;
int i, j;
pr_info("\t");
for (i = 0; i < DEF_PAGES_PER_LINE; i++) {
read_ptr_safe(fd_pages, &e, out);
if (final_page_entry(&e)) {
pr_info("\n");
goto out;
}
pr_info("%16lx ", e.va);
}
pr_info("\n");
}
}
out:
if (show_header)
pr_info("----------------------------------------\n");
}
static void show_sigacts(char *name, int fd_sigacts, bool show_header)
{
struct sa_entry e;
if (show_header) {
pr_info("\n");
pr_info("CR_FD_SIGACT: %s\n", name);
pr_info("----------------------------------------\n");
}
while (1) {
int ret = read_ptr_safe_eof(fd_sigacts, &e, out);
if (!ret)
goto out;
pr_info("sigaction: %016lx mask: %08lx "
"flags: %016lx restorer: %016lx\n",
(long)e.sigaction,
*(long *)e.mask,
(long)e.flags,
(long)e.restorer);
}
out:
if (show_header)
pr_info("----------------------------------------\n");
}
static void show_pstree(char *name, int fd_sigacts, bool show_header)
{
struct pstree_entry e;
if (show_header) {
pr_info("\n");
pr_info("CR_FD_PSTREE: %s\n", name);
pr_info("----------------------------------------\n");
}
while (1) {
u32 pid;
int ret;
ret = read_ptr_safe_eof(fd_sigacts, &e, out);
if (!ret)
goto out;
pr_info("pid: %8d nr_children: %8d nr_threads: %8d\n",
e.pid, e.nr_children, e.nr_threads);
if (e.nr_children) {
pr_info("\\\n");
pr_info(" +--- children: ");
while (e.nr_children--) {
ret = read_ptr_safe_eof(fd_sigacts, &pid, out);
if (!ret)
goto out;
pr_info(" %6d", pid);
}
pr_info("\n");
}
if (e.nr_threads) {
pr_info(" \\\n");
pr_info(" --- threads: ");
while (e.nr_threads--) {
ret = read_ptr_safe_eof(fd_sigacts, &pid, out);
if (!ret)
goto out;
pr_info(" %6d", pid);
}
pr_info("\n");
}
}
out:
if (show_header)
pr_info("----------------------------------------\n");
}
static void show_core_regs(int fd_core)
{
struct user_regs_entry regs;
struct desc_struct tls;
int i;
pr_info("\n\t---[GP registers set]---\n"); pr_info("\n\t---[GP registers set]---\n");
lseek(fd_core, GET_FILE_OFF(struct core_entry, u.arch.gpregs), SEEK_SET); lseek(fd_core, GET_FILE_OFF(struct core_entry, u.arch.gpregs), SEEK_SET);
...@@ -93,22 +317,19 @@ static void show_core_regs(struct cr_fdset *cr_fdset) ...@@ -93,22 +317,19 @@ static void show_core_regs(struct cr_fdset *cr_fdset)
pr_regs4(regs, r11, r12, r13, r14); pr_regs4(regs, r11, r12, r13, r14);
pr_regs3(regs, r15, bp, bx); pr_regs3(regs, r15, bp, bx);
pr_regs4(regs, orig_ax, flags, fs_base, gs_base); pr_regs4(regs, orig_ax, flags, fs_base, gs_base);
pr_info("\n");
err: err:
return; return;
} }
static void show_core_rest(struct cr_fdset *cr_fdset) static void show_core_rest(int fd_core)
{ {
int fd_core, i;
u32 personality;
char comm[TASK_COMM_LEN];
u64 mm_brk, mm_start_code, mm_end_code;
u64 mm_start_data, mm_end_data, mm_start_stack, mm_start_brk; u64 mm_start_data, mm_end_data, mm_start_stack, mm_start_brk;
u64 mm_brk, mm_start_code, mm_end_code;
fd_core = cr_fdset->desc[CR_FD_CORE].fd; char comm[TASK_COMM_LEN];
if (fd_core < 0) u32 personality;
goto err; int i;
lseek(fd_core, GET_FILE_OFF(struct core_entry, task_personality), SEEK_SET); lseek(fd_core, GET_FILE_OFF(struct core_entry, task_personality), SEEK_SET);
read_ptr_safe(fd_core, &personality, err); read_ptr_safe(fd_core, &personality, err);
...@@ -137,249 +358,116 @@ static void show_core_rest(struct cr_fdset *cr_fdset) ...@@ -137,249 +358,116 @@ static void show_core_rest(struct cr_fdset *cr_fdset)
lseek(fd_core, GET_FILE_OFF(struct core_entry, mm_start_brk), SEEK_SET); lseek(fd_core, GET_FILE_OFF(struct core_entry, mm_start_brk), SEEK_SET);
read_ptr_safe(fd_core, &mm_start_brk, err); read_ptr_safe(fd_core, &mm_start_brk, err);
pr_info("Personality: %x\n", personality); pr_info("\n\t---[Task parameters]---\n");
pr_info("Command: %s\n", comm); pr_info("\tPersonality: %x\n", personality);
pr_info("Brk: %lx\n", mm_brk); pr_info("\tCommand: %s\n", comm);
pr_info("Start code: %lx\n", mm_start_code); pr_info("\tBrk: %lx\n", mm_brk);
pr_info("End code: %lx\n", mm_end_code); pr_info("\tStart code: %lx\n", mm_start_code);
pr_info("Start stack: %lx\n", mm_start_stack); pr_info("\tEnd code: %lx\n", mm_end_code);
pr_info("Start data: %lx\n", mm_start_data); pr_info("\tStart stack: %lx\n", mm_start_stack);
pr_info("End data: %lx\n", mm_end_data); pr_info("\tStart data: %lx\n", mm_start_data);
pr_info("Start brk: %lx\n", mm_start_brk); pr_info("\tEnd data: %lx\n", mm_end_data);
pr_info("\tStart brk: %lx\n", mm_start_brk);
err:
return;
}
static void show_shmem(struct cr_fdset *cr_fdset)
{
struct shmem_entry e;
int fd_shmem, ret;
pr_info("\n"); pr_info("\n");
pr_info("CR_FD_SHMEM: %s\n", cr_fdset->desc[CR_FD_SHMEM].name);
pr_info("----------------------------------------\n");
fd_shmem = cr_fdset->desc[CR_FD_SHMEM].fd;
lseek(fd_shmem, MAGIC_OFFSET, SEEK_SET);
while (1) {
ret = read(fd_shmem, &e, sizeof(e));
if (!ret)
goto err;
if (ret != sizeof(e)) {
pr_perror("Can't read fdinfo entry");
goto err;
}
pr_info("0x%lx-0x%lx id %lu\n", e.start, e.end, e.shmid);
}
err: err:
pr_info("----------------------------------------\n"); return;
} }
static void show_files(struct cr_fdset *cr_fdset) static void show_core(char *name, int fd_core, bool show_header, bool show_content)
{ {
struct fdinfo_entry e; struct stat stat;
int fd_files, ret; bool is_thread;
pr_info("\n");
pr_info("CR_FD_FDINFO: %s\n", cr_fdset->desc[CR_FD_FDINFO].name);
pr_info("----------------------------------------\n");
fd_files = cr_fdset->desc[CR_FD_FDINFO].fd;
lseek(fd_files, MAGIC_OFFSET, SEEK_SET); if (fstat(fd_core, &stat)) {
pr_perror("Can't get stat on %s\n", name);
while (1) { goto out;
ret = read(fd_files, &e, sizeof(e));
if (!ret)
goto err;
if (ret != sizeof(e)) {
pr_perror("Can't read fdinfo entry");
goto err;
}
if (e.len) {
ret = read(fd_files, local_buf, e.len);
if (ret != e.len) {
pr_perror("Can't read %d bytes\n", e.len);
goto err;
}
local_buf[e.len] = 0;
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx --> %s\n",
e.type, e.len, e.flags, e.pos, e.addr, local_buf);
} else
pr_info("type: %02x len: %02x flags: %4x pos: %8x addr: %16lx\n",
e.type, e.len, e.flags, e.pos, e.addr);
} }
err: is_thread = (stat.st_size == GET_FILE_OFF_AFTER(struct core_entry));
pr_info("----------------------------------------\n");
}
static void show_pipes(struct cr_fdset *cr_fdset) if (show_header) {
{ pr_info("\n");
struct pipe_entry e; pr_info("CR_FD_CORE: %s", name);
int fd_pipes, ret; if (is_thread)
pr_info(" (thread)\n");
pr_info("\n"); else
pr_info("CR_FD_PIPES: %s\n", cr_fdset->desc[CR_FD_PIPES].name); pr_info("\n");
pr_info("----------------------------------------\n"); pr_info("----------------------------------------\n");
fd_pipes = cr_fdset->desc[CR_FD_PIPES].fd;
lseek(fd_pipes, MAGIC_OFFSET, SEEK_SET);
while (1) {
ret = read(fd_pipes, &e, sizeof(e));
if (!ret)
goto err;
if (ret != sizeof(e)) {
pr_perror("Can't read pipe entry\n");
goto err;
}
pr_info("fd: %8lx pipeid: %8lx flags: %8lx bytes: %8lx\n",
e.fd, e.pipeid, e.flags, e.bytes);
if (e.bytes)
lseek(fd_pipes, e.bytes, SEEK_CUR);
} }
err: show_core_regs(fd_core);
pr_info("----------------------------------------\n"); show_core_rest(fd_core);
} if (is_thread)
static void show_core(struct cr_fdset *cr_fdset)
{
struct vma_area vma_area = {};
struct vma_entry ve;
int fd_core, ret;
u64 va;
pr_info("\n");
pr_info("CR_FD_CORE: %s\n", cr_fdset->desc[CR_FD_CORE].name);
pr_info("----------------------------------------\n");
fd_core = cr_fdset->desc[CR_FD_CORE].fd;
if (fd_core < 0)
goto out; goto out;
show_core_regs(cr_fdset);
show_core_rest(cr_fdset);
lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET); lseek(fd_core, GET_FILE_OFF_AFTER(struct core_entry), SEEK_SET);
/* /*
* Start with VMA, then pages. * If this is thread code -- we should jump out once
* we reach EOF.
*/ */
pr_info("\n\t---[VMA areas]---\n"); if (is_thread)
while (1) { goto out;
ret = read(fd_core, &ve, sizeof(ve));
if (!ret)
break;
if (ret != sizeof(ve)) {
pr_perror("Unable to read VMA\n");
goto out;
}
if (final_vma_entry(&ve)) {
int ppl = 0;
pr_info("\n\t---[Pages]---\n");
while (1) {
ret = read(fd_core, &va, sizeof(va));
if (!ret)
goto out;
if (ret != sizeof(va)) {
pr_perror("Unable to read VA\n");
goto out;
}
if (va == 0)
goto out;
if (ppl == 0)
pr_info("\t");
pr_info("%16lx ", va);
ppl++;
if (ppl == DEF_PAGES_PER_LINE) {
pr_info("\n");
ppl = 0;
}
lseek(fd_core, PAGE_SIZE, SEEK_CUR); show_vma(fd_core);
}
}
/* Simply in a sake of fancy printing */
vma_area.vma = ve;
pr_info_vma(&vma_area);
}
pr_info("\n\t---[Memory pages]---\n");
show_pages(name, fd_core, false, show_content);
out: out:
pr_info("\n----------------------------------------\n"); if (show_header)
pr_info("----------------------------------------\n");
} }
static void show_pstree_from_file(int fd, char *name) static int cr_parse_file(struct cr_options *opts)
{ {
int ret; u32 magic;
int fd = -1;
pr_info("\n"); int ret = -1;
pr_info("CR_FD_PSTREE: %s\n", name);
pr_info("----------------------------------------\n");
while (1) {
struct pstree_entry e;
unsigned long i;
u32 child_pid;
ret = read(fd, &e, sizeof(e));
if (!ret)
break;
if (ret != sizeof(e)) {
pr_perror("Bad pstree entry");
break;
}
pr_info("Process %d number of children: %d\n",
e.pid, e.nr_children);
for (i = 0; i < e.nr_children; i++) { fd = open(opts->show_dump_file, O_RDONLY);
ret = read(fd, &child_pid, if (fd < 0) {
sizeof(child_pid)); pr_perror("Can't open %s\n", opts->show_dump_file);
pr_info(" %d", child_pid); goto err;
}
if (e.nr_children)
pr_info("\n");
} }
pr_info("----------------------------------------\n"); read_ptr_safe(fd, &magic, err);
}
switch (magic) {
static void show_pstree(struct list_head *head, char *name) case FDINFO_MAGIC:
{ show_files(opts->show_dump_file, fd, true);
struct pstree_item *item; break;
int i; case PAGES_MAGIC:
show_pages(opts->show_dump_file, fd, true,
pr_info("\n"); opts->show_pages_content);
pr_info("CR_FD_PSTREE: %s\n", name); break;
pr_info("----------------------------------------\n"); case CORE_MAGIC:
show_core(opts->show_dump_file, fd, true,
list_for_each_entry(item, head, list) { opts->show_pages_content);
pr_info("Process %d number of children: %d threads: %d\n", break;
item->pid, item->nr_children, item->nr_threads); case SHMEM_MAGIC:
for (i = 0; i < item->nr_children; i++) show_shmem(opts->show_dump_file, fd, true);
pr_info(" %d", item->children[i]); break;
if (item->nr_children) case PSTREE_MAGIC:
pr_info("\n"); show_pstree(opts->show_dump_file, fd, true);
break;
case PIPES_MAGIC:
show_pipes(opts->show_dump_file, fd, true);
break;
case SIGACT_MAGIC:
show_sigacts(opts->show_dump_file, fd, true);
break;
default:
pr_err("Unknown magic %x on %s\n", opts->show_dump_file);
goto err;
} }
ret = 0;
pr_info("----------------------------------------\n"); err:
close_safe(&fd);
return ret;
} }
static int collect_pstree(pid_t pid, struct cr_fdset *cr_fdset) static int collect_pstree(struct list_head *head, pid_t pid, struct cr_fdset *cr_fdset)
{ {
int fd = cr_fdset->desc[CR_FD_PSTREE].fd; int fd = cr_fdset->desc[CR_FD_PSTREE].fd;
struct pstree_item *item = NULL; struct pstree_item *item = NULL;
...@@ -428,7 +516,7 @@ static int collect_pstree(pid_t pid, struct cr_fdset *cr_fdset) ...@@ -428,7 +516,7 @@ static int collect_pstree(pid_t pid, struct cr_fdset *cr_fdset)
goto err; goto err;
} }
list_add_tail(&item->list, &pstree_list); list_add_tail(&item->list, head);
} }
item = NULL; item = NULL;
...@@ -444,25 +532,34 @@ err: ...@@ -444,25 +532,34 @@ err:
return ret; return ret;
} }
int cr_show(unsigned long pid, struct cr_options *opts) static int cr_show_all(unsigned long pid, struct cr_options *opts)
{ {
struct cr_fdset *cr_fdset; struct cr_fdset *cr_fdset = NULL;
struct pstree_item *item; struct pstree_item *item = NULL;
LIST_HEAD(pstree_list);
int i, ret = -1; int i, ret = -1;
cr_fdset = alloc_cr_fdset(pid); cr_fdset = alloc_cr_fdset(pid);
if (!cr_fdset) if (!cr_fdset)
goto out; goto out;
ret = prep_cr_fdset_for_restore(cr_fdset, CR_FD_DESC_ALL); ret = prep_cr_fdset_for_restore(cr_fdset,
CR_FD_DESC_USE(CR_FD_PSTREE));
if (ret) if (ret)
goto out; goto out;
ret = collect_pstree(pid, cr_fdset); ret = collect_pstree(&pstree_list, pid, cr_fdset);
if (ret) if (ret)
goto out; goto out;
show_pstree(&pstree_list, cr_fdset->desc[CR_FD_PSTREE].name); /*
* Yeah, I know we read the same file for second
* time here, but this saves us from code duplication.
*/
lseek(cr_fdset->desc[CR_FD_PSTREE].fd, MAGIC_OFFSET, SEEK_SET);
show_pstree(cr_fdset->desc[CR_FD_PSTREE].name,
cr_fdset->desc[CR_FD_PSTREE].fd,
true);
close_cr_fdset(cr_fdset); close_cr_fdset(cr_fdset);
free_cr_fdset(&cr_fdset); free_cr_fdset(&cr_fdset);
...@@ -477,7 +574,10 @@ int cr_show(unsigned long pid, struct cr_options *opts) ...@@ -477,7 +574,10 @@ int cr_show(unsigned long pid, struct cr_options *opts)
if (ret) if (ret)
goto out; goto out;
show_core(cr_fdset); lseek(cr_fdset->desc[CR_FD_CORE].fd, MAGIC_OFFSET, SEEK_SET);
show_core(cr_fdset->desc[CR_FD_CORE].name,
cr_fdset->desc[CR_FD_CORE].fd,
true, opts->show_pages_content);
if (item->nr_threads > 1) { if (item->nr_threads > 1) {
struct cr_fdset *cr_fdset_th; struct cr_fdset *cr_fdset_th;
...@@ -491,6 +591,7 @@ int cr_show(unsigned long pid, struct cr_options *opts) ...@@ -491,6 +591,7 @@ int cr_show(unsigned long pid, struct cr_options *opts)
cr_fdset_th = alloc_cr_fdset(item->threads[i]); cr_fdset_th = alloc_cr_fdset(item->threads[i]);
if (!cr_fdset) if (!cr_fdset)
goto out; goto out;
ret = prep_cr_fdset_for_restore(cr_fdset_th, CR_FD_DESC_CORE); ret = prep_cr_fdset_for_restore(cr_fdset_th, CR_FD_DESC_CORE);
if (ret) if (ret)
goto out; goto out;
...@@ -499,7 +600,10 @@ int cr_show(unsigned long pid, struct cr_options *opts) ...@@ -499,7 +600,10 @@ int cr_show(unsigned long pid, struct cr_options *opts)
pr_info("Thread: %d\n", item->threads[i]); pr_info("Thread: %d\n", item->threads[i]);
pr_info("----------------------------------------\n"); pr_info("----------------------------------------\n");
show_core_regs(cr_fdset_th); lseek(cr_fdset_th->desc[CR_FD_CORE].fd, MAGIC_OFFSET, SEEK_SET);
show_core(cr_fdset_th->desc[CR_FD_CORE].name,
cr_fdset_th->desc[CR_FD_CORE].fd,
false, opts->show_pages_content);
pr_info("----------------------------------------\n"); pr_info("----------------------------------------\n");
...@@ -508,17 +612,36 @@ int cr_show(unsigned long pid, struct cr_options *opts) ...@@ -508,17 +612,36 @@ int cr_show(unsigned long pid, struct cr_options *opts)
} }
} }
show_pipes(cr_fdset); show_pipes(cr_fdset->desc[CR_FD_PIPES].name,
show_files(cr_fdset); cr_fdset->desc[CR_FD_PIPES].fd, true);
show_shmem(cr_fdset);
show_files(cr_fdset->desc[CR_FD_FDINFO].name,
cr_fdset->desc[CR_FD_FDINFO].fd, true);
show_shmem(cr_fdset->desc[CR_FD_SHMEM].name,
cr_fdset->desc[CR_FD_SHMEM].fd, true);
show_sigacts(cr_fdset->desc[CR_FD_SIGACT].name,
cr_fdset->desc[CR_FD_SIGACT].fd, true);
close_cr_fdset(cr_fdset);
free_cr_fdset(&cr_fdset);
if (opts->leader_only) if (opts->leader_only)
break; break;
} }
out: out:
free_pstree(); free_pstree(&pstree_list);
close_cr_fdset(cr_fdset); close_cr_fdset(cr_fdset);
free_cr_fdset(&cr_fdset); free_cr_fdset(&cr_fdset);
return ret; return ret;
} }
int cr_show(unsigned long pid, struct cr_options *opts)
{
if (opts->show_single_file)
return cr_parse_file(opts);
return cr_show_all(pid, opts);
}
...@@ -233,7 +233,7 @@ int main(int argc, char *argv[]) ...@@ -233,7 +233,7 @@ int main(int argc, char *argv[])
int opt, idx; int opt, idx;
int action = -1; int action = -1;
static const char short_opts[] = "drskp:t:h"; static const char short_opts[] = "drskf:p:t:hc";
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "dump", no_argument, NULL, 'd' }, { "dump", no_argument, NULL, 'd' },
{ "restore", no_argument, NULL, 'r' }, { "restore", no_argument, NULL, 'r' },
...@@ -274,6 +274,13 @@ int main(int argc, char *argv[]) ...@@ -274,6 +274,13 @@ int main(int argc, char *argv[])
case 's': case 's':
action = opt; action = opt;
break; break;
case 'c':
opts.show_pages_content = true;
break;
case 'f':
opts.show_single_file = true;
opts.show_dump_file = optarg;
break;
case 'k': case 'k':
opts.final_state = CR_TASK_KILL; opts.final_state = CR_TASK_KILL;
break; break;
...@@ -302,6 +309,10 @@ int main(int argc, char *argv[]) ...@@ -302,6 +309,10 @@ int main(int argc, char *argv[])
usage: usage:
printk("\nUsage:\n"); printk("\nUsage:\n");
printk("\tcrtools ([--dump|-d]|[--show|-s]|[--restore|-r]) [-k] (-p|-t) pid\n\n"); printk("\t%s --dump|-d [-k] -p|-t pid\n", argv[0]);
printk("\t%s --restore|-r -p|-t pid\n", argv[0]);
printk("\t%s --show|-s [-c] (-p|-t pid)|(-f file)\n", argv[0]);
printk("\n");
return -1; return -1;
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "image.h" #include "image.h"
extern struct page_entry zero_page_entry; extern struct page_entry zero_page_entry;
extern void free_pstree(struct list_head *pstree_list);
#define CR_FD_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) #define CR_FD_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define CR_FD_PERM_DUMP (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) #define CR_FD_PERM_DUMP (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
...@@ -35,6 +36,9 @@ enum cr_task_final_state { ...@@ -35,6 +36,9 @@ enum cr_task_final_state {
struct cr_options { struct cr_options {
bool leader_only; bool leader_only;
enum cr_task_final_state final_state; enum cr_task_final_state final_state;
bool show_single_file;
bool show_pages_content;
char *show_dump_file;
}; };
/* file descriptors template */ /* file descriptors template */
......
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