diff options
Diffstat (limited to 'libelftc/libelftc_dem_arm.c')
-rw-r--r-- | libelftc/libelftc_dem_arm.c | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/libelftc/libelftc_dem_arm.c b/libelftc/libelftc_dem_arm.c new file mode 100644 index 0000000000000..e850b8b5724d6 --- /dev/null +++ b/libelftc/libelftc_dem_arm.c @@ -0,0 +1,1227 @@ +/*- + * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <libelftc.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_dem_arm.c 2065 2011-10-26 15:24:47Z jkoshy $"); + +/** + * @file cpp_demangle_arm.c + * @brief Decode function name encoding in ARM. + * + * Function name encoding in "The Annotated C++ Reference Manual". + * + * Ref : "The Annotated C++ Reference Manual", Margaet A.Ellis, + * Bjarne Stroustrup, AT&T Bell Laboratories 1990, pp 122-126. + */ + +enum encode_type { + ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER +}; + +struct cstring { + char *buf; + size_t size; +}; + +struct demangle_data { + bool ptr, ref, cnst, array; + struct cstring array_str; + const char *p; + enum encode_type type; + struct vector_str vec; + struct vector_str arg; +}; + +#define SIMPLE_HASH(x,y) (64 * x + y) +#define CPP_DEMANGLE_ARM_TRY 128 + +static void dest_cstring(struct cstring *); +static void dest_demangle_data(struct demangle_data *); +static bool init_cstring(struct cstring *, size_t); +static bool init_demangle_data(struct demangle_data *); +static bool push_CTDT(const char *, size_t, struct vector_str *); +static bool read_array(struct demangle_data *); +static bool read_class(struct demangle_data *); +static bool read_func(struct demangle_data *); +static bool read_func_name(struct demangle_data *); +static bool read_func_ptr(struct demangle_data *); +static bool read_memptr(struct demangle_data *); +static bool read_op(struct demangle_data *); +static bool read_op_user(struct demangle_data *); +static bool read_qual_name(struct demangle_data *); +static int read_subst(struct demangle_data *); +static int read_subst_iter(struct demangle_data *); +static bool read_type(struct demangle_data *); + +/** + * @brief Decode the input string by the ARM style. + * + * @return New allocated demangled string or NULL if failed. + */ +char * +cpp_demangle_ARM(const char *org) +{ + struct demangle_data d; + size_t arg_begin, arg_len; + unsigned int try; + char *rtn, *arg; + + if (org == NULL) + return (NULL); + + if (init_demangle_data(&d) == false) + return (NULL); + + try = 0; + rtn = NULL; + + d.p = org; + if (read_func_name(&d) == false) + goto clean; + + if (d.type == ENCODE_OP_CT) { + if (push_CTDT("::", 2, &d.vec) == false) + goto clean; + + goto flat; + } + + if (d.type == ENCODE_OP_DT) { + if (push_CTDT("::~", 3, &d.vec) == false) + goto clean; + + goto flat; + } + + if (d.type == ENCODE_OP_USER) + goto flat; + + /* function type */ + if (*d.p != 'F') + goto clean; + ++d.p; + + /* start argument types */ + if (vector_str_push(&d.vec, "(", 1) == false) + goto clean; + + for (;;) { + if (*d.p == 'T') { + const int rtn_subst = read_subst(&d); + + if (rtn_subst == -1) + goto clean; + else if (rtn_subst == 1) + break; + + continue; + } + + if (*d.p == 'N') { + const int rtn_subst_iter = read_subst_iter(&d); + + if (rtn_subst_iter == -1) + goto clean; + else if(rtn_subst_iter == 1) + break; + + continue; + } + + arg_begin = d.vec.size; + + if (read_type(&d) == false) + goto clean; + + if (d.ptr == true) { + if (vector_str_push(&d.vec, "*", 1) == false) + goto clean; + + d.ptr = false; + } + + if (d.ref == true) { + if (vector_str_push(&d.vec, "&", 1) == false) + goto clean; + + d.ref = false; + } + + if (d.cnst == true) { + if (vector_str_push(&d.vec, " const", 6) == false) + goto clean; + + d.cnst = false; + } + + if (d.array == true) { + if (vector_str_push(&d.vec, d.array_str.buf, + d.array_str.size) == false) + goto clean; + + dest_cstring(&d.array_str); + d.array = false; + } + + if (*d.p == '\0') + break; + + if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1, + &arg_len)) == NULL) + goto clean; + + if (vector_str_push(&d.arg, arg, arg_len) == false) + goto clean; + + free(arg); + + if (vector_str_push(&d.vec, ", ", 2) == false) + goto clean; + + if (++try > CPP_DEMANGLE_ARM_TRY) + goto clean; + } + + /* end argument types */ + if (vector_str_push(&d.vec, ")", 1) == false) + goto clean; + +flat: + rtn = vector_str_get_flat(&d.vec, NULL); +clean: + dest_demangle_data(&d); + + return (rtn); +} + +/** + * @brief Test input string is encoded by the ARM style. + * + * @return True if input string is encoded by the ARM style. + */ +bool +is_cpp_mangled_ARM(const char *org) +{ + + if (org == NULL) + return (false); + + return (strstr(org, "__") != NULL); +} + +static void +dest_cstring(struct cstring *s) +{ + + if (s == NULL) + return; + + free(s->buf); + s->buf = NULL; + s->size = 0; +} + +static void +dest_demangle_data(struct demangle_data *d) +{ + + if (d != NULL) { + vector_str_dest(&d->arg); + vector_str_dest(&d->vec); + + dest_cstring(&d->array_str); + } +} + +static bool +init_cstring(struct cstring *s, size_t len) +{ + + if (s == NULL || len <= 1) + return (false); + + if ((s->buf = malloc(sizeof(char) * len)) == NULL) + return (false); + + s->size = len - 1; + + return (true); +} + +static bool +init_demangle_data(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + d->ptr = false; + d->ref = false; + d->cnst = false; + d->array = false; + + d->array_str.buf = NULL; + d->array_str.size = 0; + + d->type = ENCODE_FUNC; + + if (vector_str_init(&d->vec) == false) + return (false); + + if (vector_str_init(&d->arg) == false) { + vector_str_dest(&d->vec); + + return (false); + } + + return (true); +} + +static bool +push_CTDT(const char *s, size_t l, struct vector_str *v) +{ + + if (s == NULL || l == 0 || v == NULL) + return (false); + + if (vector_str_push(v, s, l) == false) + return (false); + + assert(v->size > 1); + if (vector_str_push(v, v->container[v->size - 2], + strlen(v->container[v->size - 2])) == false) + return (false); + + if (vector_str_push(v, "()", 2) == false) + return (false); + + return (true); +} + +static bool +read_array(struct demangle_data *d) +{ + size_t len; + const char *end; + + if (d == NULL || d->p == NULL) + return (false); + + end = d->p; + assert(end != NULL); + + for (;;) { + if (*end == '\0') + return (false); + + if (ELFTC_ISDIGIT(*end) == 0) + break; + + ++end; + } + + if (*end != '_') + return (false); + + len = end - d->p; + assert(len > 0); + + dest_cstring(&d->array_str); + if (init_cstring(&d->array_str, len + 3) == false) + return (false); + + strncpy(d->array_str.buf + 1, d->p, len); + *d->array_str.buf = '['; + *(d->array_str.buf + len + 1) = ']'; + + d->array = true; + d->p = end + 1; + + return (true); +} + +static bool +read_class(struct demangle_data *d) +{ + size_t len; + char *str; + + if (d == NULL) + return (false); + + len = strtol(d->p, &str, 10); + if (len == 0 && (errno == EINVAL || errno == ERANGE)) + return (false); + + assert(len > 0); + assert(str != NULL); + + if (vector_str_push(&d->vec, str, len) == false) + return (false); + + d->p = str + len; + + return (true); +} + +static bool +read_func(struct demangle_data *d) +{ + size_t len; + const char *name; + char *delim; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + if ((delim = strstr(d->p, "__")) == NULL) + return (false); + + len = delim - d->p; + assert(len != 0); + + name = d->p; + + d->p = delim + 2; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + if (read_qual_name(d) == false) + return (false); + } else if (ELFTC_ISDIGIT(*d->p)) { + if (read_class(d) == false) + return (false); + + if (vector_str_push(&d->vec, "::", 2) == false) + return (false); + } + + if (vector_str_push(&d->vec, name, len) == false) + return (false); + + return (true); +} + +static bool +read_func_name(struct demangle_data *d) +{ + size_t len; + bool rtn; + char *op_name; + + if (d == NULL) + return (false); + + rtn = false; + op_name = NULL; + + assert(d->p != NULL && "d->p (org str) is NULL"); + + if (*d->p == '_' && *(d->p + 1) == '_') { + d->p += 2; + + d->type = ENCODE_OP; + if (read_op(d) == false) + return (false); + + if (d->type == ENCODE_OP_CT || d->type == ENCODE_OP_DT || + d->type == ENCODE_OP_USER) + return (true); + + /* skip "__" */ + d->p += 2; + + /* assume delimiter is removed */ + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_qual_name(d) == false) + goto clean; + + if (vector_str_push(&d->vec, "::", 2) == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } else if (ELFTC_ISDIGIT(*d->p)) { + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_class(d) == false) + goto clean; + + if (vector_str_push(&d->vec, "::", 2) == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } + } else + return (read_func(d)); + +clean: + free(op_name); + + return (rtn); +} + +/* Read function ptr type */ +static bool +read_func_ptr(struct demangle_data *d) +{ + struct demangle_data fptr; + size_t arg_len, rtn_len; + char *arg_type, *rtn_type; + int lim; + + if (d == NULL) + return (false); + + if (init_demangle_data(&fptr) == false) + return (false); + + fptr.p = d->p + 1; + lim = 0; + arg_type = NULL; + rtn_type = NULL; + + for (;;) { + if (read_type(&fptr) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (fptr.ptr == true) { + if (vector_str_push(&fptr.vec, "*", 1) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ptr = false; + } + + if (fptr.ref == true) { + if (vector_str_push(&fptr.vec, "&", 1) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ref = false; + } + + if (fptr.cnst == true) { + if (vector_str_push(&fptr.vec, " const", 6) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.cnst = false; + } + + if (*fptr.p == '_') + break; + + if (vector_str_push(&fptr.vec, ", ", 2) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (++lim > CPP_DEMANGLE_ARM_TRY) { + + dest_demangle_data(&fptr); + + return (false); + } + } + + arg_type = vector_str_get_flat(&fptr.vec, &arg_len); + /* skip '_' */ + d->p = fptr.p + 1; + + dest_demangle_data(&fptr); + + if (init_demangle_data(&fptr) == false) { + free(arg_type); + + return (false); + } + + fptr.p = d->p; + lim = 0; + + if (read_type(&fptr) == false) { + free(arg_type); + dest_demangle_data(&fptr); + + return (false); + } + + rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len); + d->p = fptr.p; + + + dest_demangle_data(&fptr); + + if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) { + free(rtn_type); + free(arg_type); + + return (false); + } + + free(rtn_type); + + if (vector_str_push(&d->vec, " (*)(", 5) == false) { + free(arg_type); + + return (false); + } + + if (vector_str_push(&d->vec, arg_type, arg_len) == false) { + free(arg_type); + + return (false); + } + + free(arg_type); + + return (vector_str_push(&d->vec, ")", 1)); +} + +static bool +read_memptr(struct demangle_data *d) +{ + struct demangle_data mptr; + size_t len; + bool rtn; + char *mptr_str; + + if (d == NULL || d->p == NULL) + return (false); + + if (init_demangle_data(&mptr) == false) + return (false); + + rtn = false; + mptr_str = NULL; + + mptr.p = d->p; + if (*mptr.p == 'Q') { + ++mptr.p; + + if (read_qual_name(&mptr) == false) + goto clean; + } else { + if (read_class(&mptr) == false) + goto clean; + } + + d->p = mptr.p; + + if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, mptr_str, len) == false) + goto clean; + + if (vector_str_push(&d->vec, "::*", 3) == false) + goto clean; + + rtn = true; +clean: + free(mptr_str); + dest_demangle_data(&mptr); + + return (rtn); +} + +static bool +read_op(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + switch (SIMPLE_HASH(*(d->p), *(d->p+1))) { + case SIMPLE_HASH('m', 'l') : + d->p += 2; + return (vector_str_push(&d->vec, "operator*", 9)); + case SIMPLE_HASH('d', 'v') : + d->p += 2; + return (vector_str_push(&d->vec, "operator/", 9)); + case SIMPLE_HASH('m', 'd') : + d->p += 2; + return (vector_str_push(&d->vec, "operator%", 9)); + case SIMPLE_HASH('p', 'l') : + d->p += 2; + return (vector_str_push(&d->vec, "operator+", 9)); + case SIMPLE_HASH('m', 'i') : + d->p += 2; + return (vector_str_push(&d->vec, "operator-", 9)); + case SIMPLE_HASH('l', 's') : + d->p += 2; + return (vector_str_push(&d->vec, "operator<<", 10)); + case SIMPLE_HASH('r', 's') : + d->p += 2; + return (vector_str_push(&d->vec, "operator>>", 10)); + case SIMPLE_HASH('e', 'q') : + d->p += 2; + return (vector_str_push(&d->vec, "operator==", 10)); + case SIMPLE_HASH('n', 'e') : + d->p += 2; + return (vector_str_push(&d->vec, "operator!=", 10)); + case SIMPLE_HASH('l', 't') : + d->p += 2; + return (vector_str_push(&d->vec, "operator<", 9)); + case SIMPLE_HASH('g', 't') : + d->p += 2; + return (vector_str_push(&d->vec, "operator>", 9)); + case SIMPLE_HASH('l', 'e') : + d->p += 2; + return (vector_str_push(&d->vec, "operator<=", 10)); + case SIMPLE_HASH('g', 'e') : + d->p += 2; + return (vector_str_push(&d->vec, "operator>=", 10)); + case SIMPLE_HASH('a', 'd') : + d->p += 2; + if (*d->p == 'v') { + ++d->p; + return (vector_str_push(&d->vec, "operator/=", + 10)); + } else + return (vector_str_push(&d->vec, "operator&", 9)); + case SIMPLE_HASH('o', 'r') : + d->p += 2; + return (vector_str_push(&d->vec, "operator|", 9)); + case SIMPLE_HASH('e', 'r') : + d->p += 2; + return (vector_str_push(&d->vec, "operator^", 9)); + case SIMPLE_HASH('a', 'a') : + d->p += 2; + if (*d->p == 'd') { + ++d->p; + return (vector_str_push(&d->vec, "operator&=", + 10)); + } else + return (vector_str_push(&d->vec, "operator&&", + 10)); + case SIMPLE_HASH('o', 'o') : + d->p += 2; + return (vector_str_push(&d->vec, "operator||", 10)); + case SIMPLE_HASH('n', 't') : + d->p += 2; + return (vector_str_push(&d->vec, "operator!", 9)); + case SIMPLE_HASH('c', 'o') : + d->p += 2; + return (vector_str_push(&d->vec, "operator~", 9)); + case SIMPLE_HASH('p', 'p') : + d->p += 2; + return (vector_str_push(&d->vec, "operator++", 10)); + case SIMPLE_HASH('m', 'm') : + d->p += 2; + return (vector_str_push(&d->vec, "operator--", 10)); + case SIMPLE_HASH('a', 's') : + d->p += 2; + return (vector_str_push(&d->vec, "operator=", 9)); + case SIMPLE_HASH('r', 'f') : + d->p += 2; + return (vector_str_push(&d->vec, "operator->", 10)); + case SIMPLE_HASH('a', 'p') : + /* apl */ + if (*(d->p + 2) != 'l') + return (false); + + d->p += 3; + return (vector_str_push(&d->vec, "operator+=", 10)); + case SIMPLE_HASH('a', 'm') : + d->p += 2; + if (*d->p == 'i') { + ++d->p; + return (vector_str_push(&d->vec, "operator-=", + 10)); + } else if (*d->p == 'u') { + ++d->p; + return (vector_str_push(&d->vec, "operator*=", + 10)); + } else if (*d->p == 'd') { + ++d->p; + return (vector_str_push(&d->vec, "operator%=", + 10)); + } + + return (false); + case SIMPLE_HASH('a', 'l') : + /* als */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (vector_str_push(&d->vec, "operator<<=", 11)); + case SIMPLE_HASH('a', 'r') : + /* ars */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (vector_str_push(&d->vec, "operator>>=", 11)); + case SIMPLE_HASH('a', 'o') : + /* aor */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (vector_str_push(&d->vec, "operator|=", 10)); + case SIMPLE_HASH('a', 'e') : + /* aer */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (vector_str_push(&d->vec, "operator^=", 10)); + case SIMPLE_HASH('c', 'm') : + d->p += 2; + return (vector_str_push(&d->vec, "operator,", 9)); + case SIMPLE_HASH('r', 'm') : + d->p += 2; + return (vector_str_push(&d->vec, "operator->*", 11)); + case SIMPLE_HASH('c', 'l') : + d->p += 2; + return (vector_str_push(&d->vec, "()", 2)); + case SIMPLE_HASH('v', 'c') : + d->p += 2; + return (vector_str_push(&d->vec, "[]", 2)); + case SIMPLE_HASH('c', 't') : + d->p += 4; + d->type = ENCODE_OP_CT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + return (read_qual_name(d)); + } else if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + return (false); + case SIMPLE_HASH('d', 't') : + d->p += 4; + d->type = ENCODE_OP_DT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + return (read_qual_name(d)); + } else if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + return (false); + case SIMPLE_HASH('n', 'w') : + d->p += 2; + return (vector_str_push(&d->vec, "operator new()", 14)); + case SIMPLE_HASH('d', 'l') : + d->p += 2; + return (vector_str_push(&d->vec, "operator delete()", + 17)); + case SIMPLE_HASH('o', 'p') : + /* __op<TO_TYPE>__<FROM_TYPE> */ + d->p += 2; + + d->type = ENCODE_OP_USER; + + return (read_op_user(d)); + default : + return (false); + }; +} + +static bool +read_op_user(struct demangle_data *d) +{ + struct demangle_data from, to; + size_t from_len, to_len; + bool rtn; + char *from_str, *to_str; + + if (d == NULL) + return (false); + + if (init_demangle_data(&from) == false) + return (false); + + rtn = false; + from_str = NULL; + to_str = NULL; + if (init_demangle_data(&to) == false) + goto clean; + + to.p = d->p; + if (*to.p == 'Q') { + ++to.p; + + if (read_qual_name(&to) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&to.vec) == false) + goto clean; + } else { + if (read_class(&to) == false) + goto clean; + + /* skip '__' */ + to.p += 2; + } + + if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL) + goto clean; + + from.p = to.p; + if (*from.p == 'Q') { + ++from.p; + + if (read_qual_name(&from) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&from.vec) == false) + goto clean; + } else { + if (read_class(&from) == false) + goto clean; + } + + if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, from_str, from_len) == false) + goto clean; + + if (vector_str_push(&d->vec, "::operator ", 11) == false) + return (false); + + if (vector_str_push(&d->vec, to_str, to_len) == false) + goto clean; + + rtn = vector_str_push(&d->vec, "()", 2); +clean: + free(to_str); + free(from_str); + dest_demangle_data(&to); + dest_demangle_data(&from); + + return (rtn); +} + +/* single digit + class names */ +static bool +read_qual_name(struct demangle_data *d) +{ + int i; + char num; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + num = *d->p - 48; + + assert(num > 0); + + ++d->p; + for (i = 0; i < num ; ++i) { + if (read_class(d) == false) + return (false); + + if (vector_str_push(&d->vec, "::", 2) == false) + return (false); + } + + if (*d->p != '\0') + d->p = d->p + 2; + + return (true); +} + +/* Return -1 at fail, 0 at success, and 1 at end */ +static int +read_subst(struct demangle_data *d) +{ + size_t idx; + char *str; + + if (d == NULL) + return (-1); + + idx = strtol(d->p + 1, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + if (vector_str_push(&d->vec, d->arg.container[idx - 1], + strlen(d->arg.container[idx - 1])) == false) + return (-1); + + if (vector_str_push(&d->arg, d->arg.container[idx - 1], + strlen(d->arg.container[idx - 1])) == false) + return (-1); + + if (*d->p == '\0') + return (1); + + return (0); +} + +static int +read_subst_iter(struct demangle_data *d) +{ + int i; + size_t idx; + char repeat; + char *str; + + if (d == NULL) + return (-1); + + ++d->p; + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + repeat = *d->p - 48; + + assert(repeat > 1); + + ++d->p; + + idx = strtol(d->p, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + for (i = 0; i < repeat ; ++i) { + if (vector_str_push(&d->vec, d->arg.container[idx - 1], + strlen(d->arg.container[idx - 1])) == false) + return (-1); + + if (vector_str_push(&d->arg, d->arg.container[idx - 1], + strlen(d->arg.container[idx - 1])) == false) + return (-1); + + if (i != repeat - 1 && + vector_str_push(&d->vec, ", ", 2) == false) + return (-1); + } + + if (*d->p == '\0') + return (1); + + return (0); +} + +static bool +read_type(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' || + *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' || + *d->p == 'M') { + switch (*d->p) { + case 'U' : + ++d->p; + + if (vector_str_push(&d->vec, "unsigned ", 9) == false) + return (false); + + break; + case 'C' : + ++d->p; + + if (*d->p == 'P') + d->cnst = true; + else { + if (vector_str_push(&d->vec, "const ", 6) == + false) + return (false); + } + + break; + case 'V' : + ++d->p; + + if (vector_str_push(&d->vec, "volatile ", 9) == false) + return (false); + + break; + case 'S' : + ++d->p; + + if (vector_str_push(&d->vec, "signed ", 7) == false) + return (false); + + break; + case 'P' : + ++d->p; + + if (*d->p == 'F') + return (read_func_ptr(d)); + else + d->ptr = true; + + break; + case 'R' : + ++d->p; + + d->ref = true; + + break; + case 'F' : + break; + case 'A' : + ++d->p; + + if (read_array(d) == false) + return (false); + + break; + case 'M' : + ++d->p; + + if (read_memptr(d) == false) + return (false); + + break; + default : + break; + }; + }; + + if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + switch (*d->p) { + case 'Q' : + ++d->p; + + return (read_qual_name(d)); + case 'v' : + ++d->p; + + return (vector_str_push(&d->vec, "void", 4)); + case 'c' : + ++d->p; + + return (vector_str_push(&d->vec, "char", 4)); + case 's' : + ++d->p; + + return (vector_str_push(&d->vec, "short", 5)); + case 'i' : + ++d->p; + + return (vector_str_push(&d->vec, "int", 3)); + case 'l' : + ++d->p; + + return (vector_str_push(&d->vec, "long", 4)); + case 'f' : + ++d->p; + + return (vector_str_push(&d->vec, "float", 5)); + case 'd': + ++d->p; + + return (vector_str_push(&d->vec, "double", 6)); + case 'r': + ++d->p; + + return (vector_str_push(&d->vec, "long double", 11)); + case 'e': + ++d->p; + + return (vector_str_push(&d->vec, "...", 3)); + default: + return (false); + }; + + /* NOTREACHED */ + return (false); +} |