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
37 SECCOMP_GET_FILTER
= 0x420c,
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
{
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
87 extern(C
) int ptrace (PtraceRequest request
, ...) nothrow @nogc;
91 // ////////////////////////////////////////////////////////////////////////// //
92 public void attachToPid (uint pid
) {
93 import core
.sys
.posix
.sys
.wait;
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
;
114 uint res
= ptrace(PtraceRequest
.PEEKDATA
, pid
, addr
, null);
115 if (errno
!= 0) throw new Exception("reading error");
120 public void procMemRead (uint pid
, ubyte[] buf
, uint addr
) {
121 import core
.stdc
.errno
;
122 import core
.stdc
.string
: memcpy
;
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);
132 memcpy(buf
.ptr
, &res
, buf
.length
);
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");
147 void main (string[] args) {
149 if (args.length > 1) {
150 import std.conv : to;
151 pid = to!uint(args[1]);
154 writeln("attached to ", pid);
158 Thread.sleep(5.seconds);