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 "deadcodefinder.h" 0019 #include <elf/elffileset.h> 0020 #include <elf/elfsymboltablesection.h> 0021 #include <elf/elfhashsection.h> 0022 #include <elf/elfheader.h> 0023 0024 #include <demangle/demangler.h> 0025 0026 #include <elf.h> 0027 0028 #include <iostream> 0029 0030 DeadCodeFinder::DeadCodeFinder() = default; 0031 DeadCodeFinder::DeadCodeFinder(const DeadCodeFinder&) = default; 0032 DeadCodeFinder::~DeadCodeFinder() = default; 0033 DeadCodeFinder& DeadCodeFinder::operator=(const DeadCodeFinder&) = default; 0034 0035 void DeadCodeFinder::findUnusedSymbols(ElfFileSet* fileSet) 0036 { 0037 m_fileSet = fileSet; 0038 0039 for (int i = 0; i < m_fileSet->size(); ++i) { 0040 scanUsage(m_fileSet->file(i)); 0041 } 0042 } 0043 0044 void DeadCodeFinder::scanUsage(ElfFile* file) 0045 { 0046 std::cerr << "Scanning " << qPrintable(file->displayName()) << "..." << std::endl; 0047 for (int i = 0; i < m_fileSet->size(); ++i) { 0048 auto otherFile = m_fileSet->file(i); 0049 auto symTab = file->hash()->linkedSection<ElfSymbolTableSection>(); 0050 if (!symTab) 0051 continue; 0052 for (uint j = 0; j < symTab->header()->entryCount(); ++j) { 0053 auto localSym = symTab->entry(j); 0054 if (localSym->size() > 0) 0055 continue; 0056 auto sym = otherFile->hash()->lookup(localSym->name()); 0057 if (!sym) 0058 continue; 0059 m_usedSymbols[otherFile].insert(sym); 0060 } 0061 } 0062 } 0063 0064 void DeadCodeFinder::setExcludePrefixes(const QStringList& excludePrefixes) 0065 { 0066 m_excludePrefixes = excludePrefixes; 0067 } 0068 0069 void DeadCodeFinder::dumpResults() 0070 { 0071 for (int i = 0; i < m_fileSet->size(); ++i) { 0072 auto file = m_fileSet->file(i); 0073 // this only makes sense for libraries 0074 if (file->header()->type() == ET_EXEC) 0075 continue; 0076 0077 bool skip = false; 0078 foreach (const auto &excludePrefix, m_excludePrefixes) { 0079 if (file->fileName().startsWith(excludePrefix)) { 0080 skip = true; 0081 break; 0082 } 0083 } 0084 if (skip) 0085 continue; 0086 0087 std::cout << "Unreferenced exported symbols in " << qPrintable(file->displayName()) << ":" << std::endl; 0088 dumpResultsForFile(file); 0089 std::cout << std::endl; 0090 } 0091 } 0092 0093 void DeadCodeFinder::dumpResultsForFile(ElfFile* file) 0094 { 0095 const auto usedSyms = m_usedSymbols.value(file); 0096 const auto symTab = file->hash()->linkedSection<ElfSymbolTableSection>(); 0097 if (!symTab) 0098 return; 0099 0100 QVector<QByteArray> unusedSyms; 0101 for (uint i = 0; i < symTab->header()->entryCount(); ++i) { 0102 auto sym = symTab->entry(i); 0103 if (sym->size() == 0 || sym->bindType() != STB_GLOBAL || sym->visibility() != STV_DEFAULT) 0104 continue; 0105 if (usedSyms.contains(sym)) 0106 continue; 0107 unusedSyms.push_back(Demangler::demangleFull(sym->name()).constData()); 0108 } 0109 0110 std::sort(unusedSyms.begin(), unusedSyms.end()); 0111 std::for_each(unusedSyms.constBegin(), unusedSyms.constEnd(), [](const QByteArray& sym) { std::cout << sym.constData() << std::endl; }); 0112 }