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