X64RegisterReader::attachAndReadOne()   B
last analyzed

Complexity

Conditions 7
Paths 15

Size

Total Lines 47
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 31
c 1
b 0
f 0
nc 15
nop 2
dl 0
loc 47
rs 8.4906
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\RegisterReader;
15
16
use FFI\CInteger;
17
use PhpProfiler\Lib\Libc\Errno\Errno;
18
use PhpProfiler\Lib\Libc\Sys\Ptrace\PtraceRequest;
19
use PhpProfiler\Lib\Libc\Sys\Ptrace\PtraceX64;
20
21
final class X64RegisterReader
22
{
23
    /** @var int */
24
    public const R15 = 0 * 8;
25
26
    /** @var int */
27
    public const R14 = 1 * 8;
28
29
    /** @var int */
30
    public const R13 = 2 * 8;
31
32
    /** @var int */
33
    public const R12 = 3 * 8;
34
35
    /** @var int */
36
    public const BP = 4 * 8;
37
38
    /** @var int */
39
    public const BX = 5 * 8;
40
41
    /** @var int */
42
    public const R11 = 6 * 8;
43
44
    /** @var int */
45
    public const R10 = 7 * 8;
46
47
    /** @var int */
48
    public const R9 = 8 * 8;
49
50
    /** @var int */
51
    public const R8 = 9 * 8;
52
53
    /** @var int */
54
    public const AX = 10 * 8;
55
56
    /** @var int */
57
    public const CX = 11 * 8;
58
59
    /** @var int */
60
    public const DX = 12 * 8;
61
62
    /** @var int */
63
    public const SI = 13 * 8;
64
65
    /** @var int */
66
    public const DI = 14 * 8;
67
68
    /** @var int */
69
    public const ORIG_AX = 15 * 8;
70
71
    /** @var int */
72
    public const IP = 16 * 8;
73
74
    /** @var int */
75
    public const CS = 17 * 8;
76
77
    /** @var int */
78
    public const FLAGS = 18 * 8;
79
80
    /** @var int */
81
    public const SP = 19 * 8;
82
83
    /** @var int */
84
    public const SS = 20 * 8;
85
86
    /** @var int */
87
    public const FS_BASE = 21 * 8;
88
89
    /** @var int */
90
    public const GS_BASE = 22 * 8;
91
92
    /** @var int */
93
    public const DS = 23 * 8;
94
95
    /** @var int */
96
    public const ES = 24 * 8;
97
98
    /** @var int */
99
    public const FS = 25 * 8;
100
101
    /** @var int */
102
    public const GS = 26 * 8;
103
104
    /** @var int[] */
105
    public const ALL_REGISTERS = [
106
        self::R15,
107
        self::R14,
108
        self::R13,
109
        self::R12,
110
        self::BP,
111
        self::BX,
112
        self::R11,
113
        self::R10,
114
        self::R9,
115
        self::R8,
116
        self::AX,
117
        self::CX,
118
        self::DX,
119
        self::SI,
120
        self::DI,
121
        self::ORIG_AX,
122
        self::IP,
123
        self::CS,
124
        self::FLAGS,
125
        self::SP,
126
        self::SS,
127
        self::FS_BASE,
128
        self::GS_BASE,
129
        self::DS,
130
        self::ES,
131
        self::FS,
132
        self::GS,
133
    ];
134
135
    public function __construct(
136
        private PtraceX64 $ptrace,
137
        private Errno $errno,
138
    ) {
139
    }
140
141
    /**
142
     * @param value-of<X64RegisterReader::ALL_REGISTERS> $register
0 ignored issues
show
Documentation Bug introduced by
The doc comment value-of<X64RegisterReader::ALL_REGISTERS> at position 0 could not be parsed: Unknown type name 'value-of' at position 0 in value-of<X64RegisterReader::ALL_REGISTERS>.
Loading history...
143
     * @throws RegisterReaderException
144
     */
145
    public function attachAndReadOne(int $pid, int $register): int
146
    {
147
        $target_offset = \FFI::new('long');
148
        /** @var \FFI\CInteger $target_offset */
149
        $target_offset->cdata = $register;
150
151
        $attach = $this->ptrace->ptrace(
152
            PtraceRequest::PTRACE_ATTACH(),
153
            $pid,
154
            null,
155
            null
156
        );
157
        if ($attach === -1) {
158
            $errno = $this->errno->get();
159
            if ($errno) {
160
                throw new RegisterReaderException("failed to attach process errno={$errno}", $errno);
161
            }
162
        }
163
        pcntl_waitpid($pid, $status, \WUNTRACED);
164
165
        $fs = $this->ptrace->ptrace(
166
            PtraceRequest::PTRACE_PEEKUSER(),
167
            $pid,
168
            \FFI::cast('void *', $target_offset),
169
            null
170
        );
171
        if ($fs === -1) {
172
            $errno = $this->errno->get();
173
            if ($errno) {
174
                throw new RegisterReaderException("failed to read register errno={$errno}", $errno);
175
            }
176
        }
177
178
        $detach = $this->ptrace->ptrace(
179
            PtraceRequest::PTRACE_DETACH(),
180
            $pid,
181
            null,
182
            null
183
        );
184
        if ($detach === -1) {
185
            $errno = $this->errno->get();
186
            if ($errno) {
187
                throw new RegisterReaderException("failed to detach process errno={$errno}", $errno);
188
            }
189
        }
190
191
        return $fs;
192
    }
193
}
194