File indexing completed on 2024-05-12 05:43:30
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 "dependencysorter.h" 0019 #include <checks/dependenciescheck.h> 0020 #include <elf/elffileset.h> 0021 0022 #include <QDebug> 0023 #include <QHash> 0024 0025 #include <cassert> 0026 #include <elf.h> 0027 0028 void DependencySorter::sortDtNeeded(ElfFileSet* fileSet) 0029 { 0030 assert(fileSet->size() > 0); 0031 0032 auto file = fileSet->file(0); 0033 if (!file->dynamicSection()) 0034 return; 0035 0036 // TODO index SO_NAME, this probably should be moved to ElfFileSet, we have that in a bunch of places now 0037 QHash<QByteArray, int> nameIndex; 0038 for (int i = 0; i < fileSet->size(); ++i) { 0039 const auto f = fileSet->file(i); 0040 if (!f->dynamicSection()) 0041 continue; 0042 const auto soName = f->dynamicSection()->soName(); 0043 if (nameIndex.contains(soName)) { 0044 qWarning() << "Suspicious DT_NEEDED entry '" << soName << "' in " << f->fileName() << ", aborting."; 0045 return; 0046 } 0047 0048 if (!soName.isEmpty()) 0049 nameIndex.insert(soName, i); 0050 } 0051 0052 // count usages 0053 QVector<int> usageCounts; 0054 const auto needed = file->dynamicSection()->neededLibraries(); 0055 usageCounts.resize(needed.size()); 0056 for (int i = 0; i < needed.size(); ++i) { 0057 auto depFile = fileSet->file(nameIndex.value(needed.at(i))); 0058 assert(depFile); 0059 assert(file != depFile); 0060 0061 usageCounts[i] = DependenciesCheck::usedSymbolCount(file, depFile); 0062 } 0063 qDebug() << usageCounts; 0064 0065 // sort, check if change is needed 0066 QVector<int> sortedNeededIndex; 0067 sortedNeededIndex.resize(needed.size()); 0068 std::iota(sortedNeededIndex.begin(), sortedNeededIndex.end(), 0); 0069 assert(sortedNeededIndex.size() == usageCounts.size()); 0070 qDebug() << sortedNeededIndex; 0071 0072 std::sort(sortedNeededIndex.begin(), sortedNeededIndex.end(), [usageCounts](int lhs, int rhs) { 0073 return usageCounts.at(lhs) > usageCounts.at(rhs); 0074 }); 0075 0076 qDebug() << sortedNeededIndex; 0077 0078 // since we modify the file in-place, get the necessary string table values before we do that 0079 QVector<uint64_t> neededValues; 0080 neededValues.resize(needed.size()); 0081 int neededIndex = 0; 0082 for (uint i = 0; i < file->dynamicSection()->header()->entryCount(); ++i) { 0083 auto dynEntry = file->dynamicSection()->entry(i); 0084 if (dynEntry->tag() != DT_NEEDED) 0085 continue; 0086 neededValues[neededIndex++] = dynEntry->value(); 0087 } 0088 0089 // open target file 0090 ElfFile newFile(file->fileName()); 0091 if (!newFile.open(QFile::ReadWrite) || !newFile.isValid()) { 0092 qWarning() << "Can't open" << file->fileName() << "for writing."; 0093 return; 0094 } 0095 0096 // write change 0097 neededIndex = 0; 0098 auto newDynSection = newFile.dynamicSection(); 0099 for (uint i = 0; i < newDynSection->header()->entryCount(); ++i) { 0100 auto dynEntry = newDynSection->entry(i); 0101 if (dynEntry->tag() != DT_NEEDED) 0102 continue; 0103 0104 dynEntry->setValue(neededValues.at(sortedNeededIndex.at(neededIndex))); 0105 0106 qDebug() << needed.at(sortedNeededIndex.at(neededIndex)); 0107 ++neededIndex; 0108 } 0109 0110 }