File indexing completed on 2024-05-12 05:43:25

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 "dependenciescheck.h"
0019 
0020 #include <elf/elffileset.h>
0021 #include <elf/elffile.h>
0022 #include <elf/elfsectionheader.h>
0023 #include <elf/elfhashsection.h>
0024 #include <elf/elfsymboltablesection.h>
0025 #include <elf/elfsymboltableentry.h>
0026 
0027 #include <QHash>
0028 
0029 #include <cassert>
0030 #include <iostream>
0031 
0032 DependenciesCheck::UnusedDependencies DependenciesCheck::unusedDependencies(ElfFileSet* fileSet, int fileToCheck)
0033 {
0034     QHash<QByteArray, int> fileIndex;
0035     for (int i = 0; i < fileSet->size(); ++i) {
0036         const auto file = fileSet->file(i);
0037         if (!file->dynamicSection())
0038             continue;
0039         const auto soName = file->dynamicSection()->soName();
0040         if (!soName.isEmpty())
0041             fileIndex.insert(soName, i);
0042         else
0043             fileIndex.insert(file->fileName().toUtf8(), i);
0044     }
0045 
0046     UnusedDependencies unusedDeps;
0047     for (int i = 0; i < fileSet->size(); ++i) {
0048         if (i != fileToCheck && fileToCheck >= 0)
0049             continue;
0050         const auto *dynamicSection = fileSet->file(i)->dynamicSection();
0051         if (!dynamicSection)
0052             continue;
0053         foreach (const auto &needed, fileSet->file(i)->dynamicSection()->neededLibraries()) {
0054             const auto depIdx = fileIndex.value(needed);
0055             const auto depFile = fileSet->file(depIdx);
0056             const auto count = usedSymbolCount(fileSet->file(i), depFile);
0057             if (count == 0)
0058                 unusedDeps.push_back(qMakePair(i, depIdx));
0059         }
0060     }
0061 
0062     return unusedDeps;
0063 }
0064 
0065 void DependenciesCheck::printUnusedDependencies(ElfFileSet* fileSet, const UnusedDependencies& unusedDeps)
0066 {
0067     for (auto unusedDep : unusedDeps) {
0068         std::cout << qPrintable(fileSet->file(unusedDep.first)->displayName()) << " depends on "
0069                   << qPrintable(fileSet->file(unusedDep.second)->displayName()) << " without using any of its symbols"
0070                   << std::endl;
0071     }
0072 }
0073 
0074 QVector<ElfSymbolTableEntry*> DependenciesCheck::usedSymbols(ElfFile* userFile, ElfFile* providerFile)
0075 {
0076     QVector<ElfSymbolTableEntry*> symbols;
0077 
0078     const auto symtab = userFile->section<ElfSymbolTableSection>(userFile->indexOfSection(SHT_DYNSYM));
0079     if (!symtab)
0080         return symbols;
0081     const auto symtabSize = symtab->header()->entryCount();
0082 
0083     const auto hashtab = providerFile->hash();
0084     assert(hashtab);
0085 
0086     for (uint i = 0; i < symtabSize; ++i) {
0087         const auto userEntry = symtab->entry(i);
0088         if (userEntry->value() != 0)
0089             continue;
0090         const auto providerEntry = hashtab->lookup(userEntry->name());
0091         if (providerEntry && providerEntry->value() > 0)
0092             symbols.push_back(providerEntry);
0093     }
0094 
0095     return symbols;
0096 }
0097 
0098 int DependenciesCheck::usedSymbolCount(ElfFile* userFile, ElfFile* providerFile)
0099 {
0100     const auto symtab = userFile->section<ElfSymbolTableSection>(userFile->indexOfSection(SHT_DYNSYM));
0101     if (!symtab)
0102         return 0;
0103     const auto symtabSize = symtab->header()->entryCount();
0104 
0105     const auto hashtab = providerFile->hash();
0106     assert(hashtab);
0107 
0108     int count = 0;
0109     for (uint i = 0; i < symtabSize; ++i) {
0110         const auto userEntry = symtab->entry(i);
0111         if (userEntry->value() != 0)
0112             continue;
0113         const auto providerEntry = hashtab->lookup(userEntry->name());
0114         if (providerEntry && providerEntry->value() > 0)
0115             ++count;
0116     }
0117     return count;
0118 }