1 /*
2     Copyright (C) 2013-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 #include "demangler.h"
20 
21 #include <QDebug>
22 #include <QScopedValueRollback>
23 
24 // workarounds for conflicting declaration in libiberty.h
25 #define HAVE_DECL_BASENAME 1
26 #define HAVE_DECL_ASPRINTF 1
27 #define HAVE_DECL_VASPRINTF 1
28 
29 #include <demangle.h>
30 
31 
demangle(const char * name)32 QVector<QByteArray> Demangler::demangle(const char* name)
33 {
34     QScopedValueRollback<const char*> mangledName(m_mangledName, name);
35 
36     void *memory = nullptr;
37     demangle_component *component = cplus_demangle_v3_components(name, DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, &memory);
38 
39     QVector<QByteArray> result;
40     if (!memory || !component) { // demangle failed, likely not mangled
41         result.push_back(name);
42         return result;
43     }
44 
45     reset();
46     handleNameComponent(component, result);
47     free(memory);
48     return result;
49 }
50 
demangleFull(const char * name)51 QByteArray Demangler::demangleFull(const char* name)
52 {
53     void *memory = nullptr;
54     demangle_component *component = cplus_demangle_v3_components(name, DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, &memory);
55 
56     size_t size;
57     char * fullName = cplus_demangle_print(DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | DMGL_VERBOSE, component, strlen(name), &size);
58     const QByteArray b(fullName);
59 
60     free(fullName);
61     free(memory);
62 
63     if (b.isEmpty())
64         return name;
65     return b;
66 }
67 
reset()68 void Demangler::reset()
69 {
70     m_inArgList = false;
71     m_templateParamIndex = 0;
72     m_templateParams.clear();
73     m_pendingPointer = false;
74     m_pendingReference = false;
75 }
76 
77 // not in a public binutils header, but needed anyway
78 struct demangle_operator_info
79 {
80     const char *type;
81     const char *name;
82     int len;
83     int args;
84 };
85 
86 struct demangle_builtin_type_info {
87     const char *name;
88     int len;
89     const char *java_name;
90     int java_len;
91     /*enum d_builtin_type_print*/ int print;
92 };
93 
join(const QVector<QByteArray> & v,const QByteArray & sep)94 static QByteArray join(const QVector<QByteArray> &v, const QByteArray &sep)
95 {
96     QByteArray res;
97     for (auto it  = v.begin(); it != v.end(); ++it) {
98         if (it != v.begin())
99             res += sep;
100         res += *it;
101     }
102     return res;
103 }
104 
handleNameComponent(demangle_component * component,QVector<QByteArray> & nameParts)105 void Demangler::handleNameComponent(demangle_component* component, QVector< QByteArray >& nameParts)
106 {
107     // TODO: complete the component types
108     switch (component->type) {
109         case DEMANGLE_COMPONENT_NAME:
110             nameParts.push_back(QByteArray(component->u.s_name.s, component->u.s_name.len));
111             break;
112         case DEMANGLE_COMPONENT_QUAL_NAME:
113             handleNameComponent(component->u.s_binary.left, nameParts);
114             handleNameComponent(component->u.s_binary.right, nameParts);
115             if (m_inArgList) {
116                 const QByteArray name = nameParts.takeLast();
117                 const QByteArray ns = nameParts.takeLast();
118                 nameParts.push_back(ns + "::" + name);
119             }
120             break;
121         case DEMANGLE_COMPONENT_LOCAL_NAME:
122             handleNameComponent(component->u.s_binary.left, nameParts);
123             handleNameComponent(component->u.s_binary.right, nameParts);
124             if (m_inArgList) {
125                 const QByteArray name = nameParts.takeLast();
126                 const QByteArray ns = nameParts.takeLast();
127                 nameParts.push_back(ns + "::" + name);
128             }
129             break;
130         case DEMANGLE_COMPONENT_TYPED_NAME:
131         {
132             // template parameters are indexed per enclosing type name, so push that on the stack here
133             QScopedValueRollback<int> indexRestter(m_templateParamIndex, 0);
134             QScopedValueRollback<QHash<int, QByteArray>> paramsResetter(m_templateParams);
135             QScopedValueRollback<bool> shouldIndexResetter(m_indexTemplateArgs, true);
136             QScopedValueRollback<QByteArray> modifierResetter(m_modifiers);
137             m_templateParams.clear();
138             m_modifiers.clear();
139 
140             // left is the name of the function, right is the return type (ignored here) and arguments
141             handleNameComponent(component->u.s_binary.left, nameParts);
142             QVector<QByteArray> args;
143             handleNameComponent(component->u.s_binary.right, args);
144             if (!nameParts.isEmpty() && !args.isEmpty())
145                 nameParts.last().append(args.last() + m_modifiers);
146             break;
147         }
148         case DEMANGLE_COMPONENT_TEMPLATE:
149         {
150             {
151                 QScopedValueRollback<bool> indexRestter(m_indexTemplateArgs, false);
152                 handleNameComponent(component->u.s_binary.left, nameParts);
153             }
154             QVector<QByteArray> args;
155             handleNameComponent(component->u.s_binary.right, args);
156             const QByteArray fullTemplate = nameParts.last() + '<' + join(args, ", ") + '>';
157             if (m_inArgList) // we only want the template grouping on top-level
158                 nameParts.removeLast();
159             nameParts.push_back(fullTemplate);
160             break;
161         }
162         case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
163             nameParts.push_back(m_templateParams.value(component->u.s_number.number));
164             break;
165         case DEMANGLE_COMPONENT_FUNCTION_PARAM:
166             // no idea what this means, but that's what c++filt is outputting for these...
167             nameParts.push_back(QByteArray("{parm#") + QByteArray::number((int)component->u.s_number.number) + '}');
168             break;
169         case DEMANGLE_COMPONENT_CTOR:
170             // TODO: do we need to consider u.s_ctor.kind?
171             handleNameComponent(component->u.s_ctor.name, nameParts);
172             break;
173         case DEMANGLE_COMPONENT_DTOR:
174             // TODO: do we need to consider u.s_dtor.kind?
175             handleNameComponent(component->u.s_dtor.name, nameParts);
176             nameParts.last().prepend('~');
177             break;
178         case DEMANGLE_COMPONENT_VTABLE:
179             handleNameComponent(component->u.s_binary.left, nameParts);
180             nameParts.push_back("vtable");
181             break;
182         case DEMANGLE_COMPONENT_VTT:
183             handleNameComponent(component->u.s_binary.left, nameParts);
184             nameParts.push_back("vtt"); // what's this?
185             break;
186         case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
187         {
188             handleNameComponent(component->u.s_binary.left, nameParts);
189             QVector<QByteArray> tmp;
190             handleNameComponent(component->u.s_binary.right, tmp);
191             nameParts.push_back("construction vtable in " + join(tmp, "::"));
192             break;
193         }
194         case DEMANGLE_COMPONENT_TYPEINFO:
195             handleNameComponent(component->u.s_binary.left, nameParts);
196             nameParts.push_back("typeinfo");
197             break;
198         case DEMANGLE_COMPONENT_TYPEINFO_NAME:
199             handleNameComponent(component->u.s_binary.left, nameParts);
200             nameParts.push_back("typeinfo name");
201             break;
202         case DEMANGLE_COMPONENT_TYPEINFO_FN:
203             handleNameComponent(component->u.s_binary.left, nameParts);
204             nameParts.push_back("typeinfo function");
205             break;
206         case DEMANGLE_COMPONENT_THUNK:
207             handleNameComponent(component->u.s_binary.left, nameParts);
208             nameParts.push_back("thunk");
209             break;
210         case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
211             handleNameComponent(component->u.s_binary.left, nameParts);
212             nameParts.push_back("virtual thunk");
213             break;
214         case DEMANGLE_COMPONENT_COVARIANT_THUNK:
215             handleNameComponent(component->u.s_binary.left, nameParts);
216             nameParts.push_back("covariant return thunk");
217             break;
218         case DEMANGLE_COMPONENT_GUARD:
219             handleNameComponent(component->u.s_binary.left, nameParts);
220             nameParts.push_back("guard variable");
221             break;
222         case DEMANGLE_COMPONENT_REFTEMP:
223         {
224             handleNameComponent(component->u.s_binary.left, nameParts);
225             QVector<QByteArray> tmp;
226             handleNameComponent(component->u.s_binary.right, tmp);
227             nameParts.push_back("reference temporary #" + tmp.last());
228             break;
229         }
230         case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
231             handleNameComponent(component->u.s_binary.left, nameParts);
232             nameParts.push_back("hidden alias");
233             break;
234         case DEMANGLE_COMPONENT_SUB_STD:
235             nameParts.push_back(QByteArray(component->u.s_name.s, component->u.s_name.len));
236             break;
237         case DEMANGLE_COMPONENT_RESTRICT:
238             handleNameComponent(component->u.s_binary.left, nameParts);
239             nameParts.last().append(" restrict");
240             break;
241         case DEMANGLE_COMPONENT_VOLATILE:
242             handleNameComponent(component->u.s_binary.left, nameParts);
243             nameParts.last().append(" volatile");
244             break;
245         case DEMANGLE_COMPONENT_CONST:
246             handleNameComponent(component->u.s_binary.left, nameParts);
247             nameParts.last().append(" const");
248             break;
249         case DEMANGLE_COMPONENT_RESTRICT_THIS:
250             handleNameComponent(component->u.s_binary.left, nameParts);
251             m_modifiers.append(" restrict");
252             break;
253         case DEMANGLE_COMPONENT_VOLATILE_THIS:
254             handleNameComponent(component->u.s_binary.left, nameParts);
255             m_modifiers.append(" volatile");
256             break;
257         case DEMANGLE_COMPONENT_CONST_THIS:
258             handleNameComponent(component->u.s_binary.left, nameParts);
259             m_modifiers.append(" const");
260             break;
261 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 24)
262         case DEMANGLE_COMPONENT_REFERENCE_THIS:
263             handleNameComponent(component->u.s_binary.left, nameParts);
264             m_modifiers.append(" &");
265             break;
266         case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
267             handleNameComponent(component->u.s_binary.left, nameParts);
268             m_modifiers.append(" &&");
269             break;
270 #endif
271         case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
272         {
273             QVector<QByteArray> parts;
274             handleNameComponent(component->u.s_binary.left, parts);
275             handleNameComponent(component->u.s_binary.right, parts);
276             nameParts.push_back(parts.first() + ' ' + parts.last());
277             break;
278         }
279         case DEMANGLE_COMPONENT_POINTER:
280         {
281             QScopedValueRollback<bool> resetter(m_pendingPointer, true);
282             handleNameComponent(component->u.s_binary.left, nameParts);
283             if (m_pendingPointer) // not consumed by a function pointer
284                 nameParts.last().append('*');
285             break;
286         }
287         case DEMANGLE_COMPONENT_REFERENCE:
288         {
289             QScopedValueRollback<bool> resetter(m_pendingReference, true);
290             handleNameComponent(component->u.s_binary.left, nameParts);
291             if (m_pendingReference && !nameParts.last().endsWith('&')) // not consumed by the array type, and primitive reference collapsing
292                 nameParts.last().append('&');
293             break;
294         }
295         case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
296             handleNameComponent(component->u.s_binary.left, nameParts);
297             // skip appending &&
298             // - in case of reference collapsing (TODO: this should be done on the tree, not the string)
299             // - if we have an empty template arg in a pack expansion
300             if (!nameParts.last().endsWith('&') && !nameParts.last().isEmpty())
301                 nameParts.last().append("&&");
302             break;
303         case DEMANGLE_COMPONENT_BUILTIN_TYPE:
304             nameParts.push_back(QByteArray(component->u.s_builtin.type->name, component->u.s_builtin.type->len));
305             break;
306         case DEMANGLE_COMPONENT_FUNCTION_TYPE:
307         {
308             const bool previousPendingPointer = m_pendingPointer;
309             m_pendingPointer = false;
310 
311             // left is return type (only relevant in argument lists), right is the (optional) argument list
312             QVector<QByteArray> returnType;
313             handleOptionalNameComponent(component->u.s_binary.left, returnType);
314 
315             QVector<QByteArray> args;
316             handleOptionalNameComponent(component->u.s_binary.right, args);
317             QByteArray fullName;
318             if (m_inArgList && !returnType.isEmpty())
319                 fullName.prepend(returnType.last() + ' ');
320             if (previousPendingPointer) { // function pointer
321                 fullName.append("(*)");
322             } else if (!m_ptrmemType.isEmpty()) {
323                 fullName.append('(' + m_ptrmemType + "::*)");
324             } else {
325                 m_pendingPointer = previousPendingPointer;
326             }
327             fullName.append('(' + join(args, ", ") + ')');
328             nameParts.push_back(fullName);
329             break;
330         }
331         case DEMANGLE_COMPONENT_ARRAY_TYPE:
332         {
333             const bool prevRef = m_pendingReference;
334             m_pendingReference = false;
335             // left is optional dimension, right is type
336             handleNameComponent(component->u.s_binary.right, nameParts);
337             QVector<QByteArray> dim;
338             handleOptionalNameComponent(component->u.s_binary.left, dim);
339             QByteArray suffix;
340             if (prevRef) {
341                 suffix += " (&)"; // array references are special...
342             } else {
343                 m_pendingReference = prevRef;
344             }
345             suffix += " [";
346             if (!dim.isEmpty())
347                 suffix.append(dim.last());
348             suffix += ']';
349             nameParts.last().append(suffix);
350             break;
351         }
352         case DEMANGLE_COMPONENT_PTRMEM_TYPE:
353         {
354             QScopedValueRollback<QByteArray> ptrmemTypeResetter(m_ptrmemType);
355             m_ptrmemType.clear();
356             QVector<QByteArray> tmp;
357             handleNameComponent(component->u.s_binary.left, tmp);
358             m_ptrmemType = tmp.last();
359             handleNameComponent(component->u.s_binary.right, nameParts);
360             break;
361         }
362         case DEMANGLE_COMPONENT_VECTOR_TYPE:
363         {
364             QVector<QByteArray> parts;
365             // left is size, right is type
366             handleNameComponent(component->u.s_binary.left, parts);
367             handleNameComponent(component->u.s_binary.right, parts);
368             nameParts.push_back(parts.last() + " __vector(" + parts.first() + ')');
369             break;
370         }
371         case DEMANGLE_COMPONENT_ARGLIST:
372         {
373             QScopedValueRollback<bool> resetter(m_inArgList, true);
374             if (!component->u.s_binary.left && !component->u.s_binary.right) {
375                 nameParts.push_back(QByteArray("")); // empty arg list
376             } else {
377                 handleOptionalNameComponent(component->u.s_binary.left, nameParts);
378                 handleOptionalNameComponent(component->u.s_binary.right, nameParts);
379             }
380             break;
381         }
382         case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
383         {
384             QScopedValueRollback<bool> resetter(m_inArgList, true);
385 
386             if (component->u.s_binary.left) {
387                 int currentIndex = -1;
388                 if (m_indexTemplateArgs)
389                     currentIndex = m_templateParamIndex++;
390                 QVector<QByteArray> left;
391                 {
392                     QScopedValueRollback<bool> resetter(m_indexTemplateArgs, false);
393                     handleNameComponent(component->u.s_binary.left, left);
394                 }
395                 nameParts += left;
396                 if (m_indexTemplateArgs) {
397                     Q_ASSERT(currentIndex >= 0);
398                     if (left.isEmpty())
399                         m_templateParams.insert(currentIndex, QByteArray()); // empty template arg, might be referenced from elsewhere...
400                     else
401                         m_templateParams.insert(currentIndex, nameParts.last());
402                 }
403             }
404 
405             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
406             break;
407         }
408 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 32)
409         case DEMANGLE_COMPONENT_TPARM_OBJ:
410             handleNameComponent(component->u.s_binary.left, nameParts);
411             nameParts.last().prepend(QByteArray("template parameter object for "));
412             break;
413 #endif
414 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
415         case DEMANGLE_COMPONENT_INITIALIZER_LIST:
416 	{
417             QVector<QByteArray> parts;
418 	    handleNameComponent(component->u.s_binary.left, parts);
419             handleNameComponent(component->u.s_binary.right, parts);
420 	    nameParts.push_back(parts.at(0) + "{" + parts.at(1) + "}");
421 	    break;
422 	}
423 #endif
424         case DEMANGLE_COMPONENT_OPERATOR:
425             nameParts.push_back(QByteArray("operator") + QByteArray(component->u.s_operator.op->name, component->u.s_operator.op->len));
426             break;
427         case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
428             handleNameComponent(component->u.s_extended_operator.name, nameParts);
429             break;
430         case DEMANGLE_COMPONENT_CAST:
431             handleNameComponent(component->u.s_binary.left, nameParts);
432             nameParts.last().prepend("operator ");
433             break;
434 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 26)
435         case DEMANGLE_COMPONENT_CONVERSION:
436             handleNameComponent(component->u.s_binary.left, nameParts);
437             nameParts.last().prepend("operator ");
438             break;
439 #endif
440 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
441         case DEMANGLE_COMPONENT_NULLARY:
442             handleNameComponent(component->u.s_binary.left, nameParts);
443             break;
444 #endif
445         case DEMANGLE_COMPONENT_UNARY:
446         {
447             handleOperatorComponent(component->u.s_binary.left, nameParts);
448             handleNameComponent(component->u.s_binary.right, nameParts);
449             const QByteArray arg = nameParts.takeLast();
450             const QByteArray op = nameParts.takeLast();
451             nameParts.push_back(op + arg);
452             break;
453         }
454         case DEMANGLE_COMPONENT_BINARY:
455         {
456             handleOperatorComponent(component->u.s_binary.left, nameParts);
457             handleNameComponent(component->u.s_binary.right, nameParts);
458             const QByteArray arg2 = nameParts.takeLast();
459             const QByteArray arg1 = nameParts.takeLast();
460             const QByteArray op = nameParts.takeLast();
461             nameParts.push_back(arg1 + op + arg2);
462             break;
463         }
464         case DEMANGLE_COMPONENT_BINARY_ARGS:
465         case DEMANGLE_COMPONENT_TRINARY:
466         case DEMANGLE_COMPONENT_TRINARY_ARG1:
467         case DEMANGLE_COMPONENT_TRINARY_ARG2:
468             handleNameComponent(component->u.s_binary.left, nameParts);
469             handleNameComponent(component->u.s_binary.right, nameParts);
470             break;
471         case DEMANGLE_COMPONENT_LITERAL:
472         case DEMANGLE_COMPONENT_LITERAL_NEG:
473         {
474             // left is type, right is value
475             QVector<QByteArray> type;
476             handleNameComponent(component->u.s_binary.left, type);
477             handleNameComponent(component->u.s_binary.right, type);
478             if (component->type == DEMANGLE_COMPONENT_LITERAL_NEG)
479                 type.last().prepend('-');
480             QByteArray typeStr;
481             // TODO add: unsigned, long, long long, unsigned long long
482             if (type.first() == "bool") {
483                 typeStr = type.last() == "0" ? "false" : "true";
484             } else if (type.first() == "int") {
485                 typeStr = type.last();
486             } else if (type.first() == "unsigned long") {
487                 typeStr = type.last() + "ul";
488             } else { // custom type
489                 typeStr = '(' + type.first() + ')' + type.last();
490             }
491             nameParts.push_back(typeStr);
492             break;
493         }
494         case DEMANGLE_COMPONENT_NUMBER:
495             nameParts.push_back(QByteArray::number((int)component->u.s_number.number));
496             break;
497         case DEMANGLE_COMPONENT_DECLTYPE:
498             // TODO: undocumented, but one seems to contain content at least
499             handleOptionalNameComponent(component->u.s_binary.left, nameParts);
500             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
501             break;
502         case DEMANGLE_COMPONENT_LAMBDA:
503         {
504             QVector<QByteArray> args;
505             handleNameComponent(component->u.s_unary_num.sub, args);
506             nameParts.push_back("{lambda(" + join(args, ", ") + ")#" + QByteArray::number(component->u.s_unary_num.num + 1) + '}');
507             break;
508         }
509         case DEMANGLE_COMPONENT_DEFAULT_ARG:
510             nameParts.push_back(QByteArray("{default arg#") + QByteArray::number((int)component->u.s_unary_num.num + 1) + '}');
511             handleOptionalNameComponent(component->u.s_unary_num.sub, nameParts);
512             break;
513         case DEMANGLE_COMPONENT_UNNAMED_TYPE:
514             nameParts.push_back(QByteArray("{unnamed type#") + QByteArray::number((int)component->u.s_number.number + 1) + '}');
515             break;
516 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
517         case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
518             handleNameComponent(component->u.s_binary.left, nameParts);
519             nameParts.last().prepend("transaction clone for ");
520             break;
521         case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
522             handleNameComponent(component->u.s_binary.left, nameParts);
523             nameParts.last().prepend("non-transaction clone for ");
524             break;
525 #endif
526         case DEMANGLE_COMPONENT_PACK_EXPANSION:
527             handleOptionalNameComponent(component->u.s_binary.left, nameParts);
528             handleOptionalNameComponent(component->u.s_binary.right, nameParts);
529             break;
530 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 24)
531         case DEMANGLE_COMPONENT_TAGGED_NAME:
532         {
533             QVector<QByteArray> args;
534             handleNameComponent(component->u.s_binary.left, nameParts);
535             handleNameComponent(component->u.s_binary.right, args);
536             const auto n = nameParts.takeLast();
537             nameParts.push_back(n + "[abi:" + args.last() + ']');
538             break;
539         }
540 #endif
541 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 23)
542         case DEMANGLE_COMPONENT_CLONE:
543         {
544             QVector<QByteArray> args;
545             handleNameComponent(component->u.s_binary.left, nameParts);
546             handleNameComponent(component->u.s_binary.right, args);
547             const auto n = nameParts.takeLast();
548             nameParts.push_back(n + " [clone " + args.last() + ']');
549             break;
550         }
551 #endif
552 #if BINUTILS_VERSION >= BINUTILS_VERSION_CHECK(2, 28)
553         case DEMANGLE_COMPONENT_NOEXCEPT:
554         {
555             handleNameComponent(component->u.s_binary.left, nameParts);
556             const auto n = nameParts.takeLast();
557             nameParts.push_back(n + " noexcept");
558             break;
559         }
560 #endif
561         default:
562             qDebug() << Q_FUNC_INFO << "unhandled component type" << component->type << m_mangledName;
563     }
564 }
565 
handleOptionalNameComponent(demangle_component * component,QVector<QByteArray> & nameParts)566 void Demangler::handleOptionalNameComponent(demangle_component* component, QVector< QByteArray >& nameParts)
567 {
568     if (!component)
569         return;
570     handleNameComponent(component, nameParts);
571 }
572 
handleOperatorComponent(demangle_component * component,QVector<QByteArray> & nameParts)573 void Demangler::handleOperatorComponent(demangle_component* component, QVector< QByteArray >& nameParts)
574 {
575     if (component->type == DEMANGLE_COMPONENT_OPERATOR) {
576         nameParts.push_back(QByteArray(component->u.s_operator.op->name, component->u.s_operator.op->len));
577         return;
578     }
579     handleNameComponent(component, nameParts);
580 }
581 
symbolType(const char * name)582 Demangler::SymbolType Demangler::symbolType(const char* name)
583 {
584     if (strlen(name) < 4)
585         return SymbolType::Normal;
586     if (name[0] != '_' || name[1] != 'Z' || name[2] != 'T')
587         return SymbolType::Normal;
588 
589     switch (name[3]) {
590         case 'V': return SymbolType::VTable;
591         case 'I': return SymbolType::TypeInfo;
592         case 'S': return SymbolType::TypeInfoName;
593         case 'T': return SymbolType::VTT;
594         case 'C': return SymbolType::ConstructionVTable;
595     }
596 
597     return SymbolType::Normal;
598 }
599