xref: /freebsd/contrib/elftoolchain/libelftc/libelftc_dem_arm.c (revision 43a5ec4eb41567cc92586503212743d89686d78f)
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 
40 ELFTC_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 
52 enum encode_type {
53 	ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER
54 };
55 
56 struct cstring {
57 	char	*buf;
58 	size_t	size;
59 };
60 
61 struct 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 
74 static void	dest_cstring(struct cstring *);
75 static void	dest_demangle_data(struct demangle_data *);
76 static bool	init_cstring(struct cstring *, size_t);
77 static bool	init_demangle_data(struct demangle_data *);
78 static bool	push_CTDT(const char *, size_t, struct vector_str *);
79 static bool	read_array(struct demangle_data *);
80 static bool	read_class(struct demangle_data *);
81 static bool	read_func(struct demangle_data *);
82 static bool	read_func_name(struct demangle_data *);
83 static bool	read_func_ptr(struct demangle_data *);
84 static bool	read_memptr(struct demangle_data *);
85 static bool	read_op(struct demangle_data *);
86 static bool	read_op_user(struct demangle_data *);
87 static bool	read_qual_name(struct demangle_data *);
88 static int	read_subst(struct demangle_data *);
89 static int	read_subst_iter(struct demangle_data *);
90 static 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  */
97 char *
98 cpp_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 
227 flat:
228 	rtn = vector_str_get_flat(&d.vec, NULL);
229 clean:
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  */
240 bool
241 is_cpp_mangled_ARM(const char *org)
242 {
243 
244 	if (org == NULL)
245 		return (false);
246 
247 	return (strstr(org, "__") != NULL);
248 }
249 
250 static void
251 dest_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 
262 static void
263 dest_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 
274 static bool
275 init_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 
289 static bool
290 init_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 
317 static bool
318 push_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 
337 static bool
338 read_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 
379 static bool
380 read_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 
403 static bool
404 read_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 
443 static bool
444 read_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 
523 clean:
524 	free(op_name);
525 
526 	return (rtn);
527 }
528 
529 /* Read function ptr type */
530 static bool
531 read_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 
657 static bool
658 read_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;
697 clean:
698 	free(mptr_str);
699 	dest_demangle_data(&mptr);
700 
701 	return (rtn);
702 }
703 
704 static bool
705 read_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 
897 static bool
898 read_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, "()");
966 clean:
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 */
976 static bool
977 read_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 */
1008 static int
1009 read_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 
1038 static int
1039 read_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 
1085 static bool
1086 read_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