File indexing completed on 2024-04-28 05:41:05

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 <dwarf/dwarfdie.h>
0019 #include <dwarf/dwarfcudie.h>
0020 #include <dwarf/dwarfinfo.h>
0021 #include <dwarf/dwarfranges.h>
0022 #include <dwarf/dwarfaddressranges.h>
0023 
0024 #include <QtTest/qtest.h>
0025 #include <QObject>
0026 
0027 #include <dwarf.h>
0028 
0029 class DwarfDieTest : public QObject
0030 {
0031     Q_OBJECT
0032 private slots:
0033     void testCU()
0034     {
0035         ElfFile f(QStringLiteral(BINDIR "single-executable"));
0036         QVERIFY(f.open(QFile::ReadOnly));
0037         QVERIFY(f.dwarfInfo());
0038         QVERIFY(f.dwarfInfo()->compilationUnits().size() > 0);
0039 
0040         DwarfDie *cu = nullptr;
0041         foreach (auto die, f.dwarfInfo()->compilationUnits()) {
0042             if (die->name().contains("single-executable")) {
0043                 cu = die;
0044                 break;
0045             }
0046         }
0047 
0048         QVERIFY(cu);
0049         QCOMPARE(cu->tag(), (Dwarf_Half)DW_TAG_compile_unit);
0050         QVERIFY(cu->children().size() > 0);
0051         QVERIFY(cu->attributes().size() > 0);
0052     }
0053 
0054     void testAttribute_AT_ranges()
0055     {
0056         ElfFile f(QStringLiteral(BINDIR "single-executable"));
0057         QVERIFY(f.open(QFile::ReadOnly));
0058         QVERIFY(f.dwarfInfo());
0059         QVERIFY(f.dwarfInfo()->compilationUnits().size() > 0);
0060 
0061         foreach (auto cu, f.dwarfInfo()->compilationUnits()) {
0062             const auto lowPC = cu->attribute(DW_AT_low_pc);
0063             const auto ranges = cu->attribute(DW_AT_ranges);
0064             if (lowPC.isNull() && ranges.isNull())
0065                 continue;
0066 
0067             QVERIFY(lowPC.isNull() != ranges.isNull()); // exactly one of them must be present
0068             if (lowPC.isNull()) {
0069                 const auto r = ranges.value<DwarfRanges>();
0070                 QVERIFY(r.isValid());
0071                 QVERIFY(r.size() > 0);
0072             } else {
0073                 const auto textSection = f.section<ElfSection>(f.indexOfSection(".text"));
0074                 QVERIFY(lowPC.value<uint64_t>() >= textSection->header()->virtualAddress());
0075                 QVERIFY(lowPC.value<uint64_t>() < textSection->header()->virtualAddress() + textSection->header()->size());
0076             }
0077         }
0078     }
0079 
0080     void testArange()
0081     {
0082         ElfFile f(QStringLiteral(BINDIR "single-executable"));
0083         QVERIFY(f.open(QFile::ReadOnly));
0084         QVERIFY(f.dwarfInfo());
0085         QVERIFY(f.dwarfInfo()->addressRanges()->isValid());
0086 
0087         QVector<DwarfDie*> dieQueue;
0088         dieQueue.resize(f.dwarfInfo()->compilationUnits().size());
0089         auto cus = f.dwarfInfo()->compilationUnits();
0090         std::copy(cus.constBegin(), cus.constEnd(), dieQueue.begin());
0091         while (!dieQueue.isEmpty()) {
0092             const auto die = dieQueue.takeFirst();
0093             dieQueue += die->children();
0094 
0095             const auto lowPC = die->attribute(DW_AT_low_pc).toULongLong();
0096             if (lowPC <= 0)
0097                 continue;
0098 
0099             const auto lookupCU = f.dwarfInfo()->addressRanges()->compilationUnitForAddress(lowPC);
0100             auto cuDie = die;
0101             while (cuDie && cuDie->tag() != DW_TAG_compile_unit)
0102                 cuDie = cuDie->parentDie();
0103             QCOMPARE(cuDie, lookupCU);
0104 
0105             if (die->tag() == DW_TAG_compile_unit)
0106                 continue;
0107 
0108             const auto lookupDie = f.dwarfInfo()->addressRanges()->dieForAddress(lowPC);
0109             QVERIFY(die == lookupDie || lowPC == lookupDie->attribute(DW_AT_low_pc).toULongLong());
0110         }
0111     }
0112 };
0113 
0114 QTEST_MAIN(DwarfDieTest)
0115 
0116 #include "dwarfdietest.moc"