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