File indexing completed on 2024-04-28 05:41:06
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 <elf/elffile.h> 0019 #include <elf/elffileset.h> 0020 #include <elf/elfsymboltablesection.h> 0021 #include <elf/elfgnusymbolversiontable.h> 0022 #include <elf/elfgnusymbolversiondefinitionssection.h> 0023 #include <elf/elfgnusymbolversiondefinition.h> 0024 #include <elf/elfgnusymbolversionrequirementssection.h> 0025 #include <elf/elfgnusymbolversionrequirement.h> 0026 #include <elf/elfgnusymbolversiondefinitionauxiliaryentry.h> 0027 0028 #include <QDebug> 0029 #include <QtTest/qtest.h> 0030 #include <QObject> 0031 0032 #include <elf.h> 0033 0034 class ElfGNUSymbolVersioningTest: public QObject 0035 { 0036 Q_OBJECT 0037 private slots: 0038 void testSymbolVersioning() 0039 { 0040 ElfFileSet set; 0041 set.addFile(QStringLiteral(BINDIR "elf-dissector")); 0042 QVERIFY(set.size() > 1); 0043 0044 // we need a full library for this, not just an executable 0045 ElfFile *f = nullptr; 0046 for (int i = 0; i < set.size(); ++i) { 0047 if (set.file(i)->dynamicSection()->soName() == "libQt5Core.so.5") 0048 f = set.file(i); 0049 } 0050 QVERIFY(f); 0051 0052 const auto symVerIndex = f->indexOfSection(".gnu.version"); 0053 QVERIFY(symVerIndex > 0); 0054 QCOMPARE(symVerIndex, f->indexOfSection(SHT_GNU_versym)); 0055 const auto symbolVersionTable = f->section<ElfGNUSymbolVersionTable>(symVerIndex); 0056 QVERIFY(symbolVersionTable); 0057 QCOMPARE(symbolVersionTable->header()->entryCount(), f->section<ElfSymbolTableSection>(f->indexOfSection(".dynsym"))->header()->entryCount()); 0058 0059 const auto symDefIndex = f->indexOfSection(".gnu.version_d"); 0060 QVERIFY(symDefIndex > 0); 0061 QCOMPARE(symDefIndex, f->indexOfSection(SHT_GNU_verdef)); 0062 const auto symbolVersionDefs = f->section<ElfGNUSymbolVersionDefinitionsSection>(symDefIndex); 0063 QVERIFY(symbolVersionDefs); 0064 0065 QCOMPARE(f->dynamicSection()->entryWithTag(DT_VERDEFNUM)->value(), (uint64_t)symbolVersionDefs->entryCount()); 0066 QVERIFY(symbolVersionDefs->entryCount() > 0); 0067 0068 const auto verDef = symbolVersionDefs->definition(0); 0069 QVERIFY(verDef); 0070 QVERIFY(verDef->auxiliarySize() > 0); 0071 0072 const auto verDefAux = verDef->auxiliaryEntry(0); 0073 QVERIFY(verDefAux); 0074 0075 const auto symNeedIndex = f->indexOfSection(".gnu.version_r"); 0076 QVERIFY(symNeedIndex > 0); 0077 QCOMPARE(symNeedIndex, f->indexOfSection(SHT_GNU_verneed)); 0078 const auto symbolVersionNeeds = f->section<ElfGNUSymbolVersionRequirementsSection>(symNeedIndex); 0079 QVERIFY(symbolVersionNeeds); 0080 0081 QCOMPARE(f->dynamicSection()->entryWithTag(DT_VERNEEDNUM)->value(), (uint64_t)symbolVersionNeeds->entryCount()); 0082 QVERIFY(symbolVersionNeeds->entryCount() > 0); 0083 0084 const auto verNeed = symbolVersionNeeds->requirement(0); 0085 QVERIFY(verNeed); 0086 QVERIFY(verNeed->auxiliarySize() > 0); 0087 } 0088 0089 void testSymbolVersionDefinitions() 0090 { 0091 ElfFileSet set; 0092 set.addFile(QStringLiteral(BINDIR "libversioned-symbols.so")); 0093 QVERIFY(set.size() > 1); 0094 0095 auto f = set.file(0); 0096 QVERIFY(f); 0097 0098 const auto symDefIndex = f->indexOfSection(".gnu.version_d"); 0099 const auto symbolVersionDefs = f->section<ElfGNUSymbolVersionDefinitionsSection>(symDefIndex); 0100 QVERIFY(symbolVersionDefs); 0101 QCOMPARE(symbolVersionDefs->entryCount(), 3u); 0102 0103 ElfGNUSymbolVersionDefinition *defV1 = nullptr, *defV2 = nullptr; 0104 auto def = symbolVersionDefs->definition(1); 0105 QVERIFY(def); 0106 QCOMPARE(def->versionIndex(), (uint16_t)2); 0107 QCOMPARE(symbolVersionDefs->definitionForVersionIndex(2), def); 0108 #ifdef Q_OS_FREEBSD 0109 // Both entries have auxiliarySize == 1 0110 QCOMPARE(def->auxiliarySize(), 1u); 0111 QCOMPARE(def->auxiliaryEntry(0)->name(), "VER1"); 0112 defV1 = def; 0113 #else 0114 if (def->auxiliarySize() == 1) 0115 defV1 = def; 0116 else 0117 defV2 = def; 0118 #endif 0119 0120 def = symbolVersionDefs->definition(2); 0121 QVERIFY(def); 0122 QCOMPARE(def->versionIndex(), (uint16_t)3); 0123 QCOMPARE(symbolVersionDefs->definitionForVersionIndex(3), def); 0124 #ifdef Q_OS_FREEBSD 0125 // Both entries have auxiliarySize == 1 0126 QCOMPARE(def->auxiliarySize(), 1u); 0127 QCOMPARE(def->auxiliaryEntry(0)->name(), "VER2"); 0128 defV2 = def; 0129 #else 0130 if (def->auxiliarySize() == 1) 0131 defV1 = def; 0132 else 0133 defV2 = def; 0134 #endif 0135 QVERIFY(defV1); 0136 QVERIFY(defV2); 0137 0138 #ifdef Q_OS_FREEBSD 0139 QEXPECT_FAIL("", "FreeBSD only 1 auxiliary", Continue); 0140 #endif 0141 QCOMPARE(defV2->auxiliarySize(), (uint16_t)2); 0142 auto defEntry = defV2->auxiliaryEntry(0); 0143 QVERIFY(defEntry); 0144 QCOMPARE(defEntry->name(), "VER2"); 0145 if (defV2->auxiliarySize() > 1) 0146 { 0147 defEntry = defV2->auxiliaryEntry(1); 0148 QVERIFY(defEntry); 0149 QCOMPARE(defEntry->name(), "VER1"); 0150 } 0151 0152 QCOMPARE(defV1->auxiliarySize(), (uint16_t)1); 0153 defEntry = defV1->auxiliaryEntry(0); 0154 QVERIFY(defEntry); 0155 QCOMPARE(defEntry->name(), "VER1"); 0156 0157 const auto symVerIndex = f->indexOfSection(".gnu.version"); 0158 const auto symbolVersionTable = f->section<ElfGNUSymbolVersionTable>(symVerIndex); 0159 QVERIFY(symbolVersionTable); 0160 0161 const auto dynTabIndex = f->indexOfSection(".dynsym"); 0162 QVERIFY(dynTabIndex > 0); 0163 const auto symTab = f->section<ElfSymbolTableSection>(dynTabIndex); 0164 QVERIFY(symTab); 0165 QCOMPARE(symTab->header()->entryCount(), symbolVersionTable->header()->entryCount()); 0166 0167 ElfSymbolTableEntry *f1 = nullptr, *f2 = nullptr, *f_ver1 = nullptr, *f_ver2 = nullptr; 0168 for (uint i = 0; i < symTab->header()->entryCount(); ++i) { 0169 auto sym = symTab->entry(i); 0170 QVERIFY(sym); 0171 if (strcmp(sym->name(), "function1") == 0) 0172 f1 = sym; 0173 else if (strcmp(sym->name(), "function2") == 0) 0174 f2 = sym; 0175 else if (strcmp(sym->name(), "function") == 0) { 0176 qDebug() << symbolVersionTable->versionIndex(i); 0177 if (symbolVersionTable->versionIndex(i) == defV2->versionIndex()) 0178 f_ver2 = sym; 0179 else if (symbolVersionTable->versionIndex(i) == defV1->versionIndex()) 0180 f_ver1 = sym; 0181 } 0182 } 0183 0184 QVERIFY(f1); 0185 QVERIFY(f2); 0186 QVERIFY(f_ver1); 0187 QVERIFY(f_ver2); 0188 QCOMPARE(f1->value(), f_ver1->value()); 0189 QCOMPARE(f2->value(), f_ver2->value()); 0190 } 0191 }; 0192 0193 QTEST_MAIN(ElfGNUSymbolVersioningTest) 0194 0195 #include "elfgnusymbolversioningtest.moc"