diff --git a/TODO b/TODO index 2a3085eda..700e640c8 100644 --- a/TODO +++ b/TODO @@ -12,3 +12,10 @@ Some things which are to be done - 'crtools show' should support showing only a subset of resources dumped such as pipes/vma/ and etc... - add bash completion file + +Some notes on code +------------------ + +- need to handle out cr_fdset(s), they are getting used more frequently + than I initially thought, including the usage only of a few file descriptors + while the whole set is always allocated diff --git a/cr-dump.c b/cr-dump.c index 01ac69fa0..4e21c9e5e 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -67,7 +67,6 @@ static FILE *fopen_proc(char *fmt, char *mode, ...) } static char big_buffer[PATH_MAX]; -static struct parasite_ctl *parasite_ctl; static char loc_buf[PAGE_SIZE]; @@ -619,28 +618,14 @@ err: return ret; } -static int dump_task_core_seized(pid_t pid, struct cr_fdset *cr_fdset) +static int get_task_regs(pid_t pid, struct core_entry *core) { - struct core_entry *core = xzalloc(sizeof(*core)); user_fpregs_struct_t fpregs = {-1}; user_regs_struct_t regs = {-1}; - int fd_core = cr_fdset->desc[CR_FD_CORE].fd; - int ret = -1; - unsigned long brk; + int ret = -1; - pr_info("\n"); - pr_info("Dumping core (pid: %d)\n", pid); - pr_info("----------------------------------------\n"); - - if (!core) - goto err; - - lseek(fd_core, MAGIC_OFFSET, SEEK_SET); - - jerr(ptrace(PTRACE_GETREGS, pid, NULL, ®s), err_free); - jerr(ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs), err_free); - - pr_info("Dumping GP/FPU registers ... "); + jerr(ptrace(PTRACE_GETREGS, pid, NULL, ®s), err); + jerr(ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs), err); assign_reg(core->u.arch.gpregs, regs, r15); assign_reg(core->u.arch.gpregs, regs, r14); @@ -684,6 +669,33 @@ static int dump_task_core_seized(pid_t pid, struct cr_fdset *cr_fdset) assign_array(core->u.arch.fpregs, fpregs, padding); pr_info("OK\n"); + ret = 0; + +err: + return ret; +} + +static int dump_task_core_seized(pid_t pid, struct cr_fdset *cr_fdset) +{ + struct core_entry *core = xzalloc(sizeof(*core)); + int fd_core = cr_fdset->desc[CR_FD_CORE].fd; + int ret = -1; + unsigned long brk; + + pr_info("\n"); + pr_info("Dumping core (pid: %d)\n", pid); + pr_info("----------------------------------------\n"); + + if (!core) + goto err; + + lseek(fd_core, MAGIC_OFFSET, SEEK_SET); + + pr_info("Dumping GP/FPU registers ... "); + ret = get_task_regs(pid, core); + if (ret) + goto err_free; + pr_info("OK\n"); pr_info("Obtainting TLS ... "); ret = dump_task_tls(pid, core->u.arch.tls_array, ARRAY_SIZE(core->u.arch.tls_array)); @@ -907,6 +919,7 @@ static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset e.pid = item->pid; e.nr_children = item->nr_children; + e.nr_threads = item->nr_threads; write_ptr_safe(cr_fdset->desc[CR_FD_PSTREE].fd, &e, err); @@ -917,6 +930,14 @@ static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset &item->children[i], err); } pr_info("\n"); + + pr_info("Threads:\n"); + for (i = 0; i < item->nr_threads; i++) { + pr_info(" %d", item->threads[i]); + write_ptr_safe(cr_fdset->desc[CR_FD_PSTREE].fd, + &item->threads[i], err); + } + pr_info("\n"); } ret = 0; @@ -1056,6 +1077,58 @@ err_strno: goto err; } +static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset) +{ + struct core_entry *core = xzalloc(sizeof(*core)); + int fd_core = cr_fdset->desc[CR_FD_CORE].fd; + int ret = -1; + + pr_info("\n"); + pr_info("Dumping core for thread (pid: %d)\n", pid); + pr_info("----------------------------------------\n"); + + if (!core) + goto err; + + lseek(fd_core, MAGIC_OFFSET, SEEK_SET); + + 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 ... "); + ret = get_task_regs(pid, core); + if (ret) + goto err_free; + pr_info("OK\n"); + + ret = unseize_task(pid); + if (ret) { + pr_err("Can't unsieze thread (pid: %d)\n", pid); + goto err_free; + } + + pr_info("Dumping header ... "); + core->header.version = HEADER_VERSION; + core->header.arch = HEADER_ARCH_X86_64; + core->header.flags = 0; + + write_ptr_safe(fd_core, core, err_free); + + pr_info("OK\n"); + ret = 0; + +err_free: + free(core); +err: + pr_info("----------------------------------------\n"); + + return ret; +} + static int dump_one_task(pid_t pid, struct cr_fdset *cr_fdset) { LIST_HEAD(vma_area_list); @@ -1138,7 +1211,7 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts) LIST_HEAD(pstree_list); struct cr_fdset *cr_fdset = NULL; struct pstree_item *item; - int ret = -1; + int i, ret = -1; pr_info("========================================\n"); if (!opts->leader_only) @@ -1184,6 +1257,21 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts) close_cr_fdset(cr_fdset); free_cr_fdset(&cr_fdset); + if (item->nr_threads > 1) { + for (i = 0; i < item->nr_threads; i++) { + /* Leader is already dumped */ + if (item->pid == item->threads[i]) + continue; + cr_fdset = alloc_cr_fdset(item->threads[i]); + if (!cr_fdset) + goto err; + if (prep_cr_fdset_for_dump(cr_fdset, CR_FD_DESC_CORE)) + goto err; + if (dump_task_thread(item->threads[i], cr_fdset)) + goto err; + } + } + if (opts->leader_only) break; } diff --git a/include/crtools.h b/include/crtools.h index 83bcb6bf9..3667b9f70 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -58,7 +58,8 @@ struct cr_fdset { }; #define CR_FD_DESC_USE(type) ((1 << (type))) -#define CR_FD_DESC_ALL ((1 << CR_FD_MAX) - 1) +#define CR_FD_DESC_ALL (CR_FD_DESC_USE(CR_FD_MAX) - 1) +#define CR_FD_DESC_CORE CR_FD_DESC_USE(CR_FD_CORE) #define CR_FD_DESC_NOPSTREE (CR_FD_DESC_ALL & ~(CR_FD_DESC_USE(CR_FD_PSTREE))) #define CR_FD_DESC_NONE (0) diff --git a/include/image.h b/include/image.h index 7eca80161..6063e8fe9 100644 --- a/include/image.h +++ b/include/image.h @@ -36,7 +36,10 @@ struct shmem_entry { struct pstree_entry { u32 pid; u32 nr_children; + u32 nr_threads; + u32 children[0]; + u32 threads[0]; } __packed; struct pipe_entry {