Passed
Push — master ( 46a849...6d6c3a )
by Shinji
01:23
created

ProcessModuleSymbolReader::isAllSymbolResolvable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\ProcessMemoryArea;
20
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderInterface;
21
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderException;
22
23
/**
24
 * Class ProcessModuleSymbolReader
25
 * @package PhpProfiler\ProcessReader
26
 */
27
final class ProcessModuleSymbolReader implements ProcessSymbolReaderInterface
28
{
29
    private Elf64SymbolResolver $symbol_resolver;
30
    /** @var ProcessMemoryArea[] */
31
    private array $memory_areas;
32
    private int $base_address;
33
    private MemoryReaderInterface $memory_reader;
34
    private ?int $tls_block_address;
35
    private int $pid;
36
37
    /**
38
     * ProcessModuleSymbolResolver constructor.
39
     * @param int $pid
40
     * @param Elf64SymbolResolver $symbol_resolver
41
     * @param ProcessMemoryArea[] $memory_areas
42
     * @param MemoryReaderInterface $memory_reader
43
     * @param int|null $tls_block_address
44
     */
45
    public function __construct(
46
        int $pid,
47
        Elf64SymbolResolver $symbol_resolver,
48
        array $memory_areas,
49
        MemoryReaderInterface $memory_reader,
50
        ?int $tls_block_address
51
    ) {
52
        $this->pid = $pid;
53
        $this->symbol_resolver = $symbol_resolver;
54
        $this->memory_areas = $memory_areas;
55
        $this->base_address = hexdec(current($memory_areas)->begin);
56
        $this->memory_reader = $memory_reader;
57
        $this->tls_block_address = $tls_block_address;
58
    }
59
60
    /**
61
     * @param string $symbol_name
62
     * @return \FFI\CArray|null
63
     * @throws MemoryReaderException
64
     * @throws ProcessSymbolReaderException
65
     */
66
    public function read(string $symbol_name): ?CData
67
    {
68
        $address_and_size = $this->resolveAddressAndSize($symbol_name);
69
        if ($address_and_size === null) {
70
            return null;
71
        }
72
        [$address, $size] = $address_and_size;
73
        return $this->memory_reader->read($this->pid, $address, $size);
74
    }
75
76
    /**
77
     * @param string $symbol_name
78
     * @return int|null
79
     * @throws ProcessSymbolReaderException
80
     */
81
    public function resolveAddress(string $symbol_name): ?int
82
    {
83
        $address_and_size = $this->resolveAddressAndSize($symbol_name);
84
        if ($address_and_size === null) {
85
            return null;
86
        }
87
        [$address,] = $address_and_size;
88
        return $address;
89
    }
90
91
92
    /**
93
     * @param string $symbol_name
94
     * @return int[]|null
95
     * @throws ProcessSymbolReaderException
96
     */
97
    private function resolveAddressAndSize(string $symbol_name): ?array
98
    {
99
        $symbol = $this->symbol_resolver->resolve($symbol_name);
100
        if ($symbol->isUndefined()) {
101
            return null;
102
        }
103
        $base_address = $this->base_address;
104
105
        if ($symbol->isTls()) {
106
            if (is_null($this->tls_block_address)) {
107
                throw new ProcessSymbolReaderException(
108
                    'trying to resolve TLS symbol but cannot find TLS block address'
109
                );
110
            }
111
            $base_address = $this->tls_block_address;
112
        }
113
        return [$base_address + $symbol->st_value->toInt(), $symbol->st_size->toInt()];
114
    }
115
116
    /**
117
     * @return bool
118
     */
119
    public function isAllSymbolResolvable(): bool
120
    {
121
        return $this->symbol_resolver instanceof Elf64AllSymbolResolver;
122
    }
123
}
124