1/*-
2 * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28#include <assert.h>
29#include <ctype.h>
30#include <errno.h>
31#include <libelftc.h>
32#include <limits.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "_libelftc.h"
39
40ELFTC_VCSID("$Id: libelftc_dem_gnu2.c 3513 2016-12-29 07:04:22Z kaiwang27 $");
41
42/**
43 * @file cpp_demangle_gnu2.c
44 * @brief Decode function name encoding in GNU 2.
45 *
46 * Function name encoding in GNU 2 based on ARM style.
47 */
48
49enum encode_type {
50	ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER,
51	ENCODE_OP_TF, ENCODE_OP_TI, ENCODE_OP_VT
52};
53
54struct cstring {
55	char	*buf;
56	size_t	size;
57};
58
59struct demangle_data {
60	bool	ptr, ref, cnst, array, cnst_fn, class_name;
61	struct cstring array_str;
62	const char *p;
63	enum encode_type type;
64	struct vector_str vec;
65	struct vector_str arg;
66};
67
68#define SIMPLE_HASH(x,y)	(64 * x + y)
69#define VEC_PUSH_STR(d,s)	vector_str_push((d), (s), strlen((s)))
70#define	CPP_DEMANGLE_GNU2_TRY	128
71
72static void	dest_cstring(struct cstring *);
73static void	dest_demangle_data(struct demangle_data *);
74static bool	init_cstring(struct cstring *, size_t);
75static bool	init_demangle_data(struct demangle_data *);
76static bool	push_CTDT(const char *, size_t, struct vector_str *);
77static bool	read_array(struct demangle_data *);
78static bool	read_class(struct demangle_data *);
79static bool	read_func(struct demangle_data *);
80static bool	read_func_name(struct demangle_data *);
81static bool	read_func_ptr(struct demangle_data *);
82static bool	read_memptr(struct demangle_data *);
83static bool	read_op(struct demangle_data *);
84static bool	read_op_user(struct demangle_data *);
85static bool	read_qual_name(struct demangle_data *);
86static int	read_subst(struct demangle_data *);
87static int	read_subst_iter(struct demangle_data *);
88static bool	read_type(struct demangle_data *);
89
90/**
91 * @brief Decode the input string by the GNU 2 style.
92 *
93 * @return New allocated demangled string or NULL if failed.
94 */
95char *
96cpp_demangle_gnu2(const char *org)
97{
98	struct demangle_data d;
99	size_t arg_begin, arg_len;
100	unsigned int try;
101	char *rtn, *arg;
102
103	if (org == NULL)
104		return (NULL);
105
106	if (init_demangle_data(&d) == false)
107		return (NULL);
108
109	try = 0;
110	rtn = NULL;
111
112	d.p = org;
113	if (read_func_name(&d) == false)
114		goto clean;
115
116	switch (d.type) {
117	case ENCODE_FUNC :
118	case ENCODE_OP :
119		break;
120
121	case ENCODE_OP_CT :
122		if (push_CTDT("::", 2, &d.vec) == false)
123			goto clean;
124
125                break;
126	case ENCODE_OP_DT :
127		if (push_CTDT("::~", 3, &d.vec) == false)
128			goto clean;
129
130		if (VEC_PUSH_STR(&d.vec, "(void)") == false)
131			goto clean;
132
133		goto flat;
134	case ENCODE_OP_USER :
135	case ENCODE_OP_TF :
136	case ENCODE_OP_TI :
137	case ENCODE_OP_VT :
138		goto flat;
139	}
140
141	if (*d.p == 'F')
142		++d.p;
143	else if (*d.p == '\0') {
144		if (d.class_name == true) {
145			if (VEC_PUSH_STR(&d.vec, "(void)") == false)
146				goto clean;
147
148			goto flat;
149		} else
150			goto clean;
151	}
152
153	/* start argument types */
154	if (VEC_PUSH_STR(&d.vec, "(") == false)
155		goto clean;
156
157	for (;;) {
158		if (*d.p == 'T') {
159			const int rtn_subst = read_subst(&d);
160
161			if (rtn_subst == -1)
162				goto clean;
163			else if (rtn_subst == 1)
164				break;
165
166			continue;
167		}
168
169		if (*d.p == 'N') {
170			const int rtn_subst_iter = read_subst_iter(&d);
171
172			if (rtn_subst_iter == -1)
173				goto clean;
174			else if(rtn_subst_iter == 1)
175				break;
176
177			continue;
178		}
179
180		arg_begin = d.vec.size;
181
182		if (read_type(&d) == false)
183			goto clean;
184
185		if (d.ptr == true) {
186			if (VEC_PUSH_STR(&d.vec, "*") == false)
187				goto clean;
188
189			d.ptr = false;
190		}
191
192		if (d.ref == true) {
193			if (VEC_PUSH_STR(&d.vec, "&") == false)
194				goto clean;
195
196			d.ref = false;
197		}
198
199		if (d.cnst == true) {
200			if (VEC_PUSH_STR(&d.vec, " const") == false)
201				goto clean;
202
203			d.cnst = false;
204		}
205
206		if (d.array == true) {
207			if (vector_str_push(&d.vec, d.array_str.buf,
208				d.array_str.size) == false)
209				goto clean;
210
211			dest_cstring(&d.array_str);
212			d.array = false;
213		}
214
215		if (*d.p == '\0')
216			break;
217
218		if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1,
219		    &arg_len)) == NULL)
220			goto clean;
221
222		if (vector_str_push(&d.arg, arg, arg_len) == false) {
223			free(arg);
224			goto clean;
225		}
226
227		free(arg);
228
229		if (VEC_PUSH_STR(&d.vec, ", ") == false)
230			goto clean;
231
232		if (++try > CPP_DEMANGLE_GNU2_TRY)
233			goto clean;
234	}
235
236	/* end argument types */
237	if (VEC_PUSH_STR(&d.vec, ")") == false)
238		goto clean;
239flat:
240	if (d.cnst_fn == true && VEC_PUSH_STR(&d.vec, " const") == false)
241		goto clean;
242
243	rtn = vector_str_get_flat(&d.vec, NULL);
244clean:
245	dest_demangle_data(&d);
246
247	return (rtn);
248}
249
250/**
251 * @brief Test input string is encoded by the GNU 2 style.
252 *
253 * @return True if input string is encoded by the GNU 2 style.
254 */
255bool
256is_cpp_mangled_gnu2(const char *org)
257{
258	char *str;
259	bool rtn = false;
260
261	if (org == NULL)
262		return (false);
263
264	/* search valid text to end */
265	str = strstr(org, "__");
266	while (str != NULL) {
267		if (*(str + 2) != '\0') {
268			if (*(str + 2) == 'C' ||
269			    *(str + 2) == 'F' ||
270			    *(str + 2) == 'Q' ||
271			    ELFTC_ISDIGIT(*(str + 2))) {
272				rtn |= true;
273
274				break;
275			}
276
277			if (*(str + 3) != '\0') {
278				switch (SIMPLE_HASH(*(str + 2), *(str + 3))) {
279				case SIMPLE_HASH('m', 'l') :
280				case SIMPLE_HASH('d', 'v') :
281				case SIMPLE_HASH('m', 'd') :
282				case SIMPLE_HASH('p', 'l') :
283				case SIMPLE_HASH('m', 'i') :
284				case SIMPLE_HASH('l', 's') :
285				case SIMPLE_HASH('r', 's') :
286				case SIMPLE_HASH('e', 'q') :
287				case SIMPLE_HASH('n', 'e') :
288				case SIMPLE_HASH('l', 't') :
289				case SIMPLE_HASH('g', 't') :
290				case SIMPLE_HASH('l', 'e') :
291				case SIMPLE_HASH('g', 'e') :
292				case SIMPLE_HASH('a', 'd') :
293				case SIMPLE_HASH('o', 'r') :
294				case SIMPLE_HASH('e', 'r') :
295				case SIMPLE_HASH('a', 'a') :
296				case SIMPLE_HASH('o', 'o') :
297				case SIMPLE_HASH('n', 't') :
298				case SIMPLE_HASH('c', 'o') :
299				case SIMPLE_HASH('p', 'p') :
300				case SIMPLE_HASH('m', 'm') :
301				case SIMPLE_HASH('a', 's') :
302				case SIMPLE_HASH('r', 'f') :
303				case SIMPLE_HASH('a', 'p') :
304				case SIMPLE_HASH('a', 'm') :
305				case SIMPLE_HASH('a', 'l') :
306				case SIMPLE_HASH('a', 'r') :
307				case SIMPLE_HASH('a', 'o') :
308				case SIMPLE_HASH('a', 'e') :
309				case SIMPLE_HASH('c', 'm') :
310				case SIMPLE_HASH('r', 'm') :
311				case SIMPLE_HASH('c', 'l') :
312				case SIMPLE_HASH('v', 'c') :
313				case SIMPLE_HASH('n', 'w') :
314				case SIMPLE_HASH('d', 'l') :
315				case SIMPLE_HASH('o', 'p') :
316				case SIMPLE_HASH('t', 'f') :
317				case SIMPLE_HASH('t', 'i') :
318					rtn |= true;
319
320					break;
321				}
322			}
323		}
324
325		str = strstr(str + 2, "__");
326	}
327
328	rtn |= strstr(org, "_$_") != NULL;
329	rtn |= strstr(org, "_vt$") != NULL;
330
331	return (rtn);
332}
333
334static void
335dest_cstring(struct cstring *s)
336{
337
338	if (s == NULL)
339		return;
340
341	free(s->buf);
342	s->buf = NULL;
343	s->size = 0;
344}
345
346static void
347dest_demangle_data(struct demangle_data *d)
348{
349
350	if (d != NULL) {
351		vector_str_dest(&d->arg);
352		vector_str_dest(&d->vec);
353
354		dest_cstring(&d->array_str);
355	}
356}
357
358static bool
359init_cstring(struct cstring *s, size_t len)
360{
361
362	if (s == NULL || len <= 1)
363		return (false);
364
365	if ((s->buf = malloc(sizeof(char) * len)) == NULL)
366		return (false);
367
368	s->size = len - 1;
369
370	return (true);
371}
372
373static bool
374init_demangle_data(struct demangle_data *d)
375{
376
377	if (d == NULL)
378		return (false);
379
380	d->ptr = false;
381	d->ref = false;
382	d->cnst = false;
383	d->array = false;
384	d->cnst_fn = false;
385	d->class_name = false;
386
387	d->array_str.buf = NULL;
388	d->array_str.size = 0;
389
390	d->type = ENCODE_FUNC;
391
392	if (!vector_str_init(&d->vec))
393		return (false);
394
395	if (!vector_str_init(&d->arg)) {
396		vector_str_dest(&d->vec);
397		return (false);
398	}
399
400	return (true);
401}
402
403static bool
404push_CTDT(const char *s, size_t l, struct vector_str *v)
405{
406
407	if (s == NULL || l == 0 || v == NULL)
408		return (false);
409
410	if (vector_str_push(v, s, l) == false)
411		return (false);
412
413	assert(v->size > 1);
414
415	return (VEC_PUSH_STR(v, v->container[v->size - 2]));
416}
417
418static bool
419read_array(struct demangle_data *d)
420{
421	size_t len;
422	const char *end;
423
424	if (d == NULL || d->p == NULL)
425		return (false);
426
427	end = d->p;
428	assert(end != NULL);
429
430	for (;;) {
431		if (*end == '\0')
432			return (false);
433
434		if (ELFTC_ISDIGIT(*end) == 0)
435			break;
436
437		++end;
438	}
439
440	if (*end != '_')
441		return (false);
442
443	len = end - d->p;
444	assert(len > 0);
445
446	dest_cstring(&d->array_str);
447	if (init_cstring(&d->array_str, len + 3) == false)
448		return (false);
449
450	strncpy(d->array_str.buf + 1, d->p, len);
451	*d->array_str.buf = '[';
452	*(d->array_str.buf + len + 1) = ']';
453
454	d->array = true;
455	d->p = end + 1;
456
457	return (true);
458}
459
460static bool
461read_class(struct demangle_data *d)
462{
463	size_t len;
464	char *str;
465
466	if (d == NULL)
467		return (false);
468
469	len = strtol(d->p, &str, 10);
470	if (len == 0 && (errno == EINVAL || errno == ERANGE))
471		return (false);
472
473	assert(len > 0);
474	assert(str != NULL);
475
476	if (vector_str_push(&d->vec, str, len) == false)
477		return (false);
478
479	d->p = str + len;
480
481	d->class_name = true;
482
483	return (true);
484}
485
486static bool
487read_func(struct demangle_data *d)
488{
489	size_t len;
490	const char *name;
491	char *delim;
492
493	if (d == NULL)
494		return (false);
495
496	assert(d->p != NULL && "d->p (org str) is NULL");
497	if ((delim = strstr(d->p, "__")) == NULL)
498		return (false);
499
500	len = delim - d->p;
501	assert(len != 0);
502
503	name = d->p;
504
505	d->p = delim + 2;
506
507	if (*d->p == 'C') {
508		++d->p;
509
510		d->cnst_fn = true;
511	}
512
513	if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
514		++d->p;
515
516		if (read_qual_name(d) == false)
517			return (false);
518	} else if (ELFTC_ISDIGIT(*d->p)) {
519		if (read_class(d) == false)
520			return (false);
521
522		if (VEC_PUSH_STR(&d->vec, "::") == false)
523			return (false);
524	}
525
526	return (vector_str_push(&d->vec, name, len));
527}
528
529static bool
530read_func_name(struct demangle_data *d)
531{
532	size_t len;
533	bool rtn;
534	char *op_name;
535
536	if (d == NULL)
537		return (false);
538
539	rtn = false;
540	op_name = NULL;
541
542	assert(d->p != NULL && "d->p (org str) is NULL");
543
544	if (*d->p == '_' && *(d->p + 1) == '_') {
545		d->p += 2;
546
547		/* CTOR */
548		if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
549			++d->p;
550			d->type = ENCODE_OP_CT;
551
552			if (read_qual_name(d) == false)
553				return (false);
554
555			return (vector_str_pop(&d->vec));
556		} else if (ELFTC_ISDIGIT(*d->p)) {
557			d->type = ENCODE_OP_CT;
558
559			return (read_class(d));
560		}
561
562		d->type = ENCODE_OP;
563		if (read_op(d) == false) {
564			/* not good condition, start function name with '__' */
565			d->type = ENCODE_FUNC;
566
567			if (VEC_PUSH_STR(&d->vec, "__") == false)
568				return (false);
569
570			return (read_func(d));
571		}
572
573		if (d->type == ENCODE_OP_USER ||
574		    d->type == ENCODE_OP_TF ||
575		    d->type == ENCODE_OP_TI)
576			return (true);
577
578		/* skip "__" */
579		d->p += 2;
580
581		if (*d->p == 'C') {
582			++d->p;
583
584			d->cnst_fn = true;
585		}
586
587		/* assume delimiter is removed */
588		if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
589			++d->p;
590
591			assert(d->vec.size > 0);
592
593			len = strlen(d->vec.container[d->vec.size - 1]);
594			if ((op_name = malloc(sizeof(char) * (len + 1)))
595			    == NULL)
596				return (false);
597
598			snprintf(op_name, len + 1, "%s",
599			    d->vec.container[d->vec.size - 1]);
600			vector_str_pop(&d->vec);
601
602			if (read_qual_name(d) == false)
603				goto clean;
604
605			if (VEC_PUSH_STR(&d->vec, "::") == false)
606				goto clean;
607
608			if (vector_str_push(&d->vec, op_name, len) == false)
609				goto clean;
610
611			rtn = true;
612		} else if (ELFTC_ISDIGIT(*d->p)) {
613			assert(d->vec.size > 0);
614
615			len = strlen(d->vec.container[d->vec.size - 1]);
616			if ((op_name = malloc(sizeof(char) * (len + 1)))
617			    == NULL)
618				return (false);
619
620			snprintf(op_name, len + 1, "%s",
621			    d->vec.container[d->vec.size - 1]);
622			vector_str_pop(&d->vec);
623
624			if (read_class(d) == false)
625				goto clean;
626
627			if (VEC_PUSH_STR(&d->vec, "::") == false)
628				goto clean;
629
630			if (vector_str_push(&d->vec, op_name, len) == false)
631				goto clean;
632
633			rtn = true;
634		}
635	} else if (memcmp(d->p, "_$_", 3) == 0) {
636		/* DTOR */
637		d->p += 3;
638		d->type = ENCODE_OP_DT;
639
640		if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
641			++d->p;
642
643			if (read_qual_name(d) == false)
644				return (false);
645
646			return (vector_str_pop(&d->vec));
647		} else if (ELFTC_ISDIGIT(*d->p))
648			return (read_class(d));
649
650		return (false);
651	} else if (memcmp(d->p, "_vt$", 4) == 0) {
652		/* vtable */
653		d->p += 4;
654		d->type = ENCODE_OP_VT;
655
656		if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
657			++d->p;
658
659			if (read_qual_name(d) == false)
660				return (false);
661
662			if (vector_str_pop(&d->vec) == false)
663				return (false);
664		} else if (ELFTC_ISDIGIT(*d->p)) {
665			if (read_class(d) == false)
666				return (false);
667		}
668
669		return (VEC_PUSH_STR(&d->vec, " virtual table"));
670	} else
671		return (read_func(d));
672clean:
673	free(op_name);
674
675	return (rtn);
676}
677
678/* Read function ptr type */
679static bool
680read_func_ptr(struct demangle_data *d)
681{
682	struct demangle_data fptr;
683	size_t arg_len, rtn_len;
684	char *arg_type, *rtn_type;
685	int lim;
686
687	if (d == NULL)
688		return (false);
689
690	if (init_demangle_data(&fptr) == false)
691		return (false);
692
693	fptr.p = d->p + 1;
694	lim = 0;
695	arg_type = NULL;
696	rtn_type = NULL;
697
698	for (;;) {
699		if (read_type(&fptr) == false) {
700			dest_demangle_data(&fptr);
701
702			return (false);
703		}
704
705		if (fptr.ptr == true) {
706			if (VEC_PUSH_STR(&fptr.vec, "*") == false) {
707				dest_demangle_data(&fptr);
708
709				return (false);
710			}
711
712			fptr.ptr = false;
713		}
714
715		if (fptr.ref == true) {
716			if (VEC_PUSH_STR(&fptr.vec, "&") == false) {
717				dest_demangle_data(&fptr);
718
719				return (false);
720			}
721
722			fptr.ref = false;
723		}
724
725		if (fptr.cnst == true) {
726			if (VEC_PUSH_STR(&fptr.vec, " const") == false) {
727				dest_demangle_data(&fptr);
728
729				return (false);
730			}
731
732			fptr.cnst = false;
733		}
734
735		if (*fptr.p == '_')
736			break;
737
738		if (VEC_PUSH_STR(&fptr.vec, ", ") == false) {
739			dest_demangle_data(&fptr);
740
741			return (false);
742		}
743
744		if (++lim > CPP_DEMANGLE_GNU2_TRY) {
745
746			dest_demangle_data(&fptr);
747
748			return (false);
749		}
750	}
751
752	arg_type = vector_str_get_flat(&fptr.vec, &arg_len);
753	/* skip '_' */
754	d->p = fptr.p + 1;
755
756	dest_demangle_data(&fptr);
757
758	if (init_demangle_data(&fptr) == false) {
759		free(arg_type);
760
761		return (false);
762	}
763
764	fptr.p = d->p;
765	lim = 0;
766
767	if (read_type(&fptr) == false) {
768		free(arg_type);
769		dest_demangle_data(&fptr);
770
771		return (false);
772	}
773
774	rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len);
775	d->p = fptr.p;
776
777
778	dest_demangle_data(&fptr);
779
780	if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) {
781		free(rtn_type);
782		free(arg_type);
783
784		return (false);
785	}
786
787	free(rtn_type);
788
789	if (VEC_PUSH_STR(&d->vec, " (*)(") == false) {
790		free(arg_type);
791
792		return (false);
793	}
794
795	if (vector_str_push(&d->vec, arg_type, arg_len) == false) {
796		free(arg_type);
797
798		return (false);
799	}
800
801	free(arg_type);
802
803	return (VEC_PUSH_STR(&d->vec, ")"));
804}
805
806static bool
807read_memptr(struct demangle_data *d)
808{
809	struct demangle_data mptr;
810	size_t len;
811	bool rtn;
812	char *mptr_str;
813
814	if (d == NULL || d->p == NULL)
815		return (false);
816
817	if (init_demangle_data(&mptr) == false)
818		return (false);
819
820	rtn = false;
821	mptr_str = NULL;
822
823	mptr.p = d->p;
824	if (*mptr.p == 'Q') {
825		++mptr.p;
826
827		if (read_qual_name(&mptr) == false)
828			goto clean;
829	} else if (read_class(&mptr) == false)
830			goto clean;
831
832	d->p = mptr.p;
833
834	if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL)
835		goto clean;
836
837	if (vector_str_push(&d->vec, mptr_str, len) == false)
838		goto clean;
839
840	if (VEC_PUSH_STR(&d->vec, "::*") == false)
841		goto clean;
842
843	rtn = true;
844clean:
845	free(mptr_str);
846	dest_demangle_data(&mptr);
847
848	return (rtn);
849}
850
851static bool
852read_op(struct demangle_data *d)
853{
854
855	if (d == NULL)
856		return (false);
857
858	assert(d->p != NULL && "d->p (org str) is NULL");
859
860	switch (SIMPLE_HASH(*(d->p), *(d->p+1))) {
861	case SIMPLE_HASH('m', 'l') :
862		d->p += 2;
863		return (VEC_PUSH_STR(&d->vec, "operator*"));
864	case SIMPLE_HASH('d', 'v') :
865		d->p += 2;
866		return (VEC_PUSH_STR(&d->vec, "operator/"));
867	case SIMPLE_HASH('m', 'd') :
868		d->p += 2;
869		return (VEC_PUSH_STR(&d->vec, "operator%"));
870	case SIMPLE_HASH('p', 'l') :
871		d->p += 2;
872		return (VEC_PUSH_STR(&d->vec, "operator+"));
873	case SIMPLE_HASH('m', 'i') :
874		d->p += 2;
875		return (VEC_PUSH_STR(&d->vec, "operator-"));
876	case SIMPLE_HASH('l', 's') :
877		d->p += 2;
878		return (VEC_PUSH_STR(&d->vec, "operator<<"));
879	case SIMPLE_HASH('r', 's') :
880		d->p += 2;
881		return (VEC_PUSH_STR(&d->vec, "operator>>"));
882	case SIMPLE_HASH('e', 'q') :
883		d->p += 2;
884		return (VEC_PUSH_STR(&d->vec, "operator=="));
885	case SIMPLE_HASH('n', 'e') :
886		d->p += 2;
887		return (VEC_PUSH_STR(&d->vec, "operator!="));
888	case SIMPLE_HASH('l', 't') :
889		d->p += 2;
890		return (VEC_PUSH_STR(&d->vec, "operator<"));
891	case SIMPLE_HASH('g', 't') :
892		d->p += 2;
893		return (VEC_PUSH_STR(&d->vec, "operator>"));
894	case SIMPLE_HASH('l', 'e') :
895		d->p += 2;
896		return (VEC_PUSH_STR(&d->vec, "operator<="));
897	case SIMPLE_HASH('g', 'e') :
898		d->p += 2;
899		return (VEC_PUSH_STR(&d->vec, "operator>="));
900	case SIMPLE_HASH('a', 'd') :
901		d->p += 2;
902		if (*d->p == 'v') {
903			++d->p;
904			return (VEC_PUSH_STR(&d->vec, "operator/="));
905		} else
906			return (VEC_PUSH_STR(&d->vec, "operator&"));
907	case SIMPLE_HASH('o', 'r') :
908		d->p += 2;
909		return (VEC_PUSH_STR(&d->vec, "operator|"));
910	case SIMPLE_HASH('e', 'r') :
911		d->p += 2;
912		return (VEC_PUSH_STR(&d->vec, "operator^"));
913	case SIMPLE_HASH('a', 'a') :
914		d->p += 2;
915		if (*d->p == 'd') {
916			++d->p;
917			return (VEC_PUSH_STR(&d->vec, "operator&="));
918		} else
919			return (VEC_PUSH_STR(&d->vec, "operator&&"));
920	case SIMPLE_HASH('o', 'o') :
921		d->p += 2;
922		return (VEC_PUSH_STR(&d->vec, "operator||"));
923	case SIMPLE_HASH('n', 't') :
924		d->p += 2;
925		return (VEC_PUSH_STR(&d->vec, "operator!"));
926	case SIMPLE_HASH('c', 'o') :
927		d->p += 2;
928		return (VEC_PUSH_STR(&d->vec, "operator~"));
929	case SIMPLE_HASH('p', 'p') :
930		d->p += 2;
931		return (VEC_PUSH_STR(&d->vec, "operator++"));
932	case SIMPLE_HASH('m', 'm') :
933		d->p += 2;
934		return (VEC_PUSH_STR(&d->vec, "operator--"));
935	case SIMPLE_HASH('a', 's') :
936		d->p += 2;
937		return (VEC_PUSH_STR(&d->vec, "operator="));
938	case SIMPLE_HASH('r', 'f') :
939		d->p += 2;
940		return (VEC_PUSH_STR(&d->vec, "operator->"));
941	case SIMPLE_HASH('a', 'p') :
942		/* apl */
943		if (*(d->p + 2) != 'l')
944			return (false);
945
946		d->p += 3;
947		return (VEC_PUSH_STR(&d->vec, "operator+="));
948	case SIMPLE_HASH('a', 'm') :
949		d->p += 2;
950		if (*d->p == 'i') {
951			++d->p;
952			return (VEC_PUSH_STR(&d->vec, "operator-="));
953		} else if (*d->p == 'u') {
954			++d->p;
955			return (VEC_PUSH_STR(&d->vec, "operator*="));
956		} else if (*d->p == 'd') {
957			++d->p;
958			return (VEC_PUSH_STR(&d->vec, "operator%="));
959		}
960
961		return (false);
962	case SIMPLE_HASH('a', 'l') :
963		/* als */
964		if (*(d->p + 2) != 's')
965			return (false);
966
967		d->p += 3;
968		return (VEC_PUSH_STR(&d->vec, "operator<<="));
969	case SIMPLE_HASH('a', 'r') :
970		/* ars */
971		if (*(d->p + 2) != 's')
972			return (false);
973
974		d->p += 3;
975		return (VEC_PUSH_STR(&d->vec, "operator>>="));
976	case SIMPLE_HASH('a', 'o') :
977		/* aor */
978		if (*(d->p + 2) != 'r')
979			return (false);
980
981		d->p += 3;
982		return (VEC_PUSH_STR(&d->vec, "operator|="));
983	case SIMPLE_HASH('a', 'e') :
984		/* aer */
985		if (*(d->p + 2) != 'r')
986			return (false);
987
988		d->p += 3;
989		return (VEC_PUSH_STR(&d->vec, "operator^="));
990	case SIMPLE_HASH('c', 'm') :
991		d->p += 2;
992		return (VEC_PUSH_STR(&d->vec, "operator,"));
993	case SIMPLE_HASH('r', 'm') :
994		d->p += 2;
995		return (VEC_PUSH_STR(&d->vec, "operator->*"));
996	case SIMPLE_HASH('c', 'l') :
997		d->p += 2;
998		return (VEC_PUSH_STR(&d->vec, "()"));
999	case SIMPLE_HASH('v', 'c') :
1000		d->p += 2;
1001		return (VEC_PUSH_STR(&d->vec, "[]"));
1002	case SIMPLE_HASH('n', 'w') :
1003		d->p += 2;
1004		return (VEC_PUSH_STR(&d->vec, "operator new()"));
1005	case SIMPLE_HASH('d', 'l') :
1006		d->p += 2;
1007		return (VEC_PUSH_STR(&d->vec, "operator delete()"));
1008	case SIMPLE_HASH('o', 'p') :
1009		/* __op<TO_TYPE>__<FROM_TYPE> */
1010		d->p += 2;
1011
1012		d->type = ENCODE_OP_USER;
1013
1014		return (read_op_user(d));
1015	case SIMPLE_HASH('t', 'f') :
1016		d->p += 2;
1017		d->type = ENCODE_OP_TF;
1018
1019		if (read_type(d) == false)
1020			return (false);
1021
1022		return (VEC_PUSH_STR(&d->vec, " type_info function"));
1023	case SIMPLE_HASH('t', 'i') :
1024		d->p += 2;
1025		d->type = ENCODE_OP_TI;
1026
1027		if (read_type(d) == false)
1028			return (false);
1029
1030		return (VEC_PUSH_STR(&d->vec, " type_info node"));
1031	default :
1032		return (false);
1033	};
1034}
1035
1036static bool
1037read_op_user(struct demangle_data *d)
1038{
1039	struct demangle_data from, to;
1040	size_t from_len, to_len;
1041	bool rtn;
1042	char *from_str, *to_str;
1043
1044	if (d == NULL)
1045		return (false);
1046
1047	if (init_demangle_data(&from) == false)
1048		return (false);
1049
1050	rtn = false;
1051	from_str = NULL;
1052	to_str = NULL;
1053	if (init_demangle_data(&to) == false)
1054		goto clean;
1055
1056	to.p = d->p;
1057	if (*to.p == 'Q') {
1058		++to.p;
1059
1060		if (read_qual_name(&to) == false)
1061			goto clean;
1062
1063		/* pop last '::' */
1064		if (vector_str_pop(&to.vec) == false)
1065			goto clean;
1066	} else {
1067		if (read_class(&to) == false)
1068			goto clean;
1069
1070		/* skip '__' */
1071		to.p += 2;
1072	}
1073
1074	if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL)
1075		goto clean;
1076
1077	from.p = to.p;
1078	if (*from.p == 'Q') {
1079		++from.p;
1080
1081		if (read_qual_name(&from) == false)
1082			goto clean;
1083
1084		/* pop last '::' */
1085		if (vector_str_pop(&from.vec) == false)
1086			goto clean;
1087	} else if (read_class(&from) == false)
1088			goto clean;
1089
1090	if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL)
1091		goto clean;
1092
1093	if (vector_str_push(&d->vec, from_str, from_len) == false)
1094		goto clean;
1095
1096	if (VEC_PUSH_STR(&d->vec, "::operator ") == false)
1097		goto clean;
1098
1099	if (vector_str_push(&d->vec, to_str, to_len) == false)
1100		goto clean;
1101
1102	rtn = VEC_PUSH_STR(&d->vec, "()");
1103clean:
1104	free(to_str);
1105	free(from_str);
1106	dest_demangle_data(&to);
1107	dest_demangle_data(&from);
1108
1109	return (rtn);
1110}
1111
1112/* single digit + class names */
1113static bool
1114read_qual_name(struct demangle_data *d)
1115{
1116	int i;
1117	char num;
1118
1119	if (d == NULL)
1120		return (false);
1121
1122	assert(d->p != NULL && "d->p (org str) is NULL");
1123	assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
1124
1125	num = *d->p - 48;
1126
1127	assert(num > 0);
1128
1129	++d->p;
1130	for (i = 0; i < num ; ++i) {
1131		if (read_class(d) == false)
1132			return (false);
1133
1134		if (VEC_PUSH_STR(&d->vec, "::") == false)
1135			return (false);
1136	}
1137
1138	if (*d->p != '\0')
1139		d->p = d->p + 2;
1140
1141	return (true);
1142}
1143
1144/* Return -1 at fail, 0 at success, and 1 at end */
1145static int
1146read_subst(struct demangle_data *d)
1147{
1148	size_t idx;
1149	char *str;
1150
1151	if (d == NULL)
1152		return (-1);
1153
1154	idx = strtol(d->p + 1, &str, 10);
1155	if (idx == 0 && (errno == EINVAL || errno == ERANGE))
1156		return (-1);
1157
1158	assert(idx > 0);
1159	assert(str != NULL);
1160
1161	d->p = str;
1162
1163	if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
1164		return (-1);
1165
1166	if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false)
1167		return (-1);
1168
1169	if (*d->p == '\0')
1170		return (1);
1171
1172	return (0);
1173}
1174
1175static int
1176read_subst_iter(struct demangle_data *d)
1177{
1178	int i;
1179	size_t idx;
1180	char repeat;
1181	char *str;
1182
1183	if (d == NULL)
1184		return (-1);
1185
1186	++d->p;
1187	assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
1188
1189	repeat = *d->p - 48;
1190
1191	assert(repeat > 1);
1192
1193	++d->p;
1194
1195	idx = strtol(d->p, &str, 10);
1196	if (idx == 0 && (errno == EINVAL || errno == ERANGE))
1197		return (-1);
1198
1199	assert(idx > 0);
1200	assert(str != NULL);
1201
1202	d->p = str;
1203
1204	for (i = 0; i < repeat ; ++i) {
1205		if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
1206			return (-1);
1207
1208		if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false)
1209			return (-1);
1210
1211		if (i != repeat - 1 &&
1212		    VEC_PUSH_STR(&d->vec, ", ") == false)
1213			return (-1);
1214	}
1215
1216	if (*d->p == '\0')
1217		return (1);
1218
1219	return (0);
1220}
1221
1222static bool
1223read_type(struct demangle_data *d)
1224{
1225
1226	if (d == NULL)
1227		return (false);
1228
1229	assert(d->p != NULL && "d->p (org str) is NULL");
1230
1231	while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' ||
1232	       *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' ||
1233	       *d->p == 'M') {
1234		switch (*d->p) {
1235		case 'U' :
1236			++d->p;
1237
1238			if (VEC_PUSH_STR(&d->vec, "unsigned ") == false)
1239				return (false);
1240
1241			break;
1242		case 'C' :
1243			++d->p;
1244
1245			if (*d->p == 'P')
1246				d->cnst = true;
1247			else {
1248				if (VEC_PUSH_STR(&d->vec, "const ") ==
1249				    false)
1250					return (false);
1251			}
1252
1253			break;
1254		case 'V' :
1255			++d->p;
1256
1257			if (VEC_PUSH_STR(&d->vec, "volatile ") == false)
1258				return (false);
1259
1260			break;
1261		case 'S' :
1262			++d->p;
1263
1264			if (VEC_PUSH_STR(&d->vec, "signed ") == false)
1265				return (false);
1266
1267			break;
1268		case 'P' :
1269			++d->p;
1270
1271			if (*d->p == 'F')
1272				return (read_func_ptr(d));
1273			else
1274				d->ptr = true;
1275
1276			break;
1277		case 'R' :
1278			++d->p;
1279
1280			d->ref = true;
1281
1282			break;
1283		case 'F' :
1284			break;
1285		case 'A' :
1286			++d->p;
1287
1288			if (read_array(d) == false)
1289				return (false);
1290
1291			break;
1292		case 'M' :
1293			++d->p;
1294
1295			if (read_memptr(d) == false)
1296				return (false);
1297
1298			break;
1299		default :
1300			break;
1301		}
1302	}
1303
1304	if (ELFTC_ISDIGIT(*d->p))
1305		return (read_class(d));
1306
1307	switch (*d->p) {
1308	case 'Q' :
1309		++d->p;
1310
1311		return (read_qual_name(d));
1312	case 'v' :
1313		++d->p;
1314
1315		return (VEC_PUSH_STR(&d->vec, "void"));
1316	case 'b':
1317		++d->p;
1318
1319		return(VEC_PUSH_STR(&d->vec, "bool"));
1320	case 'c' :
1321		++d->p;
1322
1323		return (VEC_PUSH_STR(&d->vec, "char"));
1324	case 's' :
1325		++d->p;
1326
1327		return (VEC_PUSH_STR(&d->vec, "short"));
1328	case 'i' :
1329		++d->p;
1330
1331		return (VEC_PUSH_STR(&d->vec, "int"));
1332	case 'l' :
1333		++d->p;
1334
1335		return (VEC_PUSH_STR(&d->vec, "long"));
1336	case 'f' :
1337		++d->p;
1338
1339		return (VEC_PUSH_STR(&d->vec, "float"));
1340	case 'd':
1341		++d->p;
1342
1343		return (VEC_PUSH_STR(&d->vec, "double"));
1344	case 'r':
1345		++d->p;
1346
1347		return (VEC_PUSH_STR(&d->vec, "long double"));
1348	case 'e':
1349		++d->p;
1350
1351		return (VEC_PUSH_STR(&d->vec, "..."));
1352	case 'w':
1353		++d->p;
1354
1355		return (VEC_PUSH_STR(&d->vec, "wchar_t"));
1356	case 'x':
1357		++d->p;
1358
1359		return (VEC_PUSH_STR(&d->vec, "long long"));
1360	default:
1361		return (false);
1362	};
1363
1364	/* NOTREACHED */
1365	return (false);
1366}
1367