2011-09-23 12:00:45 +04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2011-12-19 21:05:02 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/vfs.h>
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/user.h>
|
|
|
|
#include <sys/wait.h>
|
2011-12-05 12:07:52 +04:00
|
|
|
#include <sys/resource.h>
|
2011-12-19 21:05:02 +04:00
|
|
|
#include <sys/wait.h>
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "types.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "util.h"
|
2011-12-19 18:52:50 +04:00
|
|
|
#include "log.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include "crtools.h"
|
|
|
|
|
|
|
|
void printk(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list params;
|
|
|
|
|
|
|
|
va_start(params, format);
|
2011-12-19 18:52:50 +04:00
|
|
|
vdprintf(get_logfd(), format, params);
|
2011-09-23 12:00:45 +04:00
|
|
|
va_end(params);
|
|
|
|
}
|
|
|
|
|
2011-10-26 10:10:19 +04:00
|
|
|
void hex_dump(void *addr, unsigned long len)
|
|
|
|
{
|
|
|
|
unsigned char *p = addr;
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
len = (len + 8) & ~7;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i += 8) {
|
|
|
|
printk("%08lx: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
|
|
p, p[i+0], p[i+1], p[i+2], p[i+3],
|
|
|
|
p[i+4], p[i+5], p[i+6], p[i+7]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
void printk_registers(user_regs_struct_t *regs)
|
|
|
|
{
|
|
|
|
printk("ip : %16lx cs : %16lx ds : %16lx\n"
|
|
|
|
"es : %16lx fs : %16lx gs : %16lx\n"
|
|
|
|
"sp : %16lx ss : %16lx flags : %16lx\n"
|
|
|
|
"ax : %16lx cx : %16lx dx : %16lx\n"
|
|
|
|
"si : %16lx di : %16lx bp : %16lx\n"
|
|
|
|
"bx : %16lx r8 : %16lx r9 : %16lx\n"
|
|
|
|
"r10 : %16lx r11 : %16lx r12 : %16lx\n"
|
|
|
|
"r13 : %16lx r14 : %16lx r15 : %16lx\n"
|
|
|
|
"orig_ax: %16lx fs_base: %16lx gs_base: %16lx\n\n",
|
|
|
|
regs->ip, regs->cs, regs->ds,
|
|
|
|
regs->es, regs->fs, regs->gs,
|
|
|
|
regs->sp, regs->ss, regs->flags,
|
|
|
|
regs->ax, regs->cx, regs->dx,
|
|
|
|
regs->si, regs->di, regs->bp,
|
|
|
|
regs->bx, regs->r8, regs->r9,
|
|
|
|
regs->r10, regs->r11, regs->r12,
|
|
|
|
regs->r13, regs->r14, regs->r15,
|
|
|
|
regs->orig_ax, regs->fs_base, regs->gs_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printk_siginfo(siginfo_t *siginfo)
|
|
|
|
{
|
|
|
|
printk("si_signo %d si_errno %d si_code %d\n",
|
|
|
|
siginfo->si_signo, siginfo->si_errno, siginfo->si_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printk_vma(struct vma_area *vma_area)
|
|
|
|
{
|
|
|
|
if (!vma_area)
|
|
|
|
return;
|
|
|
|
|
2011-11-22 00:13:04 +04:00
|
|
|
printk("s: %16lx e: %16lx l: %4liK p: %8x f: %8x pg: %8lx "
|
2011-11-23 13:55:04 +04:00
|
|
|
"vf: %s st: %s spc: %s\n",
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.start, vma_area->vma.end,
|
2011-11-24 15:07:03 +04:00
|
|
|
KBYTES(vma_area_len(vma_area)),
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.prot,
|
|
|
|
vma_area->vma.flags,
|
2011-09-23 16:17:24 +04:00
|
|
|
vma_area->vma.pgoff,
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vm_file_fd < 0 ? "n" : "y",
|
|
|
|
!vma_area->vma.status ? "--" :
|
|
|
|
((vma_area->vma.status & VMA_FILE_PRIVATE) ? "FP" :
|
|
|
|
((vma_area->vma.status & VMA_FILE_SHARED) ? "FS" :
|
|
|
|
((vma_area->vma.status & VMA_ANON_SHARED) ? "AS" :
|
|
|
|
((vma_area->vma.status & VMA_ANON_PRIVATE) ? "AP" : "--")))),
|
|
|
|
!vma_area->vma.status ? "--" :
|
|
|
|
((vma_area->vma.status & VMA_AREA_STACK) ? "stack" :
|
2011-10-12 13:33:02 +04:00
|
|
|
((vma_area->vma.status & VMA_AREA_HEAP) ? "heap" :
|
|
|
|
((vma_area->vma.status & VMA_AREA_VSYSCALL) ? "vsyscall" :
|
|
|
|
((vma_area->vma.status & VMA_AREA_VDSO) ? "vdso" : "n")))));
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-09-27 18:28:09 +04:00
|
|
|
int close_safe(int *fd)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if (*fd > -1) {
|
|
|
|
ret = close(*fd);
|
|
|
|
if (!ret)
|
|
|
|
*fd = -1;
|
|
|
|
else
|
|
|
|
pr_perror("Unable to close fd: %d\n", *fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
int reopen_fd_as(int new_fd, int old_fd)
|
|
|
|
{
|
|
|
|
if (old_fd != new_fd) {
|
|
|
|
int tmp = dup2(old_fd, new_fd);
|
2011-09-27 18:39:56 +04:00
|
|
|
if (tmp < 0) {
|
|
|
|
pr_perror("Dup on %d -> %d failed\n", old_fd, new_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
return tmp;
|
2011-09-27 18:39:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Just to have error message if failed */
|
|
|
|
close_safe(&old_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-12-26 21:47:00 +04:00
|
|
|
return 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-10-26 22:48:10 +04:00
|
|
|
int parse_maps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area = NULL;
|
|
|
|
u64 start, end, pgoff;
|
|
|
|
char map_files_path[64];
|
2011-11-15 11:34:11 +04:00
|
|
|
char big_buffer[1024];
|
2011-09-23 12:00:45 +04:00
|
|
|
char maps_path[64];
|
|
|
|
unsigned long ino;
|
|
|
|
char r,w,x,s;
|
|
|
|
int dev_maj, dev_min;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
DIR *map_files_dir = NULL;
|
|
|
|
FILE *maps = NULL;
|
|
|
|
|
|
|
|
snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps", pid);
|
|
|
|
maps = fopen(maps_path, "r");
|
|
|
|
if (!maps) {
|
|
|
|
pr_perror("Can't open: %s\n", maps_path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(map_files_path, sizeof(map_files_path),
|
|
|
|
"/proc/%d/map_files", pid);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It might be a problem in kernel, either
|
|
|
|
* I'm debugging it on old kernel ;)
|
|
|
|
*/
|
|
|
|
map_files_dir = opendir(map_files_path);
|
2011-10-26 22:48:10 +04:00
|
|
|
if (use_map_files && !map_files_dir) {
|
2011-10-13 16:07:34 +04:00
|
|
|
pr_err("Can't open %s, old kernel?\n",
|
|
|
|
map_files_path);
|
|
|
|
goto err;
|
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
while (fgets(big_buffer, sizeof(big_buffer), maps)) {
|
|
|
|
char vma_file_path[16+16+2];
|
|
|
|
struct stat st_buf;
|
2011-10-13 16:07:34 +04:00
|
|
|
int num;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-13 16:07:34 +04:00
|
|
|
num = sscanf(big_buffer, "%lx-%lx %c%c%c%c %lx %02x:%02x %lu",
|
2011-09-23 12:00:45 +04:00
|
|
|
&start, &end, &r, &w, &x, &s, &pgoff, &dev_maj,
|
|
|
|
&dev_min, &ino);
|
2011-10-13 16:07:34 +04:00
|
|
|
if (num != 10) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't parse: %s", big_buffer);
|
2011-10-13 16:07:34 +04:00
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
vma_area = alloc_vma_area();
|
|
|
|
if (!vma_area)
|
2011-10-13 16:07:34 +04:00
|
|
|
goto err;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
/* Figure out if it's file mapping */
|
|
|
|
snprintf(vma_file_path, sizeof(vma_file_path), "%lx-%lx", start, end);
|
|
|
|
|
|
|
|
if (map_files_dir) {
|
|
|
|
/*
|
|
|
|
* Note that we "open" it in dumper process space
|
|
|
|
* so later we might refer to it via /proc/self/fd/vm_file_fd
|
|
|
|
* if needed.
|
|
|
|
*/
|
|
|
|
vma_area->vm_file_fd = openat(dirfd(map_files_dir),
|
|
|
|
vma_file_path, O_RDONLY);
|
|
|
|
if (vma_area->vm_file_fd < 0) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
pr_perror("Failed opening %s/%s\n",
|
|
|
|
map_files_path,
|
|
|
|
vma_file_path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vma_area->vma.start = start;
|
|
|
|
vma_area->vma.end = end;
|
|
|
|
vma_area->vma.pgoff = pgoff;
|
|
|
|
vma_area->vma.prot = PROT_NONE;
|
|
|
|
|
|
|
|
if (r == 'r')
|
|
|
|
vma_area->vma.prot |= PROT_READ;
|
|
|
|
if (w == 'w')
|
|
|
|
vma_area->vma.prot |= PROT_WRITE;
|
|
|
|
if (x == 'x')
|
|
|
|
vma_area->vma.prot |= PROT_EXEC;
|
|
|
|
|
|
|
|
if (s == 's')
|
|
|
|
vma_area->vma.flags = MAP_SHARED;
|
|
|
|
else if (s == 'p')
|
|
|
|
vma_area->vma.flags = MAP_PRIVATE;
|
|
|
|
|
2011-11-08 13:54:01 +04:00
|
|
|
if (strstr(big_buffer, "[stack]")) {
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_STACK;
|
2011-11-30 20:14:20 +03:00
|
|
|
vma_area->vma.flags |= MAP_GROWSDOWN;
|
2011-11-08 13:54:01 +04:00
|
|
|
} else if (strstr(big_buffer, "[vsyscall]")) {
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_VSYSCALL;
|
2011-11-08 13:54:01 +04:00
|
|
|
} else if (strstr(big_buffer, "[vdso]")) {
|
2011-11-29 16:39:48 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
|
2011-11-08 13:54:01 +04:00
|
|
|
} else if (strstr(big_buffer, "[heap]")) {
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_HEAP;
|
2011-11-08 13:54:01 +04:00
|
|
|
} else {
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.status = VMA_AREA_REGULAR;
|
2011-11-08 13:54:01 +04:00
|
|
|
}
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Some mapping hints for restore, we save this on
|
|
|
|
* disk and restore might need to analyze it.
|
|
|
|
*/
|
|
|
|
if (vma_area->vm_file_fd >= 0) {
|
|
|
|
|
|
|
|
if (fstat(vma_area->vm_file_fd, &st_buf) < 0) {
|
|
|
|
pr_perror("Failed fstat on %s%s\n",
|
|
|
|
map_files_path,
|
|
|
|
vma_file_path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!S_ISREG(st_buf.st_mode)) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't handle non-regular "
|
|
|
|
"mapping on %s%s\n",
|
|
|
|
map_files_path,
|
|
|
|
vma_file_path);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* /dev/zero stands for anon-shared mapping
|
|
|
|
* otherwise it's some file mapping.
|
|
|
|
*/
|
|
|
|
if (MAJOR(st_buf.st_dev) == 0) {
|
|
|
|
if (!(vma_area->vma.flags & MAP_SHARED))
|
|
|
|
goto err_bogus_mapping;
|
2011-11-08 12:19:43 +04:00
|
|
|
vma_area->vma.flags |= MAP_ANONYMOUS;
|
2011-09-23 12:00:45 +04:00
|
|
|
vma_area->vma.status |= VMA_ANON_SHARED;
|
|
|
|
vma_area->shmid = st_buf.st_ino;
|
|
|
|
} else {
|
|
|
|
if (vma_area->vma.flags & MAP_PRIVATE)
|
|
|
|
vma_area->vma.status |= VMA_FILE_PRIVATE;
|
|
|
|
else
|
|
|
|
vma_area->vma.status |= VMA_FILE_SHARED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No file but mapping -- anonymous one.
|
|
|
|
*/
|
|
|
|
if (vma_area->vma.flags & MAP_SHARED)
|
|
|
|
goto err_bogus_mapping;
|
2011-11-08 00:39:21 +04:00
|
|
|
|
|
|
|
vma_area->vma.flags |= MAP_ANONYMOUS;
|
|
|
|
vma_area->vma.status |= VMA_ANON_PRIVATE;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
list_add_tail(&vma_area->list, vma_area_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
vma_area = NULL;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (maps)
|
|
|
|
fclose(maps);
|
|
|
|
|
|
|
|
if (map_files_dir)
|
|
|
|
closedir(map_files_dir);
|
|
|
|
|
|
|
|
xfree(vma_area);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err_bogus_mapping:
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Bogus mapping %lx-%lx\n",
|
|
|
|
vma_area->vma.start,
|
|
|
|
vma_area->vma.end);
|
2011-09-23 12:00:45 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2011-10-24 13:43:21 +04:00
|
|
|
|
|
|
|
DIR *opendir_proc(char *fmt, ...)
|
|
|
|
{
|
2011-11-15 11:29:33 +04:00
|
|
|
DIR *dir;
|
2011-10-24 13:43:21 +04:00
|
|
|
char path[128];
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
sprintf(path, "/proc/");
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(path + 6, sizeof(path) - 6, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2011-11-15 11:29:33 +04:00
|
|
|
dir = opendir(path);
|
|
|
|
if (!dir)
|
|
|
|
pr_perror("Can't open %s\n", path);
|
|
|
|
return dir;
|
2011-10-24 13:43:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fopen_proc(char *fmt, char *mode, ...)
|
|
|
|
{
|
2011-11-15 11:29:33 +04:00
|
|
|
FILE *file;
|
2011-10-24 13:43:21 +04:00
|
|
|
char fname[128];
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
sprintf(fname, "/proc/");
|
|
|
|
va_start(args, mode);
|
|
|
|
vsnprintf(fname + 6, sizeof(fname) - 6, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2011-11-15 11:29:33 +04:00
|
|
|
file = fopen(fname, mode);
|
|
|
|
if (!file)
|
|
|
|
pr_perror("Can't open %s\n", fname);
|
|
|
|
return file;
|
2011-10-24 13:43:21 +04:00
|
|
|
}
|
|
|
|
|
2011-12-25 17:04:02 +04:00
|
|
|
FILE *fopen_fmt(char *fmt, char *mode, ...)
|
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
char fname[128];
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, mode);
|
|
|
|
vsnprintf(fname, sizeof(fname), fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
file = fopen(fname, mode);
|
|
|
|
if (!file)
|
|
|
|
pr_perror("Can't open %s\n", fname);
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2011-10-24 13:51:41 +04:00
|
|
|
int open_fmt(char *fmt, int mode, ...)
|
2011-10-24 13:43:21 +04:00
|
|
|
{
|
2011-11-15 11:29:33 +04:00
|
|
|
int fd;
|
2011-10-24 13:43:21 +04:00
|
|
|
char fname[128];
|
2011-10-24 13:51:41 +04:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, mode);
|
|
|
|
vsnprintf(fname, sizeof(fname), fmt, args);
|
|
|
|
va_end(args);
|
2011-10-24 13:43:21 +04:00
|
|
|
|
2011-11-15 11:29:33 +04:00
|
|
|
fd = open(fname, mode);
|
|
|
|
if (fd < 0)
|
|
|
|
pr_perror("Can't open %s\n", fname);
|
|
|
|
return fd;
|
2011-10-24 13:43:21 +04:00
|
|
|
}
|