File indexing completed on 2024-05-12 05:43:26

0001 /*
0002     Copyright (C) 2013-2014 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 <config-elf-dissector.h>
0019 #include "demangler.h"
0020 
0021 #include <QDebug>
0022 #include <QScopedValueRollback>
0023 
0024 // workarounds for conflicting declaration in libiberty.h
0025 #define HAVE_DECL_BASENAME 1
0026 #define HAVE_DECL_ASPRINTF 1
0027 #define HAVE_DECL_VASPRINTF 1
0028 
0029 #include <demangle.h>
0030 
0031 
0032 QVector<QByteArray> Demangler::demangle(const char* name)
0033 {
0034     QScopedValueRollback<const char*> mangledName(m_mangledName, name);
0035 
0036     void *memory = nullptr;
0037     demangle_component *component = cplus_demangle_v3_components(name, DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, &memory);
0038 
0039     QVector<QByteArray> result;
0040     if (!memory || !component) { // demangle failed, likely not mangled
0041         result.push_back(name);
0042         return result;
0043     }
0044 
0045     reset();
0046     handleNameComponent(component, result);
0047     free(memory);
0048     return result;
0049 }
0050 
0051 QByteArray Demangler::demangleFull(const char* name)
0052 {
0053     void *memory = nullptr;
0054     demangle_component *component = cplus_demangle_v3_components(name, DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, &memory);
0055 
0056     size_t size;
0057     char * fullName = cplus_demangle_print(DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, component, strlen(name), &size);
0058     const QByteArray b(fullName);
0059 
0060     free(fullName);
0061     free(memory);
0062 
0063     if (b.isEmpty())
0064         return name;
0065     return b;
0066 }
0067 
0068 void Demangler::reset()
0069 {
0070     m_inArgList = false;
0071     m_templateParamIndex = 0;
0072     m_templateParams.clear();
0073     m_pendingPointer = false;
0074     m_pendingReference = false;
0075 }
0076 
0077 // not in a public binutils header, but needed anyway
0078 struct demangle_operator_info
0079 {
0080     const char *type;
0081     const char *name;
0082     int len;
0083     int args;
0084 };
0085 
0086 struct demangle_builtin_type_info {
0087     const char *name;
0088     int len;
0089     const char *java_name;
0090     int java_len;
0091     /*enum d_builtin_type_print*/ int print;
0092 };
0093 
0094 static QByteArray join(const QVector<QByteArray> &v, const QByteArray &sep)
0095 {
0096     QByteArray res;
0097     for (auto it  = v.begin(); it != v.end(); ++it) {
0098         if (it != v.begin())
0099             res += sep;
0100         res += *it;
0101     }
0102     return res;
0103 }
0104 
0105 void Demangler::handleNameComponent(demangle_component* component, QVector< QByteArray >& nameParts)
0106 {
0107     // TODO: complete the component types
0108     switch (component->type) {
0109         case DEMANGLE_COMPONENT_NAME:
0110             nameParts.push_back(QByteArray(component->u.s_name.s, component->u.s_name.len));
0111             break;
0112         case DEMANGLE_COMPONENT_QUAL_NAME:
0113             handleNameComponent(component->u.s_binary.left, nameParts);
0114             handleNameComponent(component->u.s_binary.right, nameParts);
0115             if (m_inArgList) {
0116                 const QByteArray name = nameParts.takeLast();
0117                 const QByteArray ns = nameParts.takeLast();
0118                 nameParts.push_back(ns + "::" + name);
0119             }
0120             break;
0121         case DEMANGLE_COMPONENT_LOCAL_NAME:
0122             handleNameComponent(component->u.s_binary.left, nameParts);
0123             handleNameComponent(component->u.s_binary.right, nameParts);
0124             if (m_inArgList) {
0125                 const QByteArray name = nameParts.takeLast();
0126                 const QByteArray ns = nameParts.takeLast();
0127                 nameParts.push_back(ns + "::" + name);
0128             }
0129             break;
0130         case DEMANGLE_COMPONENT_TYPED_NAME:
0131         {
0132             // template parameters are indexed per enclosing type name, so push that on the stack here
0133             QScopedValueRollback<int> indexRestter(m_templateParamIndex, 0);
0134             QScopedValueRollback<QHash<int, QByteArray>> paramsResetter(m_templateParams);
0135             QScopedValueRollback<bool> shouldIndexResetter(m_indexTemplateArgs, true);
0136             QScopedValueRollback<QByteArray> modifierResetter(m_modifiers);
0137             m_templateParams.clear();
0138             m_modifiers.clear();
0139 
0140             // left is the name of the function, right is the return type (ignored here) and arguments
0141             handleNameComponent(component->u.s_binary.left, nameParts);
0142             QVector<QByteArray> args;
0143             handleNameComponent(component->u.s_binary.right, args);
0144             if (!nameParts.isEmpty() && !args.isEmpty())
0145                 nameParts.last().append(args.last() + m_modifiers);
0146             break;
0147         }
0148         case DEMANGLE_COMPONENT_TEMPLATE:
0149         {
0150             {
0151                 QScopedValueRollback<bool> indexRestter(m_indexTemplateArgs, false);
0152                 handleNameComponent(component->u.s_binary.left, nameParts);
0153             }
0154             QVector<QByteArray> args;
0155             handleNameComponent(component->u.s_binary.right, args);
0156             const QByteArray fullTemplate = nameParts.last() + '<' + join(args, ", ") + '>';
0157             if (m_inArgList) // we only want the template grouping on top-level
0158                 nameParts.removeLast();
0159             nameParts.push_back(fullTemplate);
0160             break;
0161         }
0162         case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
0163             nameParts.push_back(m_templateParams.value(component->u.s_number.number));
0164             break;
0165         case DEMANGLE_COMPONENT_FUNCTION_PARAM:
0166             // no idea what this means, but that's what c++filt is outputting for these...
0167             nameParts.push_back(QByteArray("{parm#") + QByteArray::number((int)component->u.s_number.number) + '}');
0168             break;
0169         case DEMANGLE_COMPONENT_CTOR:
0170             // TODO: do we need to consider u.s_ctor.kind?
0171             handleNameComponent(component->u.s_ctor.name, nameParts);
0172             break;
0173         case DEMANGLE_COMPONENT_DTOR:
0174             // TODO: do we need to consider u.s_dtor.kind?
0175             handleNameComponent(component->u.s_dtor.name, nameParts);
0176             nameParts.last().prepend('~');
0177             break;
0178         case DEMANGLE_COMPONENT_VTABLE:
0179             handleNameComponent(component->u.s_binary.left, nameParts);
0180             nameParts.push_back("vtable");
0181             break;
0182         case DEMANGLE_COMPONENT_VTT:
0183             handleNameComponent(component->u.s_binary.left, nameParts);
0184             nameParts.push_back("vtt"); // what's this?
0185             break;
0186         case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
0187         {
0188             handleNameComponent(component->u.s_binary.left, nameParts);
0189             QVector<QByteArray> tmp;
0190             handleNameComponent(component->u.s_binary.right, tmp);
0191             nameParts.push_back("construction vtable in " + join(tmp, "::"));
0192             break;
0193         }
0194         case DEMANGLE_COMPONENT_TYPEINFO:
0195             handleNameComponent(component->u.s_binary.left, nameParts);
0196             nameParts.push_back("typeinfo");
0197             break;
0198         case DEMANGLE_COMPONENT_TYPEINFO_NAME:
0199             handleNameComponent(component->u.s_binary.left, nameParts);
0200             nameParts.push_back("typeinfo name");
0201             break;
0202         case DEMANGLE_COMPONENT_TYPEINFO_FN:
0203             handleNameComponent(component->u.s_binary.left, nameParts);
0204             nameParts.push_back("typeinfo function");
0205             break;
0206         case DEMANGLE_COMPONENT_THUNK:
0207             handleNameComponent(component->u.s_binary.left, nameParts);
0208             nameParts.push_back("thunk");
0209             break;
0210         case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
0211             handleNameComponent(component->u.s_binary.left, nameParts);
0212             nameParts.push_back("virtual thunk");
0213             break;
0214         case DEMANGLE_COMPONENT_COVARIANT_THUNK:
0215             handleNameComponent(component->u.s_binary.left, nameParts);
0216             nameParts.push_back("covariant return thunk");
0217             break;
0218         case DEMANGLE_COMPONENT_GUARD:
0219             handleNameComponent(component->u.s_binary.left, nameParts);
0220             nameParts.push_back("guard variable");
0221             break;
0222         case DEMANGLE_COMPONENT_REFTEMP:
0223         {
0224             handleNameComponent(component->u.s_binary.left, nameParts);
0225             QVector<QByteArray> tmp;
0226             handleNameComponent(component->u.s_binary.right, tmp);
0227             nameParts.push_back("reference temporary #" + tmp.last());
0228             break;
0229         }
0230         case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
0231             handleNameComponent(component->u.s_binary.left, nameParts);
0232             nameParts.push_back("hidden alias");
0233             break;
0234         case DEMANGLE_COMPONENT_SUB_STD:
0235             nameParts.push_back(QByteArray(component->u.s_name.s, component->u.s_name.len));
0236             break;
0237         case DEMANGLE_COMPONENT_RESTRICT:
0238             handleNameComponent(component->u.s_binary.left, nameParts);
0239             nameParts.last().append(" restrict");
0240             break;
0241         case DEMANGLE_COMPONENT_VOLATILE:
0242             handleNameComponent(component->u.s_binary.left, nameParts);
0243             nameParts.last().append(" volatile");
0244             break;
0245         case DEMANGLE_COMPONENT_CONST:
0246             handleNameComponent(component->u.s_binary.left, nameParts);
0247             nameParts.last().append(" const");
0248             break;
0249         case DEMANGLE_COMPONENT_RESTRICT_THIS:
0250             handleNameComponent(component->u.s_binary.left, nameParts);
0251             m_modifiers.append(" restrict");
0252             break;
0253         case DEMANGLE_COMPONENT_VOLATILE_THIS:
0254             handleNameComponent(component->u.s_binary.left, nameParts);
0255             m_modifiers.append(" volatile");
0256             break;
0257         case DEMANGLE_COMPONENT_CONST_THIS:
0258             handleNameComponent(component->u.s_binary.left, nameParts);
0259             m_modifiers.append(" const");
0260             break;
0261 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 24)
0262         case DEMANGLE_COMPONENT_REFERENCE_THIS:
0263             handleNameComponent(component->u.s_binary.left, nameParts);
0264             m_modifiers.append(" &");
0265             break;
0266         case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
0267             handleNameComponent(component->u.s_binary.left, nameParts);
0268             m_modifiers.append(" &&");
0269             break;
0270 #endif
0271         case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
0272         {
0273             QVector<QByteArray> parts;
0274             handleNameComponent(component->u.s_binary.left, parts);
0275             handleNameComponent(component->u.s_binary.right, parts);
0276             nameParts.push_back(parts.first() + ' ' + parts.last());
0277             break;
0278         }
0279         case DEMANGLE_COMPONENT_POINTER:
0280         {
0281             QScopedValueRollback<bool> resetter(m_pendingPointer, true);
0282             handleNameComponent(component->u.s_binary.left, nameParts);
0283             if (m_pendingPointer) // not consumed by a function pointer
0284                 nameParts.last().append('*');
0285             break;
0286         }
0287         case DEMANGLE_COMPONENT_REFERENCE:
0288         {
0289             QScopedValueRollback<bool> resetter(m_pendingReference, true);
0290             handleNameComponent(component->u.s_binary.left, nameParts);
0291             if (m_pendingReference && !nameParts.last().endsWith('&')) // not consumed by the array type, and primitive reference collapsing
0292                 nameParts.last().append('&');
0293             break;
0294         }
0295         case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
0296             handleNameComponent(component->u.s_binary.left, nameParts);
0297             // skip appending &&
0298             // - in case of reference collapsing (TODO: this should be done on the tree, not the string)
0299             // - if we have an empty template arg in a pack expansion
0300             if (!nameParts.last().endsWith('&') && !nameParts.last().isEmpty())
0301                 nameParts.last().append("&&");
0302             break;
0303         case DEMANGLE_COMPONENT_BUILTIN_TYPE:
0304             nameParts.push_back(QByteArray(component->u.s_builtin.type->name, component->u.s_builtin.type->len));
0305             break;
0306         case DEMANGLE_COMPONENT_FUNCTION_TYPE:
0307         {
0308             const bool previousPendingPointer = m_pendingPointer;
0309             m_pendingPointer = false;
0310 
0311             // left is return type (only relevant in argument lists), right is the (optional) argument list
0312             QVector<QByteArray> returnType;
0313             handleOptionalNameComponent(component->u.s_binary.left, returnType);
0314 
0315             QVector<QByteArray> args;
0316             handleOptionalNameComponent(component->u.s_binary.right, args);
0317             QByteArray fullName;
0318             if (m_inArgList && !returnType.isEmpty())
0319                 fullName.prepend(returnType.last() + ' ');
0320             if (previousPendingPointer) { // function pointer
0321                 fullName.append("(*)");
0322             } else if (!m_ptrmemType.isEmpty()) {
0323                 fullName.append('(' + m_ptrmemType + "::*)");
0324             } else {
0325                 m_pendingPointer = previousPendingPointer;
0326             }
0327             fullName.append('(' + join(args, ", ") + ')');
0328             nameParts.push_back(fullName);
0329             break;
0330         }
0331         case DEMANGLE_COMPONENT_ARRAY_TYPE:
0332         {
0333             const bool prevRef = m_pendingReference;
0334             m_pendingReference = false;
0335             // left is optional dimension, right is type
0336             handleNameComponent(component->u.s_binary.right, nameParts);
0337             QVector<QByteArray> dim;
0338             handleOptionalNameComponent(component->u.s_binary.left, dim);
0339             QByteArray suffix;
0340             if (prevRef) {
0341                 suffix += " (&)"; // array references are special...
0342             } else {
0343                 m_pendingReference = prevRef;
0344             }
0345             suffix += " [";
0346             if (!dim.isEmpty())
0347                 suffix.append(dim.last());
0348             suffix += ']';
0349             nameParts.last().append(suffix);
0350             break;
0351         }
0352         case DEMANGLE_COMPONENT_PTRMEM_TYPE:
0353         {
0354             QScopedValueRollback<QByteArray> ptrmemTypeResetter(m_ptrmemType);
0355             m_ptrmemType.clear();
0356             QVector<QByteArray> tmp;
0357             handleNameComponent(component->u.s_binary.left, tmp);
0358             m_ptrmemType = tmp.last();
0359             handleNameComponent(component->u.s_binary.right, nameParts);
0360             break;
0361         }
0362         case DEMANGLE_COMPONENT_VECTOR_TYPE:
0363         {
0364             QVector<QByteArray> parts;
0365             // left is size, right is type
0366             handleNameComponent(component->u.s_binary.left, parts);
0367             handleNameComponent(component->u.s_binary.right, parts);
0368             nameParts.push_back(parts.last() + " __vector(" + parts.first() + ')');
0369             break;
0370         }
0371         case DEMANGLE_COMPONENT_ARGLIST:
0372         {
0373             QScopedValueRollback<bool> resetter(m_inArgList, true);
0374             if (!component->u.s_binary.left && !component->u.s_binary.right) {
0375                 nameParts.push_back(QByteArray("")); // empty arg list
0376             } else {
0377                 handleOptionalNameComponent(component->u.s_binary.left, nameParts);
0378                 handleOptionalNameComponent(component->u.s_binary.right, nameParts);
0379             }
0380             break;
0381         }
0382         case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
0383         {
0384             QScopedValueRollback<bool> resetter(m_inArgList, true);
0385 
0386             if (component->u.s_binary.left) {
0387                 int currentIndex = -1;
0388                 if (m_indexTemplateArgs)
0389                     currentIndex = m_templateParamIndex++;
0390                 QVector<QByteArray> left;
0391                 {
0392                     QScopedValueRollback<bool> resetter(m_indexTemplateArgs, false);
0393                     handleNameComponent(component->u.s_binary.left, left);
0394                 }
0395                 nameParts += left;
0396                 if (m_indexTemplateArgs) {
0397                     Q_ASSERT(currentIndex >= 0);
0398                     if (left.isEmpty())
0399                         m_templateParams.insert(currentIndex, QByteArray()); // empty template arg, might be referenced from elsewhere...
0400                     else
0401                         m_templateParams.insert(currentIndex, nameParts.last());
0402                 }
0403             }
0404 
0405             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
0406             break;
0407         }
0408 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 32)
0409         case DEMANGLE_COMPONENT_TPARM_OBJ:
0410             handleNameComponent(component->u.s_binary.left, nameParts);
0411             nameParts.last().prepend(QByteArray("template parameter object for "));
0412             break;
0413 #endif
0414 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
0415         case DEMANGLE_COMPONENT_INITIALIZER_LIST:
0416     {
0417             QVector<QByteArray> parts;
0418         handleNameComponent(component->u.s_binary.left, parts);
0419             handleNameComponent(component->u.s_binary.right, parts);
0420         nameParts.push_back(parts.at(0) + "{" + parts.at(1) + "}");
0421         break;
0422     }
0423 #endif
0424         case DEMANGLE_COMPONENT_OPERATOR:
0425             nameParts.push_back(QByteArray("operator") + QByteArray(component->u.s_operator.op->name, component->u.s_operator.op->len));
0426             break;
0427         case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
0428             handleNameComponent(component->u.s_extended_operator.name, nameParts);
0429             break;
0430         case DEMANGLE_COMPONENT_CAST:
0431             handleNameComponent(component->u.s_binary.left, nameParts);
0432             nameParts.last().prepend("operator ");
0433             break;
0434 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 26)
0435         case DEMANGLE_COMPONENT_CONVERSION:
0436             handleNameComponent(component->u.s_binary.left, nameParts);
0437             nameParts.last().prepend("operator ");
0438             break;
0439 #endif
0440 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
0441         case DEMANGLE_COMPONENT_NULLARY:
0442             handleNameComponent(component->u.s_binary.left, nameParts);
0443             break;
0444 #endif
0445         case DEMANGLE_COMPONENT_UNARY:
0446         {
0447             handleOperatorComponent(component->u.s_binary.left, nameParts);
0448             handleNameComponent(component->u.s_binary.right, nameParts);
0449             const QByteArray arg = nameParts.takeLast();
0450             const QByteArray op = nameParts.takeLast();
0451             nameParts.push_back(op + arg);
0452             break;
0453         }
0454         case DEMANGLE_COMPONENT_BINARY:
0455         {
0456             handleOperatorComponent(component->u.s_binary.left, nameParts);
0457             handleNameComponent(component->u.s_binary.right, nameParts);
0458             const QByteArray arg2 = nameParts.takeLast();
0459             const QByteArray arg1 = nameParts.takeLast();
0460             const QByteArray op = nameParts.takeLast();
0461             nameParts.push_back(arg1 + op + arg2);
0462             break;
0463         }
0464         case DEMANGLE_COMPONENT_BINARY_ARGS:
0465         case DEMANGLE_COMPONENT_TRINARY:
0466         case DEMANGLE_COMPONENT_TRINARY_ARG1:
0467         case DEMANGLE_COMPONENT_TRINARY_ARG2:
0468             handleNameComponent(component->u.s_binary.left, nameParts);
0469             handleNameComponent(component->u.s_binary.right, nameParts);
0470             break;
0471         case DEMANGLE_COMPONENT_LITERAL:
0472         case DEMANGLE_COMPONENT_LITERAL_NEG:
0473         {
0474             // left is type, right is value
0475             QVector<QByteArray> type;
0476             handleNameComponent(component->u.s_binary.left, type);
0477             handleNameComponent(component->u.s_binary.right, type);
0478             if (component->type == DEMANGLE_COMPONENT_LITERAL_NEG)
0479                 type.last().prepend('-');
0480             QByteArray typeStr;
0481             // TODO add: unsigned, long, long long, unsigned long long
0482             if (type.first() == "bool") {
0483                 typeStr = type.last() == "0" ? "false" : "true";
0484             } else if (type.first() == "int") {
0485                 typeStr = type.last();
0486             } else if (type.first() == "unsigned long") {
0487                 typeStr = type.last() + "ul";
0488             } else { // custom type
0489                 typeStr = '(' + type.first() + ')' + type.last();
0490             }
0491             nameParts.push_back(typeStr);
0492             break;
0493         }
0494         case DEMANGLE_COMPONENT_NUMBER:
0495             nameParts.push_back(QByteArray::number((int)component->u.s_number.number));
0496             break;
0497         case DEMANGLE_COMPONENT_DECLTYPE:
0498             // TODO: undocumented, but one seems to contain content at least
0499             handleOptionalNameComponent(component->u.s_binary.left, nameParts);
0500             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
0501             break;
0502         case DEMANGLE_COMPONENT_LAMBDA:
0503         {
0504             QVector<QByteArray> args;
0505             handleNameComponent(component->u.s_unary_num.sub, args);
0506             nameParts.push_back("{lambda(" + join(args, ", ") + ")#" + QByteArray::number(component->u.s_unary_num.num + 1) + '}');
0507             break;
0508         }
0509         case DEMANGLE_COMPONENT_DEFAULT_ARG:
0510             nameParts.push_back(QByteArray("{default arg#") + QByteArray::number((int)component->u.s_unary_num.num + 1) + '}');
0511             handleOptionalNameComponent(component->u.s_unary_num.sub, nameParts);
0512             break;
0513         case DEMANGLE_COMPONENT_UNNAMED_TYPE:
0514             nameParts.push_back(QByteArray("{unnamed type#") + QByteArray::number((int)component->u.s_number.number + 1) + '}');
0515             break;
0516 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
0517         case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
0518             handleNameComponent(component->u.s_binary.left, nameParts);
0519             nameParts.last().prepend("transaction clone for ");
0520             break;
0521         case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
0522             handleNameComponent(component->u.s_binary.left, nameParts);
0523             nameParts.last().prepend("non-transaction clone for ");
0524             break;
0525 #endif
0526         case DEMANGLE_COMPONENT_PACK_EXPANSION:
0527             handleOptionalNameComponent(component->u.s_binary.left, nameParts);
0528             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
0529             break;
0530 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 24)
0531         case DEMANGLE_COMPONENT_TAGGED_NAME:
0532         {
0533             QVector<QByteArray> args;
0534             handleNameComponent(component->u.s_binary.left, nameParts);
0535             handleNameComponent(component->u.s_binary.right, args);
0536             const auto n = nameParts.takeLast();
0537             nameParts.push_back(n + "[abi:" + args.last() + ']');
0538             break;
0539         }
0540 #endif
0541 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
0542         case DEMANGLE_COMPONENT_CLONE:
0543         {
0544             QVector<QByteArray> args;
0545             handleNameComponent(component->u.s_binary.left, nameParts);
0546             handleNameComponent(component->u.s_binary.right, args);
0547             const auto n = nameParts.takeLast();
0548             nameParts.push_back(n + " [clone " + args.last() + ']');
0549             break;
0550         }
0551 #endif
0552 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 28)
0553         case DEMANGLE_COMPONENT_NOEXCEPT:
0554         {
0555             handleNameComponent(component->u.s_binary.left, nameParts);
0556             const auto n = nameParts.takeLast();
0557             nameParts.push_back(n + " noexcept");
0558             break;
0559         }
0560 #endif
0561         default:
0562             qDebug() << Q_FUNC_INFO << "unhandled component type" << component->type << m_mangledName;
0563     }
0564 }
0565 
0566 void Demangler::handleOptionalNameComponent(demangle_component* component, QVector< QByteArray >& nameParts)
0567 {
0568     if (!component)
0569         return;
0570     handleNameComponent(component, nameParts);
0571 }
0572 
0573 void Demangler::handleOperatorComponent(demangle_component* component, QVector< QByteArray >& nameParts)
0574 {
0575     if (component->type == DEMANGLE_COMPONENT_OPERATOR) {
0576         nameParts.push_back(QByteArray(component->u.s_operator.op->name, component->u.s_operator.op->len));
0577         return;
0578     }
0579     handleNameComponent(component, nameParts);
0580 }
0581 
0582 Demangler::SymbolType Demangler::symbolType(const char* name)
0583 {
0584     if (strlen(name) < 4)
0585         return SymbolType::Normal;
0586     if (name[0] != '_' || name[1] != 'Z' || name[2] != 'T')
0587         return SymbolType::Normal;
0588 
0589     switch (name[3]) {
0590         case 'V': return SymbolType::VTable;
0591         case 'I': return SymbolType::TypeInfo;
0592         case 'S': return SymbolType::TypeInfoName;
0593         case 'T': return SymbolType::VTT;
0594         case 'C': return SymbolType::ConstructionVTable;
0595     }
0596 
0597     return SymbolType::Normal;
0598 }