1 /* 2 Copyright (C) 2014 Volker Krause <vkrause@kde.org> 3 4 This program is free software; you can redistribute it and/or modify it 5 under the terms of the GNU Library General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or (at your 7 option) any later version. 8 9 This program is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 12 License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18 #include <config-elf-dissector.h> 19 20 #include <QtTest/qtest.h> 21 #include <QObject> 22 #include <QDebug> 23 24 #include <demangle/demangler.h> 25 26 #define VB QVector<QByteArray>() 27 28 class DemanglerTest : public QObject 29 { 30 Q_OBJECT 31 private slots: testDemangler_data()32 void testDemangler_data() 33 { 34 QTest::addColumn<QString>("mangled"); // should be QByteArray, but then we have to explicitly cast it below 35 QTest::addColumn<QVector<QByteArray>>("expectedDemangled"); 36 37 QTest::newRow("empty") << "" << (VB << ""); 38 QTest::newRow("C 1") << "malloc" << (VB << "malloc"); 39 QTest::newRow("member func 1") << "_ZN10QArrayData4dataEv" << (VB << "QArrayData" << "data()"); 40 QTest::newRow("member func 2") << "_ZN10QByteArray6appendERKS_" << (VB << "QByteArray" << "append(QByteArray const&)"); 41 QTest::newRow("member func 3") << "_ZN10QByteArray6numberEii" << (VB << "QByteArray" << "number(int, int)"); 42 QTest::newRow("ctor 1") << "_ZN10QByteArrayC1EPKci" << (VB << "QByteArray" << "QByteArray(char const*, int)"); 43 QTest::newRow("copy ctor 1") << "_ZN10QByteArrayC1ERKS_" << (VB << "QByteArray" << "QByteArray(QByteArray const&)"); 44 QTest::newRow("copy ctor 2") << "_ZN10QByteArrayC2ERKS_" << (VB << "QByteArray" << "QByteArray(QByteArray const&)"); 45 QTest::newRow("dtor 1") << "_ZN10QByteArrayD1Ev" << (VB << "QByteArray" << "~QByteArray()"); 46 QTest::newRow("dtor 2") << "_ZN10QByteArrayD2Ev" << (VB << "QByteArray" << "~QByteArray()"); 47 48 QTest::newRow("operator 1") << "_ZN10QByteArraypLERKS_" << (VB << "QByteArray" << "operator+=(QByteArray const&)"); 49 QTest::newRow("operator 2") << "_ZNK10QByteArraycvPKcEv" << (VB << "QByteArray" << "operator char const*() const"); 50 QTest::newRow("operator 3") << "_ZN7QStringaSEOS_" << (VB << "QString" << "operator=(QString&&)"); 51 52 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 24) 53 QTest::newRow("rvalue ref on this") << "_ZNO7QString11toLocal8BitEv" << (VB << "QString" << "toLocal8Bit() &&"); 54 #endif 55 56 QTest::newRow("template func 1") << "_Z13qGetPtrHelperI14QScopedPointerI11QObjectData21QScopedPointerDeleterIS1_EEENT_7pointerERKS5_" << (VB << "qGetPtrHelper" << "qGetPtrHelper<QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>>(QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>> const&)"); 57 QTest::newRow("template func 2") << "_ZN23QXmlStreamWriterPrivate5writeILi4EEEvRAT__Kc" << (VB << "QXmlStreamWriterPrivate" << "write" << "write<4>(char const (&) [4])"); 58 QTest::newRow("template func 3") << "_ZSt4moveIRP11TreeMapItemEONSt16remove_referenceIT_E4typeEOS4_" << (VB << "std" << "move" << "move<TreeMapItem*&>(TreeMapItem*&)"); 59 60 QTest::newRow("function pointer template") << "_ZN20QGlobalStaticDeleterI5QListIPFP7QObjectvEEED1Ev" << (VB << "QGlobalStaticDeleter" << "QGlobalStaticDeleter<QList<QObject* (*)()>>" << "~QGlobalStaticDeleter()"); 61 62 #if BINUTILS_VERSION < BINUTILS_VERSION_CHECK(2, 36) 63 QTest::newRow("lambda 1") << "_ZSt7find_ifIPKSt10shared_ptrI7ElfFileEZN10ElfFileSet7addFileERK7QStringEUlRS3_E_ET_SB_SB_T0_" << (VB << "std" << "find_if" << "find_if<std::shared_ptr<ElfFile> const*, ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1}>(ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1}, ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1}, ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1})"); 64 #else 65 QTest::newRow("lambda 1") << "_ZSt7find_ifIPKSt10shared_ptrI7ElfFileEZN10ElfFileSet7addFileERK7QStringEUlRS3_E_ET_SB_SB_T0_" << (VB << "std" << "find_if" << "find_if<std::shared_ptr<ElfFile> const*, ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1}>(std::shared_ptr<ElfFile> const*, std::shared_ptr<ElfFile> const*, ElfFileSet::addFile(QString const&)::{lambda(std::shared_ptr<ElfFile> const&)#1})"); 66 #endif 67 QTest::newRow("lambda 2") << "_ZZN13Ui_MainWindow7setupUiEP11QMainWindowENKUlvE5_clEv" << (VB << "Ui_MainWindow" << "setupUi(QMainWindow*)" << "{lambda()#7}" << "operator()() const"); 68 69 QTest::newRow("tmp 1") << "_Z27qRegisterNormalizedMetaTypeI7QVectorI10QByteArrayEEiRKS1_PT_N9QtPrivate21MetaTypeDefinedHelperIS5_Xaasr12QMetaTypeId2IS5_E7DefinedntsrSA_9IsBuiltInEE11DefinedTypeE" << (VB << "qRegisterNormalizedMetaType" << /*"qRegisterNormalizedMetaType<QVector<QByteArray>>(QByteArray const&, QVector<QByteArray>*, QtPrivate::MetaTypeDefinedHelper<QVector<QByteArray>, QMetaTypeId2<QVector<QByteArray>>::Defined&&(!QMetaTypeId2<QVector<QByteArray>>::IsBuiltIn)>::DefinedType)"*/ "qRegisterNormalizedMetaType<QVector<QByteArray>>(QByteArray const&, QVector<QByteArray>*, QtPrivate::MetaTypeDefinedHelper<QVector<QByteArray>, QMetaTypeId2<QVector<QByteArray>>::Defined&&!QMetaTypeId2<QVector<QByteArray>>::IsBuiltIn>::DefinedType)"); // TODO find a way to fix the parenthesis in unary/binary expressions 70 #if BINUTILS_VERSION < BINUTILS_VERSION_CHECK(2, 36) 71 QTest::newRow("tmp 2") << "_ZN7QObject7connectIM9QLineEditFvRK7QStringEZN10MainWindowC1EP7QWidgetEUlS4_E_EEN9QtPrivate9QEnableIfIXeqsrNSB_15FunctionPointerIT0_EE13ArgumentCountngLi1EEN11QMetaObject10ConnectionEE4TypeEPKNSD_IT_E6ObjectESK_PKS_SE_N2Qt14ConnectionTypeE" << (VB << "QObject" << "connect" << /*"connect<void (QLineEdit::*)(QString const&), MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}>(QtPrivate::QEnableIf<void (QLineEdit::*)(QString const&)>::Object const*, QtPrivate::QEnableIf<MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}::FunctionPointer<MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}>::ArgumentCount==(-(1)), QMetaObject::Connection>::Type, QObject const*, MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}::FunctionPointer, Qt::ConnectionType)"*/ "connect<void (QLineEdit::*)(QString const&), MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}>(QtPrivate::QEnableIf<void (QLineEdit::*)(QString const&)>::Object const*, QtPrivate::QEnableIf<MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}::FunctionPointer<MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}>::ArgumentCount==-1, QMetaObject::Connection>::Type, QObject const*, MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}::FunctionPointer, Qt::ConnectionType)"); // TODO fix parenthesis on -1 72 #else 73 QTest::newRow("tmp 2") << "_ZN7QObject7connectIM9QLineEditFvRK7QStringEZN10MainWindowC1EP7QWidgetEUlS4_E_EEN9QtPrivate9QEnableIfIXeqsrNSB_15FunctionPointerIT0_EE13ArgumentCountngLi1EEN11QMetaObject10ConnectionEE4TypeEPKNSD_IT_E6ObjectESK_PKS_SE_N2Qt14ConnectionTypeE" << (VB << "QObject" << "connect" << "connect<void (QLineEdit::*)(QString const&), MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}>(QtPrivate::FunctionPointer<void (QLineEdit::*)(QString const&)>::Object const*, void (QLineEdit::*)(QString const&), QObject const*, MainWindow::MainWindow(QWidget*)::{lambda(QString const&)#1}, Qt::ConnectionType)"); 74 #endif 75 76 QTest::newRow("pack 1") << "_ZSt12__get_helperILm0EPN2Ui10MainWindowEISt14default_deleteIS1_EEENSt9__add_refIT0_E4typeERSt11_Tuple_implIXT_EIS6_DpT1_EE" << (VB << "std" << "__get_helper" << "__get_helper<0ul, Ui::MainWindow*, std::default_delete<Ui::MainWindow>>(std::_Tuple_impl<0ul, Ui::MainWindow*, std::default_delete<Ui::MainWindow>>&)"); 77 QTest::newRow("pack 2") << "_ZN3WTF14NeverDestroyedINS_12_GLOBAL__N_125ARC4RandomNumberGeneratorEEC1IIEEEDpOT_" << (VB << "WTF" << "NeverDestroyed" << "NeverDestroyed<WTF::(anonymous namespace)::ARC4RandomNumberGenerator>" << "NeverDestroyed" << "NeverDestroyed<>()"); 78 79 QTest::newRow("vendor 1") << "_ZL18mergeQuestionMarksU8__vectorx" << (VB << "mergeQuestionMarks(long long __vector)"); 80 81 QTest::newRow("array no size") << "_ZN5boost6detail21sp_assert_convertibleIA_NS_18default_color_typeES3_EEvv" << (VB << "boost" << "detail" << "sp_assert_convertible" << "sp_assert_convertible<boost::default_color_type [], boost::default_color_type []>()"); 82 QTest::newRow("vector type") << "_ZN9QSimdSse25v_mulEDv4_fS0_" << (VB << "QSimdSse2" << "v_mul(float __vector(4), float __vector(4))"); 83 84 QTest::newRow("decltype in return") << "_ZNSt16allocator_traitsISaIiEE9constructIiJRKiEEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS0_PT_DpOS5_" << (VB << "std" << "allocator_traits" << "allocator_traits<std::allocator<int>>" << "construct" << "construct<int, int const&>(std::allocator<int>&, int*, int const&)"); 85 QTest::newRow("decltype with binary op") << "_ZSt5beginI7QVectorIP7ElfFileEEDTcldtfp_5beginEERT_" << (VB << "std" << "begin" << "begin<QVector<ElfFile*>>(QVector<ElfFile*>&)"); 86 87 QTest::newRow("typeinfo") << "_ZTI14ElfNodeVisitorIiE" << (VB << "ElfNodeVisitor" << "ElfNodeVisitor<int>" << "typeinfo"); 88 QTest::newRow("typeinfo name") << "_ZTS26KRecursiveFilterProxyModel" << (VB << "KRecursiveFilterProxyModel" << "typeinfo name"); 89 QTest::newRow("vtable") << "_ZTV17ElfDynamicSection" << (VB << "ElfDynamicSection" << "vtable"); 90 QTest::newRow("thunk") << "_ZThn16_N13TreeMapWidgetD0Ev" << (VB << "TreeMapWidget" << "~TreeMapWidget()" << "thunk"); 91 QTest::newRow("virtual thunk") << "_ZTv0_n24_N5Solid6Ifaces11OpticalDiscD1Ev" << (VB << "Solid" << "Ifaces" << "OpticalDisc" << "~OpticalDisc()" << "virtual thunk"); 92 QTest::newRow("covariant thunk") << "_ZTch0_h16_NK12ThreadWeaver15WeaverImplState6weaverEv" << (VB << "ThreadWeaver" << "WeaverImplState" << "weaver() const" << "covariant return thunk"); 93 QTest::newRow("vtt") << "_ZTTN5Solid6Ifaces13StorageVolumeE" << (VB << "Solid" << "Ifaces" << "StorageVolume" << "vtt"); 94 QTest::newRow("construction vtable") << "_ZTCN5Solid8Backends7UDisks211OpticalDiscE0_NS1_5BlockE" << (VB << "Solid" << "Backends" << "UDisks2" << "Block" << "construction vtable in Solid::Backends::UDisks2::OpticalDisc"); 95 96 QTest::newRow("guard variable") << "_ZGVZN12_GLOBAL__N_119Q_QGS_s_parsingData13innerFunctionEvE6holder" << (VB << "(anonymous namespace)" << "Q_QGS_s_parsingData" << "innerFunction()" << "holder" << "guard variable"); 97 QTest::newRow("reference temporary") << "_ZGRZNK16KateHighlighting10canBreakAtE5QChariE2sq0" << (VB << "KateHighlighting" << "canBreakAt(QChar, int) const" << "sq" << "reference temporary #0"); 98 QTest::newRow("unnamed type") << "_ZN24QVariantAnimationPrivateUt_D1Ev" << (VB << "QVariantAnimationPrivate" << "{unnamed type#1}" << "~QVariantAnimationPrivate()"); 99 100 QTest::newRow("literal bool") << "_ZNSt10_Iter_baseIPN3QV45ValueELb0EE7_S_baseES2_" << (VB << "std" << "_Iter_base" << "_Iter_base<QV4::Value*, false>" << "_S_base(QV4::Value*)"); 101 QTest::newRow("literal custom") << "_ZSt10_ConstructIN3JSC4Yarr13YarrGeneratorILNS1_18YarrJITCompileModeE0EE6YarrOpEIS5_EEvPT_DpOT0_" << (VB << "std" << "_Construct" << "_Construct<JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::YarrOp, JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::YarrOp>(JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::YarrOp*, JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::YarrOp&&)"); 102 QTest::newRow("literal neg int") << "_ZNK7WebCore17CSSPrimitiveValue15convertToLengthILin1EEENS_6LengthEPKNS_11RenderStyleES5_db" << (VB << "WebCore" << "CSSPrimitiveValue" << "convertToLength" << "convertToLength<-1>(WebCore::RenderStyle const*, WebCore::RenderStyle const*, double, bool) const"); 103 104 QTest::newRow("cloned component") << "_ZN7QVectorIjE16defaultConstructEPjS1_.isra.2" << (VB << "QVector" << "QVector<unsigned int>" << "defaultConstruct(unsigned int*, unsigned int*) [clone .isra.2]"); 105 106 QTest::newRow("nested types") << "_ZN7QVectorIPZN10MainWindow8loadFileERK7QStringE10SymbolNodeE4dataEv" << (VB << "QVector" << "QVector<MainWindow::loadFile(QString const&)::SymbolNode*>" << "data()"); 107 108 QTest::newRow("default argument") << "_ZZN8KDevelop18SourceFileTemplate22setTemplateDescriptionERK7QStringS3_Ed_NKUlvE_clEv" << (VB << "KDevelop" << "SourceFileTemplate" << "setTemplateDescription(QString const&, QString const&)" << "{default arg#1}" << "{lambda()#1}" << "operator()() const"); 109 110 QTest::newRow("abi tag") << "_ZNK5ZXing6Result4textB5cxx11Ev" << (VB << "ZXing" << "Result" << "text[abi:cxx11]() const"); 111 112 QTest::newRow("transaction clone") << "_ZGTtNSt11logic_errorC1EPKc.cold.14" << (VB << "std" << "logic_error" << "transaction clone for logic_error(char const*) [clone .cold.14]"); 113 114 QTest::newRow("initializer list") << "_Z1fP1BIXtl1ALi1EEEE" << (VB << "f(B<A{1}>*)"); 115 QTest::newRow("template parameter object") << "_ZTAXtl1ALi1EEE" << (VB << "template parameter object for A{1}"); 116 117 QTest::newRow("noexcept") << "_ZSt9__find_ifIPKcN9__gnu_cxx5__ops12_Iter_negateIPDoFiiEEEET_S8_S8_T0_St26random_access_iterator_tag.isra.0" 118 << (VB << "std" << "__find_if" << "__find_if<char const*, __gnu_cxx::__ops::_Iter_negate<int (*)(int) noexcept>>(char const*, char const*, __gnu_cxx::__ops::_Iter_negate<int (*)(int) noexcept>, std::random_access_iterator_tag) [clone .isra.0]"); 119 } 120 testDemangler()121 void testDemangler() 122 { 123 QFETCH(QString, mangled); 124 QFETCH(QVector<QByteArray>, expectedDemangled); 125 126 Demangler d; 127 auto actualDemangled = d.demangle(mangled.toLatin1()); 128 if (actualDemangled != expectedDemangled) { 129 qDebug() << actualDemangled; 130 qDebug() << expectedDemangled; 131 } 132 QEXPECT_FAIL("nested types", "bug in pointer handling", Continue); 133 QCOMPARE(actualDemangled, expectedDemangled); 134 } 135 testSymbolType_data()136 void testSymbolType_data() 137 { 138 QTest::addColumn<QByteArray>("symbol"); 139 QTest::addColumn<Demangler::SymbolType>("type"); 140 141 QTest::newRow("empty") << QByteArray("") << Demangler::SymbolType::Normal; 142 QTest::newRow("C") << QByteArray("malloc") << Demangler::SymbolType::Normal; 143 QTest::newRow("C++") << QByteArray("_ZN10QArrayData4dataEv") << Demangler::SymbolType::Normal; 144 145 QTest::newRow("vtable") << QByteArray("_ZTV17ElfDynamicSection") << Demangler::SymbolType::VTable; 146 QTest::newRow("typeinfo") << QByteArray("_ZTI14ElfNodeVisitorIiE") << Demangler::SymbolType::TypeInfo; 147 QTest::newRow("typeinfo name") << QByteArray("_ZTS26KRecursiveFilterProxyModel") << Demangler::SymbolType::TypeInfoName; 148 // QTest::newRow("thunk") << QByteArray("_ZThn16_N13TreeMapWidgetD0Ev") << Demangler::SymbolType::Thunk; 149 // QTest::newRow("virtual thunk") << QByteArray("_ZTv0_n24_N5Solid6Ifaces11OpticalDiscD1Ev") << Demangler::SymbolType::VirtualThunk; 150 // QTest::newRow("covariant thunk") << QByteArray("_ZTch0_h16_NK12ThreadWeaver15WeaverImplState6weaverEv") << Demangler::SymbolType::CovariantThunk; 151 QTest::newRow("vtt") << QByteArray("_ZTTN5Solid6Ifaces13StorageVolumeE") << Demangler::SymbolType::VTT; 152 QTest::newRow("construction vtable") << QByteArray("_ZTCN5Solid8Backends7UDisks211OpticalDiscE0_NS1_5BlockE") << Demangler::SymbolType::ConstructionVTable; 153 } 154 testSymbolType()155 void testSymbolType() 156 { 157 QFETCH(QByteArray, symbol); 158 QFETCH(Demangler::SymbolType, type); 159 160 QCOMPARE(Demangler::symbolType(symbol), type); 161 } 162 }; 163 164 QTEST_MAIN(DemanglerTest) 165 166 #include "demangler_test.moc" 167