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"
|
|
|
|
|
|
|
|
#include "crtools.h"
|
|
|
|
|
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) {
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_msg("%p: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
2012-01-31 17:17:19 +04:00
|
|
|
&p[i], p[i+0], p[i+1], p[i+2], p[i+3],
|
2011-10-26 10:10:19 +04:00
|
|
|
p[i+4], p[i+5], p[i+6], p[i+7]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-01 18:52:42 +04:00
|
|
|
void pr_info_siginfo(siginfo_t *siginfo)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_info("si_signo %d si_errno %d si_code %d\n",
|
|
|
|
siginfo->si_signo, siginfo->si_errno, siginfo->si_code);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2012-03-01 18:52:42 +04:00
|
|
|
void pr_info_vma(struct vma_area *vma_area)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
if (!vma_area)
|
|
|
|
return;
|
|
|
|
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_info("s: %16lx e: %16lx l: %4liK p: %8x f: %8x pg: %8lx "
|
|
|
|
"vf: %s st: %s spc: %s\n",
|
|
|
|
vma_area->vma.start, vma_area->vma.end,
|
|
|
|
KBYTES(vma_area_len(vma_area)),
|
|
|
|
vma_area->vma.prot,
|
|
|
|
vma_area->vma.flags,
|
|
|
|
vma_area->vma.pgoff,
|
|
|
|
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" :
|
|
|
|
((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
|
2012-02-01 02:08:04 +04:00
|
|
|
pr_perror("Unable to close fd %d", *fd);
|
2011-09-27 18:28:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-13 13:15:57 +04:00
|
|
|
int reopen_fd_as_safe(int new_fd, int old_fd, bool allow_reuse_fd)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2012-01-13 13:15:57 +04:00
|
|
|
int tmp;
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
if (old_fd != new_fd) {
|
2012-01-13 13:15:57 +04:00
|
|
|
|
|
|
|
if (!allow_reuse_fd) {
|
|
|
|
if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) {
|
|
|
|
if (new_fd < 3) {
|
|
|
|
/*
|
2012-02-01 02:08:04 +04:00
|
|
|
* Standard descriptors.
|
2012-01-13 13:15:57 +04:00
|
|
|
*/
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_warn("fd %d already in use\n", new_fd);
|
2012-01-13 13:15:57 +04:00
|
|
|
} else {
|
2012-02-01 02:08:04 +04:00
|
|
|
pr_err("fd %d already in use\n", new_fd);
|
2012-01-13 13:15:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-01-10 16:41:00 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = dup2(old_fd, new_fd);
|
2011-09-27 18:39:56 +04:00
|
|
|
if (tmp < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Dup %d -> %d failed", 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-12-26 21:48:00 +04:00
|
|
|
int move_img_fd(int *img_fd, int want_fd)
|
|
|
|
{
|
|
|
|
if (*img_fd == want_fd) {
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
tmp = dup(*img_fd);
|
|
|
|
if (tmp < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't dup file");
|
2011-12-26 21:48:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-01-10 16:41:00 +04:00
|
|
|
close(*img_fd);
|
|
|
|
|
2011-12-26 21:48:00 +04:00
|
|
|
*img_fd = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-16 00:51:26 +04:00
|
|
|
int get_image_path(char *path, int size, const char *fmt, int pid)
|
|
|
|
{
|
2012-01-16 00:52:21 +04:00
|
|
|
int len;
|
2012-01-16 00:51:26 +04:00
|
|
|
|
2012-01-16 00:52:21 +04:00
|
|
|
len = snprintf(path, size, "%s/", image_dir);
|
|
|
|
len += snprintf(path + len, size - len, fmt, pid);
|
|
|
|
if (len > size) {
|
|
|
|
pr_err("Image path buffer overflow %d/%d\n", size, len);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-01-16 00:51:26 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-29 19:56:34 +04:00
|
|
|
int open_image_ro_nocheck(const char *fmt, int pid)
|
2011-10-24 13:43:21 +04:00
|
|
|
{
|
2011-12-29 19:56:34 +04:00
|
|
|
char path[PATH_MAX];
|
|
|
|
int tmp;
|
2011-10-24 13:51:41 +04:00
|
|
|
|
2012-01-16 00:52:21 +04:00
|
|
|
tmp = get_image_path(path, sizeof(path), fmt, pid);
|
|
|
|
if (tmp == 0)
|
|
|
|
tmp = open(path, O_RDONLY);
|
2011-12-29 19:56:34 +04:00
|
|
|
if (tmp < 0)
|
2012-03-01 18:52:42 +04:00
|
|
|
pr_warn("Can't open image %s for %d: %m\n", fmt, pid);
|
2011-12-29 19:56:34 +04:00
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_image_ro(int type, int pid)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
u32 magic = 0;
|
2011-10-24 13:43:21 +04:00
|
|
|
|
2011-12-29 19:56:34 +04:00
|
|
|
fd = open_image_ro_nocheck(fdset_template[type].fmt, pid);
|
2011-11-15 11:29:33 +04:00
|
|
|
if (fd < 0)
|
2011-12-29 19:56:34 +04:00
|
|
|
return fd;
|
|
|
|
|
|
|
|
read(fd, &magic, sizeof(magic));
|
|
|
|
if (magic != fdset_template[type].magic) {
|
|
|
|
pr_err("Magic mismatch for %d of %d\n", type, pid);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-11-15 11:29:33 +04:00
|
|
|
return fd;
|
2011-10-24 13:43:21 +04:00
|
|
|
}
|
2012-01-12 23:50:45 +04:00
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
static pid_t open_proc_pid = 0;
|
|
|
|
static int open_proc_fd = -1;
|
|
|
|
|
|
|
|
int close_pid_proc(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (open_proc_fd >= 0)
|
|
|
|
ret = close(open_proc_fd);
|
|
|
|
|
|
|
|
open_proc_fd = -1;
|
|
|
|
open_proc_pid = 0;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int open_pid_proc(pid_t pid)
|
2012-01-12 23:50:45 +04:00
|
|
|
{
|
|
|
|
char path[18];
|
|
|
|
int fd;
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
if (pid == open_proc_pid)
|
|
|
|
return open_proc_fd;
|
|
|
|
|
|
|
|
close_pid_proc();
|
2012-01-12 23:50:45 +04:00
|
|
|
sprintf(path, "/proc/%d", pid);
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
if (fd < 0)
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't open %s", path);
|
2012-02-17 01:39:36 +04:00
|
|
|
else {
|
|
|
|
open_proc_fd = fd;
|
|
|
|
open_proc_pid = pid;
|
|
|
|
}
|
|
|
|
|
2012-01-12 23:50:45 +04:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
int do_open_proc(pid_t pid, int flags, const char *fmt, ...)
|
2012-01-12 23:50:45 +04:00
|
|
|
{
|
2012-02-17 01:39:35 +04:00
|
|
|
char path[128];
|
|
|
|
va_list args;
|
2012-02-17 01:39:36 +04:00
|
|
|
int dirfd = open_pid_proc(pid);
|
|
|
|
|
|
|
|
if (dirfd < 0)
|
|
|
|
return -1;
|
2012-01-12 23:50:45 +04:00
|
|
|
|
2012-02-17 01:39:35 +04:00
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(path, sizeof(path), fmt, args);
|
|
|
|
va_end(args);
|
2012-01-12 23:50:45 +04:00
|
|
|
|
2012-02-17 01:39:35 +04:00
|
|
|
return openat(dirfd, path, flags);
|
2012-01-12 23:50:45 +04:00
|
|
|
}
|