xref: /freebsd/contrib/elftoolchain/libelftc/libelftc_dem_arm.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
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 2065 2011-10-26 15:24:47Z jkoshy $");
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	CPP_DEMANGLE_ARM_TRY	128
72 
73 static void	dest_cstring(struct cstring *);
74 static void	dest_demangle_data(struct demangle_data *);
75 static bool	init_cstring(struct cstring *, size_t);
76 static bool	init_demangle_data(struct demangle_data *);
77 static bool	push_CTDT(const char *, size_t, struct vector_str *);
78 static bool	read_array(struct demangle_data *);
79 static bool	read_class(struct demangle_data *);
80 static bool	read_func(struct demangle_data *);
81 static bool	read_func_name(struct demangle_data *);
82 static bool	read_func_ptr(struct demangle_data *);
83 static bool	read_memptr(struct demangle_data *);
84 static bool	read_op(struct demangle_data *);
85 static bool	read_op_user(struct demangle_data *);
86 static bool	read_qual_name(struct demangle_data *);
87 static int	read_subst(struct demangle_data *);
88 static int	read_subst_iter(struct demangle_data *);
89 static 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  */
96 char *
97 cpp_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 
224 flat:
225 	rtn = vector_str_get_flat(&d.vec, NULL);
226 clean:
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  */
237 bool
238 is_cpp_mangled_ARM(const char *org)
239 {
240 
241 	if (org == NULL)
242 		return (false);
243 
244 	return (strstr(org, "__") != NULL);
245 }
246 
247 static void
248 dest_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 
259 static void
260 dest_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 
271 static bool
272 init_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 
286 static bool
287 init_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 
315 static bool
316 push_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 
336 static bool
337 read_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 
378 static bool
379 read_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 
402 static bool
403 read_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 
442 static bool
443 read_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 
522 clean:
523 	free(op_name);
524 
525 	return (rtn);
526 }
527 
528 /* Read function ptr type */
529 static bool
530 read_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 
656 static bool
657 read_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;
696 clean:
697 	free(mptr_str);
698 	dest_demangle_data(&mptr);
699 
700 	return (rtn);
701 }
702 
703 static bool
704 read_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 
903 static bool
904 read_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);
972 clean:
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 */
982 static bool
983 read_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 */
1014 static int
1015 read_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 
1046 static int
1047 read_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 
1095 static bool
1096 read_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