ProcessModuleSymbolReader::read()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
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\Elf\Process;
15
16
use FFI\CData;
17
use PhpProfiler\Lib\Elf\SymbolResolver\Elf64AllSymbolResolver;
18
use PhpProfiler\Lib\Elf\SymbolResolver\Elf64SymbolResolver;
19
use PhpProfiler\Lib\Process\MemoryMap\ProcessModuleMemoryMap;
20
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderInterface;
21
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderException;
22
23
use function is_null;
24
25
final class ProcessModuleSymbolReader implements ProcessSymbolReaderInterface
26
{
27
    private int $base_address;
28
29
    public function __construct(
30
        private int $pid,
31
        private Elf64SymbolResolver $symbol_resolver,
32
        ProcessModuleMemoryMap $module_memory_map,
33
        private MemoryReaderInterface $memory_reader,
34
        private ?int $tls_block_address
35
    ) {
36
        $this->base_address = $module_memory_map->getBaseAddress();
37
    }
38
39
    /**
40
     * @return \FFI\CArray<int>|null
41
     * @throws MemoryReaderException
42
     * @throws ProcessSymbolReaderException
43
     */
44
    public function read(string $symbol_name): ?CData
45
    {
46
        $address_and_size = $this->resolveAddressAndSize($symbol_name);
47
        if ($address_and_size === null) {
48
            return null;
49
        }
50
        [$address, $size] = $address_and_size;
51
        return $this->memory_reader->read($this->pid, $address, $size);
52
    }
53
54
    /**
55
     * @throws ProcessSymbolReaderException
56
     */
57
    public function resolveAddress(string $symbol_name): ?int
58
    {
59
        $address_and_size = $this->resolveAddressAndSize($symbol_name);
60
        if ($address_and_size === null) {
61
            return null;
62
        }
63
        [$address,] = $address_and_size;
64
        return $address;
65
    }
66
67
68
    /**
69
     * @return array{int, int}|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{int, int}|null at position 2 could not be parsed: Expected ':' at position 2, but found 'int'.
Loading history...
70
     * @throws ProcessSymbolReaderException
71
     */
72
    private function resolveAddressAndSize(string $symbol_name): ?array
73
    {
74
        $symbol = $this->symbol_resolver->resolve($symbol_name);
75
        if ($symbol->isUndefined()) {
76
            return null;
77
        }
78
        $base_address = $this->base_address;
79
80
        if ($symbol->isTls()) {
81
            if (is_null($this->tls_block_address)) {
82
                throw new ProcessSymbolReaderException(
83
                    'trying to resolve TLS symbol but cannot find TLS block address'
84
                );
85
            }
86
            $base_address = $this->tls_block_address;
87
        }
88
        return [$base_address + $symbol->st_value->toInt(), $symbol->st_size->toInt()];
89
    }
90
91
    public function isAllSymbolResolvable(): bool
92
    {
93
        return $this->symbol_resolver instanceof Elf64AllSymbolResolver;
94
    }
95
}
96