File indexing completed on 2024-05-12 05:43:29
0001 /* 0002 Copyright (C) 2015 Volker Krause <vkrause@kde.org> 0003 0004 This program is free software; you can redistribute it and/or modify it 0005 under the terms of the GNU Library General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or (at your 0007 option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, but WITHOUT 0010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0012 License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program. If not, see <https://www.gnu.org/licenses/>. 0016 */ 0017 0018 #include "elfgnuhashsection.h" 0019 #include "elfsymboltablesection.h" 0020 #include "elffile.h" 0021 0022 0023 #include <cassert> 0024 0025 ElfGnuHashSection::ElfGnuHashSection(ElfFile* file, ElfSectionHeader* shdr): 0026 ElfHashSection(file, shdr) 0027 { 0028 // must be a power of two 0029 assert ((maskWordsCount() & (maskWordsCount() - 1)) == 0); 0030 } 0031 0032 ElfGnuHashSection::~ElfGnuHashSection() = default; 0033 0034 uint32_t ElfGnuHashSection::bucketCount() const 0035 { 0036 return *reinterpret_cast<const uint32_t*>(rawData()); 0037 } 0038 0039 uint32_t ElfGnuHashSection::bucket(uint32_t index) const 0040 { 0041 return *(reinterpret_cast<const uint32_t*>(rawData() + maskWordsCount() * file()->addressSize()) + 4 + index); 0042 } 0043 0044 uint32_t ElfGnuHashSection::chainCount() const 0045 { 0046 const auto symTab = linkedSection<ElfSymbolTableSection>(); 0047 assert(symTab); 0048 return symTab->header()->entryCount() - symbolIndex(); 0049 } 0050 0051 uint32_t* ElfGnuHashSection::value(uint32_t index) const 0052 { 0053 return const_cast<uint32_t*>(reinterpret_cast<const uint32_t*>(rawData() + maskWordsCount() * file()->addressSize()) + 4 + bucketCount() + index - symbolIndex()); 0054 } 0055 0056 uint32_t ElfGnuHashSection::symbolIndex() const 0057 { 0058 return *(reinterpret_cast<const uint32_t*>(rawData()) + 1); 0059 } 0060 0061 uint32_t ElfGnuHashSection::maskWordsCount() const 0062 { 0063 return *(reinterpret_cast<const uint32_t*>(rawData()) + 2); 0064 } 0065 0066 uint32_t ElfGnuHashSection::shift2() const 0067 { 0068 return *(reinterpret_cast<const uint32_t*>(rawData()) + 3); 0069 } 0070 0071 uint32_t ElfGnuHashSection::hash(const char* name) 0072 { 0073 uint32_t h = 5381; 0074 0075 for (unsigned char c = *name; c != '\0'; c = *++name) 0076 h = h * 33 + c; 0077 0078 return h; 0079 } 0080 0081 uint64_t ElfGnuHashSection::filterMask(uint32_t index) const 0082 { 0083 if (file()->addressSize() == 8) 0084 return *(reinterpret_cast<const uint64_t*>(rawData()) + 2 + index); 0085 return *(reinterpret_cast<const uint32_t*>(rawData()) + 4 + index); 0086 } 0087 0088 ElfSymbolTableEntry* ElfGnuHashSection::lookup(const char* name) const 0089 { 0090 auto h1 = hash(name); 0091 0092 { 0093 const uint32_t h2 = h1 >> shift2(); 0094 const uint32_t c = file()->addressSize() * 8; 0095 const uint32_t n = (h1 / c) & (maskWordsCount() - 1); 0096 0097 const uint32_t hashbit1 = h1 & (c - 1); 0098 const uint32_t hashbit2 = h2 & (c - 1); 0099 0100 const auto bitmask = filterMask(n); 0101 if (((bitmask >> hashbit1) & (bitmask >> hashbit2) & 1) == 0) 0102 return nullptr; 0103 } 0104 0105 auto n = bucket(h1 % bucketCount()); 0106 if (n == 0) 0107 return nullptr; 0108 0109 const auto symTab = linkedSection<ElfSymbolTableSection>(); 0110 assert(symTab); 0111 auto hashValue = value(n); 0112 0113 for (h1 &= ~1; true; ++n) { 0114 const auto entry = symTab->entry(n); 0115 const auto h2 = *hashValue++; 0116 if ((h1 == (h2 & ~1)) && strcmp(name, entry->name()) == 0) 0117 return entry; 0118 if (h2 & 1) 0119 break; 0120 } 0121 0122 return nullptr; 0123 } 0124 0125 QVector<uint32_t> ElfGnuHashSection::histogram() const 0126 { 0127 QVector<uint32_t> hist; 0128 for (uint i = 0; i < bucketCount(); ++i) { 0129 int count = 0; 0130 0131 const auto n = bucket(i); 0132 auto hashValue = value(n); 0133 0134 while (!(*hashValue++ & 1)) 0135 ++count; 0136 0137 hist.resize(std::max(hist.size(), count + 1)); 0138 hist[count]++; 0139 } 0140 return hist; 0141 } 0142 0143 double ElfGnuHashSection::averagePrefixLength() const 0144 { 0145 int sum = 0; 0146 int count = 0; 0147 0148 const auto symTab = linkedSection<ElfSymbolTableSection>(); 0149 assert(symTab); 0150 0151 for (uint i = 0; i < bucketCount(); ++i) { 0152 auto n1 = bucket(i); 0153 auto hashValue1 = value(n1); 0154 while (!(*hashValue1 & 1)) { 0155 const auto entry1 = symTab->entry(n1); 0156 0157 auto n2 = n1 + 1; 0158 auto hashValue2 = hashValue1 + 1; 0159 while (!(*hashValue2 & 1)) { 0160 const auto entry2 = symTab->entry(n2); 0161 sum += commonPrefixLength(entry1->name(), entry2->name()); 0162 ++count; 0163 ++hashValue2; 0164 } 0165 ++hashValue1; 0166 ++n1; 0167 } 0168 } 0169 0170 return count > 0 ? (double)sum / (double)count : 0.0; 0171 }