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/elfsymboltablesection.h>
0020 #include <elf/elfheader.h>
0021 #include <elf/elfpltsection.h>
0022 #include <elf/elfrelocationsection.h>
0023 #include <elf/elfgotsection.h>
0024 
0025 #include <QtTest/qtest.h>
0026 #include <QObject>
0027 
0028 #include <elf.h>
0029 
0030 class ElfFileTest : public QObject
0031 {
0032     Q_OBJECT
0033 private slots:
0034     void testLoad_data()
0035     {
0036         QTest::addColumn<QString>("executable");
0037         QTest::newRow("single-executable") << QStringLiteral(BINDIR "single-executable");
0038         QTest::newRow("structures") << QStringLiteral(BINDIR "structures");
0039     }
0040     void testLoad()
0041     {
0042         QFETCH(QString, executable);
0043 
0044         ElfFile f(executable);
0045         QVERIFY(f.open(QFile::ReadOnly));
0046         QCOMPARE(f.isValid(), true);
0047         QCOMPARE(f.byteOrder(), ELFDATA2LSB);
0048 
0049         QVERIFY(f.header());
0050         QVERIFY(f.header()->programHeaderCount() > 0);
0051         QVERIFY(f.header()->programHeaderEntrySize() > 0);
0052         QVERIFY(f.header()->programHeaderTableOffset() > 0);
0053         QVERIFY(f.header()->sectionHeaderCount() > 0);
0054         QVERIFY(f.header()->sectionHeaderEntrySize() > 0);
0055         QVERIFY(f.header()->sectionHeaderTableOffset() > 0);
0056 
0057         QCOMPARE(f.sectionHeaders().isEmpty(), false);
0058         QCOMPARE((uint16_t)f.sectionHeaders().size(), f.header()->sectionHeaderCount());
0059         QCOMPARE((uint16_t)f.sectionCount(), f.header()->sectionHeaderCount());
0060         QVERIFY(f.size() > 0);
0061         QVERIFY(f.indexOfSection(".dynsym") >= 0);
0062         QCOMPARE(f.indexOfSection(".doesnotexist"), -1);
0063 
0064         QVERIFY(f.dynamicSection());
0065         QVERIFY(f.dynamicSection()->size() > 0);
0066         QVERIFY(f.symbolTable());
0067         QVERIFY(f.symbolTable()->size() > 0);
0068 
0069         if (f.indexOfSection(".plt") > 0) {
0070             auto pltSection = f.section<ElfPltSection>(f.indexOfSection(".plt"));
0071             QVERIFY(pltSection);
0072 #ifdef Q_OS_FREEBSD
0073             QEXPECT_FAIL("", "FreeBSD no plt entries", Continue);
0074 #endif
0075             QVERIFY(pltSection->header()->entryCount() > 0);
0076             QVERIFY(pltSection->gotSection());
0077             for (uint i = 1; i < pltSection->header()->entryCount(); ++i) {
0078                 auto pltEntry = pltSection->entry(i);
0079                 QVERIFY(pltEntry);
0080                 QVERIFY(pltEntry->gotEntry());
0081             }
0082         }
0083 
0084         QVERIFY(f.reverseRelocator());
0085 
0086         for (int i = 0; i < f.header()->sectionHeaderCount(); ++i) {
0087             auto shdr = f.sectionHeaders().at(i);
0088             if (shdr->type() == SHT_REL || shdr->type() == SHT_RELA) {
0089                 auto section = f.section<ElfRelocationSection>(i);
0090                 QVERIFY(section);
0091                 QVERIFY(section->header()->entryCount() > 0);
0092             }
0093 
0094             if (QByteArray(shdr->name()).startsWith(".got")) {
0095                 auto section = f.section<ElfGotSection>(i);
0096                 QVERIFY(section);
0097                 uint startIndex = 0;
0098                 if (strcmp(shdr->name(), ".got.plt") == 0)
0099                     startIndex = 3; // the first 3 entries are placeholders for lazy symbol resolution
0100                 for (uint i = startIndex; i < section->header()->entryCount(); ++i) {
0101                     auto gotEntry = section->entry(i);
0102                     QVERIFY(f.reverseRelocator()->find(gotEntry->address()));
0103                 }
0104             }
0105         }
0106 
0107 #ifdef Q_OS_FREEBSD
0108         // Doesn't seem to have a buildId (w/ clang, anyway)
0109         QVERIFY(f.buildId().isEmpty());
0110 #else
0111         QVERIFY(f.buildId().size() >= 16);
0112 #endif
0113 
0114         QCOMPARE((uint16_t)f.segmentHeaders().size(), f.header()->programHeaderCount());
0115     }
0116 
0117     void testFailedLoad_data()
0118     {
0119         QTest::addColumn<QString>("executable");
0120         QTest::newRow("not existing") << QStringLiteral("not-existing");
0121         QTest::newRow("text file") << QStringLiteral(BINDIR "../CMakeCache.txt");
0122     }
0123 
0124     void testFailedLoad()
0125     {
0126         QFETCH(QString, executable);
0127 
0128         ElfFile f(executable);
0129         QCOMPARE(f.open(QFile::ReadOnly), false);
0130         QCOMPARE(f.isValid(), false);
0131     }
0132 };
0133 
0134 QTEST_MAIN(ElfFileTest)
0135 
0136 #include "elffiletest.moc"