diff --git a/cr-dump.c b/cr-dump.c index fed67c4c4..2edd59b00 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -128,6 +128,8 @@ void free_mappings(struct vm_area_list *vma_area_list) list_for_each_entry_safe(vma_area, p, &vma_area_list->h, list) { close_vma_file(vma_area); + if (!vma_area->file_borrowed) + free(vma_area->st); free(vma_area); } @@ -341,15 +343,14 @@ static int dump_task_rlims(int pid, struct cr_fdset *fds) return 0; } -static int dump_filemap(pid_t pid, VmaEntry *vma, int file_fd, +static int dump_filemap(pid_t pid, struct vma_area *vma_area, const struct cr_fdset *fdset) { struct fd_parms p = FD_PARMS_INIT; + VmaEntry *vma = &vma_area->vma; - if (fstat(file_fd, &p.stat) < 0) { - pr_perror("Can't stat file for vma"); - return -1; - } + BUG_ON(!vma_area->st); + p.stat = *vma_area->st; if ((vma->prot & PROT_WRITE) && vma_entry_is(vma, VMA_FILE_SHARED)) p.flags = O_RDWR; @@ -357,7 +358,7 @@ static int dump_filemap(pid_t pid, VmaEntry *vma, int file_fd, p.flags = O_RDONLY; vma->shmid = fd_id_generate_special(); - return dump_one_reg_file(file_fd, vma->shmid, &p); + return dump_one_reg_file(vma_area->vm_file_fd, vma->shmid, &p); } static int check_sysvipc_map_dump(pid_t pid, VmaEntry *vma) @@ -395,7 +396,7 @@ static int dump_task_mappings(pid_t pid, const struct vm_area_list *vma_area_lis ret = add_shmem_area(pid, vma); else if (vma_entry_is(vma, VMA_FILE_PRIVATE) || vma_entry_is(vma, VMA_FILE_SHARED)) - ret = dump_filemap(pid, vma, vma_area->vm_file_fd, cr_fdset); + ret = dump_filemap(pid, vma_area, cr_fdset); else if (vma_entry_is(vma, VMA_AREA_SOCKET)) ret = dump_socket_map(vma_area); else diff --git a/include/vma.h b/include/vma.h index 2bd484418..03994a6eb 100644 --- a/include/vma.h +++ b/include/vma.h @@ -27,6 +27,8 @@ struct vma_area { unsigned long premmaped_addr; bool file_borrowed; + + struct stat *st; }; extern int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list); diff --git a/proc_parse.c b/proc_parse.c index 55d7c7834..254fced63 100644 --- a/proc_parse.c +++ b/proc_parse.c @@ -351,16 +351,21 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file vma_area->vma.flags |= (prev->vma.flags & MAP_ANONYMOUS); vma_area->vma.status = prev->vma.status; vma_area->vma.shmid = prev->vma.shmid; + vma_area->st = prev->st; } else if (vma_area->vm_file_fd >= 0) { - struct stat st_buf; + struct stat *st_buf; - if (fstat(vma_area->vm_file_fd, &st_buf) < 0) { + st_buf = vma_area->st = xmalloc(sizeof(*st_buf)); + if (!st_buf) + goto err; + + if (fstat(vma_area->vm_file_fd, st_buf) < 0) { pr_perror("Failed fstat on %d's map %lu", pid, start); goto err; } - if (!S_ISREG(st_buf.st_mode) && - !(S_ISCHR(st_buf.st_mode) && st_buf.st_rdev == DEVZERO)) { + if (!S_ISREG(st_buf->st_mode) && + !(S_ISCHR(st_buf->st_mode) && st_buf->st_rdev == DEVZERO)) { pr_err("Can't handle non-regular mapping on %d's map %lu\n", pid, start); goto err; } @@ -369,12 +374,12 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file * /dev/zero stands for anon-shared mapping * otherwise it's some file mapping. */ - if (is_anon_shmem_map(st_buf.st_dev)) { + if (is_anon_shmem_map(st_buf->st_dev)) { if (!(vma_area->vma.flags & MAP_SHARED)) goto err_bogus_mapping; vma_area->vma.flags |= MAP_ANONYMOUS; vma_area->vma.status |= VMA_ANON_SHARED; - vma_area->vma.shmid = st_buf.st_ino; + vma_area->vma.shmid = st_buf->st_ino; if (!strcmp(file_path, "/SYSV")) { pr_info("path: %s\n", file_path);