LibThreadDbTlsFinder::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 6
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\Tls;
15
16
use PhpProfiler\Lib\ByteStream\CDataByteReader;
17
use PhpProfiler\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader;
18
use PhpProfiler\Lib\Elf\Process\ProcessSymbolReaderInterface;
19
use PhpProfiler\Lib\Elf\Process\ProcessSymbolReaderException;
20
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderException;
21
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderInterface;
22
23
/**
24
 * This class uses some debugging symbols from libpthread.so,
25
 * so if the target process doesn't load libpthread, it won't work.
26
 */
27
final class LibThreadDbTlsFinder implements TlsFinderInterface
28
{
29
    public function __construct(
30
        private ProcessSymbolReaderInterface $symbol_reader,
31
        private ThreadPointerRetrieverInterface $thread_pointer_retriever,
32
        private MemoryReaderInterface $memory_reader,
33
        private IntegerByteSequenceReader $integer_reader,
34
    ) {
35
    }
36
37
    /**
38
     * @throws MemoryReaderException
39
     * @throws ProcessSymbolReaderException
40
     * @throws TlsFinderException
41
     */
42
    public function findTlsBlock(int $pid, int $module_index): int
43
    {
44
        $thread_pointer = $this->thread_pointer_retriever->getThreadPointer($pid);
45
46
        [,,$thread_db_pthread_dtvp_offset] = $this->getLibThreadDbDescriptor('_thread_db_pthread_dtvp');
47
        [$thread_db_dtv_dtv_size,,] = $this->getLibThreadDbDescriptor('_thread_db_dtv_dtv');
48
        [,,$thread_db_dtv_t_pointer_val_offset] = $this->getLibThreadDbDescriptor('_thread_db_dtv_t_pointer_val');
49
//        [,,] = $this->getLibThreadDbDescriptor($pid, '_thread_db_link_map_l_tls_modid');
50
51
        $dtv_pointer_address = $thread_pointer + $thread_db_pthread_dtvp_offset;
52
        $dtv_pointer_cdata = $this->memory_reader->read($pid, $dtv_pointer_address, 8);
53
        $dtv_pointer = $this->integer_reader->read64(new CDataByteReader($dtv_pointer_cdata), 0)->toInt();
54
55
        $dtv_slot = $thread_db_dtv_dtv_size * $module_index;
56
        $tls_address_pointer = $dtv_pointer + $dtv_slot + $thread_db_dtv_t_pointer_val_offset;
57
58
        $tls_address_cdata = $this->memory_reader->read($pid, $tls_address_pointer, 8);
59
        return $this->integer_reader->read64(new CDataByteReader($tls_address_cdata), 0)->toInt();
60
    }
61
62
    /**
63
     * @return int[]
64
     * @throws MemoryReaderException
65
     * @throws ProcessSymbolReaderException
66
     * @throws TlsFinderException
67
     */
68
    private function getLibThreadDbDescriptor(string $symbol_name): array
69
    {
70
        $buffer = $this->symbol_reader->read($symbol_name);
71
        if (is_null($buffer)) {
72
            throw new TlsFinderException('cannot find ' . $symbol_name);
73
        }
74
        $desc = new CDataByteReader($buffer);
75
76
        $desc_size = $this->integer_reader->read32($desc, 0) >> 3;
77
        $desc_num = $this->integer_reader->read32($desc, 4);
78
        $desc_offset = $this->integer_reader->read32($desc, 8);
79
80
        return [$desc_size, $desc_num, $desc_offset];
81
    }
82
}
83