Passed
Pull Request — master (#46)
by Shinji
01:44
created

ProcessStopper::stop()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 10
c 1
b 0
f 1
nc 3
nop 1
dl 0
loc 19
rs 9.9332
1
<?php
2
3
/**
4
 * This file is part of the sj-i/php-profiler package.
5
 *
6
 * (c) sji <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace PhpProfiler\Lib\Process\ProcessStopper;
15
16
use FFI\CInteger;
17
18
final class ProcessStopper
19
{
20
    private \FFI $ffi;
21
22
    private const PTRACE_ATTACH = 16;
23
    private const PTRACE_DETACH = 17;
24
25
    public function __construct()
26
    {
27
        $this->ffi = \FFI::cdef('
28
           struct user_regs_struct {
29
               unsigned long r15;
30
               unsigned long r14;
31
               unsigned long r13;
32
               unsigned long r12;
33
               unsigned long bp;
34
               unsigned long bx;
35
               unsigned long r11;
36
               unsigned long r10;
37
               unsigned long r9;
38
               unsigned long r8;
39
               unsigned long ax;
40
               unsigned long cx;
41
               unsigned long dx;
42
               unsigned long si;
43
               unsigned long di;
44
               unsigned long orig_ax;
45
               unsigned long ip;
46
               unsigned long cs;
47
               unsigned long flags;
48
               unsigned long sp;
49
               unsigned long ss;
50
               unsigned long fs_base;
51
               unsigned long gs_base;
52
               unsigned long ds;
53
               unsigned long es;
54
               unsigned long fs;
55
               unsigned long gs;
56
           };
57
           typedef int pid_t;
58
           enum __ptrace_request
59
           {
60
               PTRACE_TRACEME = 0,
61
               PTRACE_PEEKTEXT = 1,
62
               PTRACE_PEEKDATA = 2,
63
               PTRACE_PEEKUSER = 3,
64
               PTRACE_POKETEXT = 4,
65
               PTRACE_POKEDATA = 5,
66
               PTRACE_POKEUSER = 6,
67
               PTRACE_CONT = 7,
68
               PTRACE_KILL = 8,
69
               PTRACE_SINGLESTEP = 9,
70
               PTRACE_GETREGS = 12,
71
               PTRACE_SETREGS = 13,
72
               PTRACE_GETFPREGS = 14,
73
               PTRACE_SETFPREGS = 15,
74
               PTRACE_ATTACH = 16,
75
               PTRACE_DETACH = 17,
76
               PTRACE_GETFPXREGS = 18,
77
               PTRACE_SETFPXREGS = 19,
78
               PTRACE_SYSCALL = 24,
79
               PTRACE_SETOPTIONS = 0x4200,
80
               PTRACE_GETEVENTMSG = 0x4201,
81
               PTRACE_GETSIGINFO = 0x4202,
82
               PTRACE_SETSIGINFO = 0x4203
83
           };
84
           long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
85
           int errno;
86
       ', 'libc.so.6');
87
    }
88
89
    public function stop(int $pid): bool
90
    {
91
        /** @var CInteger $zero */
92
        $zero = $this->ffi->new('long');
93
        $zero->cdata = 0;
94
        $null = \FFI::cast('void *', $zero);
95
96
        /** @var \FFI\Libc\ptrace_ffi $this->ffi */
97
        $attach = $this->ffi->ptrace(self::PTRACE_ATTACH, $pid, $null, $null);
0 ignored issues
show
Bug introduced by
The method ptrace() does not exist on FFI. It seems like you code against a sub-type of FFI such as FFI\Libc\ptrace_ffi. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

97
        /** @scrutinizer ignore-call */ 
98
        $attach = $this->ffi->ptrace(self::PTRACE_ATTACH, $pid, $null, $null);
Loading history...
98
99
        if ($attach === -1) {
100
            /** @var int $errno */
101
            $errno = $this->ffi->errno;
102
            if ($errno) {
103
                return false;
104
            }
105
        }
106
        pcntl_waitpid($pid, $status, WUNTRACED);
107
        return true;
108
    }
109
110
    public function resume(int $pid): void
111
    {
112
        /** @var CInteger $zero */
113
        $zero = $this->ffi->new('long');
114
        $zero->cdata = 0;
115
        $null = \FFI::cast('void *', $zero);
116
117
        /** @var \FFI\Libc\ptrace_ffi $this->ffi */
118
        $detach = $this->ffi->ptrace(self::PTRACE_DETACH, $pid, $null, $null);
119
        if ($detach === -1) {
120
            /** @var int $errno */
121
            $errno = $this->ffi->errno;
122
            if ($errno) {
123
                return;
124
            }
125
        }
126
    }
127
}
128