PhpGlobalsFinder::getSymbolReader()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 6
c 1
b 1
f 0
nc 1
nop 2
dl 0
loc 10
rs 10
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\PhpProcessReader;
15
16
use PhpProfiler\Inspector\Settings\TargetPhpSettings\TargetPhpSettings;
17
use PhpProfiler\Inspector\Settings\TargetProcessSettings\TargetProcessSettings;
18
use PhpProfiler\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader;
19
use PhpProfiler\Lib\ByteStream\CDataByteReader;
20
use PhpProfiler\Lib\Elf\Parser\ElfParserException;
21
use PhpProfiler\Lib\Elf\Process\ProcessSymbolReaderException;
22
use PhpProfiler\Lib\Elf\Process\ProcessSymbolReaderInterface;
23
use PhpProfiler\Lib\Elf\Tls\TlsFinderException;
24
use PhpProfiler\Lib\PhpInternals\ZendTypeReader;
25
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderException;
26
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderInterface;
27
use PhpProfiler\Lib\Process\ProcessSpecifier;
28
use RuntimeException;
29
30
final class PhpGlobalsFinder
31
{
32
    public function __construct(
33
        private PhpSymbolReaderCreator $php_symbol_reader_creator,
34
        private IntegerByteSequenceReader $integer_reader,
35
        private MemoryReaderInterface $memory_reader
36
    ) {
37
    }
38
39
    /**
40
     * @throws MemoryReaderException
41
     * @throws ProcessSymbolReaderException
42
     * @throws TlsFinderException
43
     */
44
    public function findTsrmLsCache(
45
        ProcessSpecifier $process_specifier,
46
        TargetPhpSettings $target_php_settings
47
    ): ?int {
48
        $tsrm_lm_cache_cdata = $this->getSymbolReader(
49
            $process_specifier,
50
            $target_php_settings
51
        )->read('_tsrm_ls_cache');
52
        if (isset($tsrm_lm_cache_cdata)) {
53
            return $this->integer_reader->read64(
54
                new CDataByteReader($tsrm_lm_cache_cdata),
55
                0
56
            )->toInt();
57
        }
58
        return null;
59
    }
60
61
    /**
62
     * @throws MemoryReaderException
63
     * @throws ProcessSymbolReaderException
64
     * @throws TlsFinderException
65
     */
66
    public function getSymbolReader(
67
        ProcessSpecifier $process_specifier,
68
        TargetPhpSettings $target_php_settings
69
    ): ProcessSymbolReaderInterface {
70
        return $this->php_symbol_reader_creator->create(
71
            $process_specifier->pid,
72
            $target_php_settings->php_regex,
73
            $target_php_settings->libpthread_regex,
74
            $target_php_settings->php_path,
75
            $target_php_settings->libpthread_path
76
        );
77
    }
78
79
    /**
80
     * @throws ElfParserException
81
     * @throws MemoryReaderException
82
     * @throws ProcessSymbolReaderException
83
     * @throws TlsFinderException
84
     */
85
    public function findExecutorGlobals(
86
        ProcessSpecifier $process_specifier,
87
        TargetPhpSettings $target_php_settings
88
    ): int {
89
        $tsrm_ls_cache = $this->findTsrmLsCache($process_specifier, $target_php_settings);
90
        if (isset($tsrm_ls_cache)) {
91
            switch ($target_php_settings->php_version) {
92
                case ZendTypeReader::V70:
93
                case ZendTypeReader::V71:
94
                case ZendTypeReader::V72:
95
                case ZendTypeReader::V73:
96
                    $executor_globals_id_cdata = $this->getSymbolReader($process_specifier, $target_php_settings)
97
                        ->read('executor_globals_id');
98
                    if (is_null($executor_globals_id_cdata)) {
99
                        throw new RuntimeException('executor_globals_id not found');
100
                    }
101
                    $tsrm_ls_cache_dereferenced = $this->integer_reader->read64(
102
                        new CDataByteReader(
103
                            $this->memory_reader->read(
104
                                $process_specifier->pid,
105
                                $tsrm_ls_cache,
106
                                8
107
                            )
108
                        ),
109
                        0
110
                    )->toInt();
111
                    $executor_globals_id = $this->integer_reader->read32(
112
                        new CDataByteReader($executor_globals_id_cdata),
113
                        0
114
                    );
115
                    return $this->integer_reader->read64(
116
                        new CDataByteReader(
117
                            $this->memory_reader->read(
118
                                $process_specifier->pid,
119
                                $tsrm_ls_cache_dereferenced + ($executor_globals_id - 1) * 8,
120
                                8
121
                            )
122
                        ),
123
                        0
124
                    )->toInt();
125
126
                case ZendTypeReader::V74:
127
                case ZendTypeReader::V80:
128
                case ZendTypeReader::V81:
129
                    $executor_globals_offset_cdata = $this->getSymbolReader(
130
                        $process_specifier,
131
                        $target_php_settings
132
                    )->read('executor_globals_offset');
133
                    if (is_null($executor_globals_offset_cdata)) {
134
                        throw new RuntimeException('executor_globals_offset not found');
135
                    }
136
                    $executor_globals_offset = $this->integer_reader->read64(
137
                        new CDataByteReader($executor_globals_offset_cdata),
138
                        0
139
                    )->toInt();
140
                    return $tsrm_ls_cache + $executor_globals_offset;
141
                default:
142
                    throw new \LogicException('this should never happen');
143
            }
144
        }
145
        $executor_globals_address = $this->getSymbolReader($process_specifier, $target_php_settings)
146
            ->resolveAddress('executor_globals');
147
        if (is_null($executor_globals_address)) {
148
            throw new RuntimeException('executor globals not found');
149
        }
150
        return $executor_globals_address;
151
    }
152
153
    public function findModuleRegistry(
154
        ProcessSpecifier $process_specifier,
155
        TargetPhpSettings $target_php_settings
156
    ): ?int {
157
        $symbol_reader = $this->getSymbolReader(
158
            $process_specifier,
159
            $target_php_settings
160
        );
161
        $module_registry = $symbol_reader->resolveAddress('module_registry');
162
        return $module_registry;
163
    }
164
}
165