summaryrefslogtreecommitdiff
path: root/src/mem/io-ptrace.c
blob: cf9a861a637b4511245ef610f1789142993ecff1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "io.h"
#include <stdio.h>
#include <err.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

static size_t
mem_io_ptrace_do(const struct mem_io *io, void *ptr, const size_t offset, const size_t size, size_t (*iofun)(void*, size_tsize_tFILE*))
{
   if (fseek(io->backing, offset, SEEK_SET) != 0) {
      warn("fseek(/proc/%u/mem, %zu)", io->pid, offset);
      return 0;
   }

   return iofun(ptr, 1, size, io->backing);
}

static size_t
mem_io_ptrace_write(const struct mem_io *io, const void *ptr, const size_t offset, const size_t size)
{
   clearerr(io->backing);
   const size_t ret = mem_io_ptrace_do(io, (void*)ptr, offset, size, (size_t(*)())fwrite);

   if (ferror(io->backing))
      warn("fwrite(/proc/%u/mem)", io->pid);

   return ret;
}

static size_t
mem_io_ptrace_read(const struct mem_io *io, void *ptr, const size_t offset, const size_t size)
{
   clearerr(io->backing);
   const size_t ret = mem_io_ptrace_do(io, ptr, offset, size, fread);

   if (ferror(io->backing))
      warn("fread(/proc/%u/mem)", io->pid);

   return ret;
}

static void
mem_io_ptrace_cleanup(struct mem_io *io)
{
   if (io->backing)
      fclose(io->backing);

   if (io->pid)
      ptrace(PTRACE_DETACH, io->pid, 10);
}

bool
mem_io_ptrace_init(struct mem_io *io, const pid_t pid)
{
   *io = (struct mem_io){
      .pid = pid,
      .read = mem_io_ptrace_read,
      .write = mem_io_ptrace_write,
      .cleanup = mem_io_ptrace_cleanup
   };

   if (ptrace(PTRACE_ATTACH, pid, NULLNULL) == -1L) {
      warn("ptrace(PTRACE_ATTACH, %u, NULL, NULL)", pid);
      goto fail;
   }

   {
      int status;
      if (waitpid(pid, &status, 0) == -1 || !WIFSTOPPED(status)) {
         warn("waitpid(%u) == %d", pid, status);
         goto fail;
      }
   }

   char path[128];
   snprintf(path, sizeof(path), "/proc/%u/mem", pid);
   if (!(io->backing = fopen(path, "w+b"))) {
      warn("fopen(%s)", path);
      goto fail;
   }

   return true;

fail:
   io->cleanup(io);
   return false;
}