initial commit
[nyatools.git] / ptrace.d
blobaa0d467bec6797b73bdc4f13b475a929d9431b8e
1 module ptrace;
2 extern(C) nothrow @nogc private {
4 // Type of the REQUEST argument to `ptrace()`
5 enum PtraceRequest : int {
6 TRACEME = 0, // indicate that the process making this request should be traced; all signals received by this process can be intercepted by its parent, and its parent can use the other `ptrace' requests
7 PEEKTEXT = 1, // return the word in the process's text space at address ADDR
8 PEEKDATA = 2, // return the word in the process's data space at address ADDR
9 PEEKUSER = 3, // return the word in the process's user area at offset ADDR
10 POKETEXT = 4, // write the word DATA into the process's text space at address ADDR
11 POKEDATA = 5, // write the word DATA into the process's data space at address ADDR
12 POKEUSER = 6, // write the word DATA into the process's user area at offset ADDR
13 CONT = 7, // continue the process
14 KILL = 8, // kill the process
15 SINGLESTEP = 9, // single step the process. This is not supported on all machines
16 GETREGS = 12, // get all general purpose registers used by a processes. This is not supported on all machines
17 SETREGS = 13, // set all general purpose registers used by a processes. This is not supported on all machines
18 GETFPREGS = 14, // get all floating point registers used by a processes. This is not supported on all machines
19 SETFPREGS = 15, // set all floating point registers used by a processes. This is not supported on all machines
20 ATTACH = 16, // attach to a process that is already running
21 DETACH = 17, // detach from a process attached to with ATTACH
22 GETFPXREGS = 18, // get all extended floating point registers used by a processes. This is not supported on all machines
23 SETFPXREGS = 19, // set all extended floating point registers used by a processes. This is not supported on all machines
24 SYSCALL = 24, // continue and stop at the next (return from) syscall
25 SETOPTIONS = 0x4200, // set ptrace filter options
26 GETEVENTMSG = 0x4201, // get last ptrace message
27 GETSIGINFO = 0x4202, // get siginfo for process
28 SETSIGINFO = 0x4203, // set new siginfo for process
29 GETREGSET = 0x4204, // get register content
30 SETREGSET = 0x4205, // set register content
31 SEIZE = 0x4206, // like ATTACH, but do not force tracee to trap and do not affect signal or group stop state
32 INTERRUPT = 0x4207, // trap seized tracee
33 LISTEN = 0x4208, // wait for next group event
34 PEEKSIGINFO = 0x4209,
35 GETSIGMASK = 0x420a,
36 SETSIGMASK = 0x420b,
37 SECCOMP_GET_FILTER = 0x420c,
41 // flag for LISTEN
42 enum uint PTRACE_SEIZE_DEVEL = 0x80000000u;
44 // options set using SETOPTIONS
45 alias PtraceSetOptions = uint;
46 enum /*PtraceSetOptions*/ : uint {
47 PTRACE_O_TRACESYSGOOD = 0x00000001u,
48 PTRACE_O_TRACEFORK = 0x00000002u,
49 PTRACE_O_TRACEVFORK = 0x00000004u,
50 PTRACE_O_TRACECLONE = 0x00000008u,
51 PTRACE_O_TRACEEXEC = 0x00000010u,
52 PTRACE_O_TRACEVFORKDONE = 0x00000020u,
53 PTRACE_O_TRACEEXIT = 0x00000040u,
54 PTRACE_O_TRACESECCOMP = 0x00000080u,
55 PTRACE_O_EXITKILL = 0x00100000u,
56 PTRACE_O_SUSPEND_SECCOMP = 0x00200000u,
57 PTRACE_O_MASK = 0x003000ffu,
60 // wait extended result codes for the above trace options
61 enum PtraceEventCodes {
62 FORK = 1,
63 VFORK = 2,
64 CLONE = 3,
65 EXEC = 4,
66 VFORK_DONE = 5,
67 EXIT = 6,
68 SECCOMP = 7,
71 // arguments for PEEKSIGINFO
72 struct PtracePeekSigInfoArgs {
73 ulong off; // From which siginfo to start
74 uint flags; // Flags for peeksiginfo
75 int nr; // How many siginfos to take
78 enum uint PTRACE_PEEKSIGINFO_SHARED = 1u<<0; // read signals from a shared (process wide) queue
80 /* Perform process tracing functions. REQUEST is one of the values above, and determines the action to be taken.
81 * For all requests except TRACEME, PID specifies the process to be traced.
83 * PID and the other arguments described above for the various requests should
84 * appear (those that are used for the particular request) as:
85 * pid_t PID, void *ADDR, int DATA, void *ADDR2
86 * after REQUEST. */
87 extern(C) int ptrace (PtraceRequest request, ...) nothrow @nogc;
91 // ////////////////////////////////////////////////////////////////////////// //
92 public void attachToPid (uint pid) {
93 import core.sys.posix.sys.wait;
94 int status;
95 // attach, to the target application, which should cause a SIGSTOP
96 if (ptrace(PtraceRequest.ATTACH, pid, null, null) == -1) throw new Exception("attach failed");
97 // wait for the SIGSTOP to take place
98 if (waitpid(pid, &status, 0) == -1 || !WIFSTOPPED(status)) throw new Exception("error waiting target to stop");
102 // ////////////////////////////////////////////////////////////////////////// //
103 public void detachFromPid (uint pid) {
104 // addr is ignore under Linux, but should be 1 under FreeBSD in order to let the child process continue at what it had been interrupted
105 ptrace(PtraceRequest.DETACH, pid, 1, 0); // == 0
109 // ////////////////////////////////////////////////////////////////////////// //
110 // read 4 bytes; i should be already attached to the process
111 public uint procMemReadU32 (uint pid, uint addr) {
112 import core.stdc.errno;
113 errno = 0;
114 uint res = ptrace(PtraceRequest.PEEKDATA, pid, addr, null);
115 if (errno != 0) throw new Exception("reading error");
116 return res;
120 public void procMemRead (uint pid, ubyte[] buf, uint addr) {
121 import core.stdc.errno;
122 import core.stdc.string : memcpy;
123 errno = 0;
124 while (buf.length > 0) {
125 uint res = ptrace(PtraceRequest.PEEKDATA, pid, addr, null);
126 if (errno != 0) throw new Exception("reading error");
127 if (buf.length > 4) {
128 memcpy(buf.ptr, &res, 4);
129 buf = buf[4..$];
130 addr += 4;
131 } else {
132 memcpy(buf.ptr, &res, buf.length);
133 return;
139 // write 4 bytes; i should be already attached to the process
140 public void procMemWrite (uint pid, uint addr, uint val) {
141 if (ptrace(PtraceRequest.POKEDATA, pid, addr, val) != 0) throw new Exception("reading error");
146 import iv.vfs.io;
147 void main (string[] args) {
148 uint pid = 30329;
149 if (args.length > 1) {
150 import std.conv : to;
151 pid = to!uint(args[1]);
153 attachToPid(pid);
154 writeln("attached to ", pid);
156 import core.thread;
157 import core.time;
158 Thread.sleep(5.seconds);
160 detachFromPid(pid);