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