Passed
Push — 0.6.x ( 9a1948...a98caa )
by Shinji
03:23 queued 01:32
created

Elf64GnuHashTable   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 65
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 21
c 1
b 1
f 0
dl 0
loc 65
rs 10
wmc 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A lookup() 0 19 4
A getNumberOfSymbols() 0 5 1
A __construct() 0 9 1
A hash() 0 9 2
A checkBloomFilter() 0 6 2
1
<?php
2
3
/**
4
 * This file is part of the reliforp/reli-prof 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 Reli\Lib\Elf\Structure\Elf64;
15
16
use Reli\Lib\Integer\UInt64;
17
18
/**
19
 * @see https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/
20
 */
21
final class Elf64GnuHashTable
22
{
23
    public const ELFCLASS_BITS = 64;
24
25
    /**
26
     * @param UInt64[] $bloom
27
     * @param int[] $buckets
28
     * @param int[] $chain
29
     */
30
    public function __construct(
31
        public int $nbuckets, // uint32_t
32
        public int $symoffset, // uint32_t
33
        public int $bloom_size, // uint32_t
34
        public int $bloom_shift, // uint32_t
35
        public array $bloom, // uint64_t[bloom_size]
36
        public array $buckets, // uint32_t[nbuckets]
37
        public array $chain // uint32_t[]
38
    ) {
39
    }
40
41
    public function lookup(string $name, callable $symbol_table_checker): int
42
    {
43
        $hash = self::hash($name);
44
/* this filter is buggy, so commenting out for now
45
        if (!$this->checkBloomFilter($hash)) {
46
            return Elf64SymbolTable::STN_UNDEF;
47
        }
48
*/
49
        $chain_offset = max(0, $this->buckets[$hash % $this->nbuckets] - $this->symoffset);
50
51
        do {
52
            if ((1 | $this->chain[$chain_offset]) === (1 | $hash)) {
53
                if ($symbol_table_checker($name, $chain_offset + $this->symoffset)) {
54
                    return $chain_offset + $this->symoffset;
55
                }
56
            }
57
        } while (($this->chain[$chain_offset++] & 1) === 0);
58
59
        return Elf64SymbolTable::STN_UNDEF;
60
    }
61
62
    public function getNumberOfSymbols(): int
63
    {
64
        /** @var int $last_chain_key */
65
        $last_chain_key = array_key_last($this->chain);
66
        return $last_chain_key + 1 + $this->symoffset;
67
    }
68
69
    public function checkBloomFilter(int $hash): bool
70
    {
71
        $bloom = $this->bloom[($hash / self::ELFCLASS_BITS) % $this->bloom_size];
72
        $bloom_hash1 = $hash % self::ELFCLASS_BITS;
73
        $bloom_hash2 = ($hash >> $this->bloom_shift) % self::ELFCLASS_BITS;
74
        return $bloom->checkBitSet($bloom_hash1) and $bloom->checkBitSet($bloom_hash2);
75
    }
76
77
    public static function hash(string $name): int
78
    {
79
        $h = 5381;
80
81
        $name_len = strlen($name);
82
        for ($i = 0; $i < $name_len; $i++) {
83
            $h = (($h << 5) + $h + ord($name[$i])) & 0xffffffff;
84
        }
85
        return $h;
86
    }
87
}
88