aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2017-06-25 22:19:01 +0000
committerEd Maste <emaste@FreeBSD.org>2017-06-25 22:19:01 +0000
commit2b7f789ebfc1d2b049bf705a49f76e078e3b11b7 (patch)
tree7c99930aa2aec9afef2f469345940b4d94ad176f
parent8cc1f6cc64e76b11cee23af79828b63cd7be4c09 (diff)
Import ELF Tool Chain snapshot at r3561vendor/elftoolchain/elftoolchain-r3561
Notes
Notes: svn path=/vendor/elftoolchain/dist/; revision=320341 svn path=/vendor/elftoolchain/elftoolchain-r3561/; revision=320342; tag=vendor/elftoolchain/elftoolchain-r3561
-rw-r--r--elfdump/elfdump.c6
-rw-r--r--libelftc/_libelftc.h4
-rw-r--r--libelftc/libelftc_dem_gnu3.c757
-rw-r--r--libelftc/libelftc_vstr.c43
-rw-r--r--test/cxxfilt/tet_scen24
-rw-r--r--test/cxxfilt/ts/Makefile4
-rw-r--r--test/cxxfilt/ts/builtin/Makefile5
-rw-r--r--test/cxxfilt/ts/builtin/tclist48
-rw-r--r--test/cxxfilt/ts/misc/tclist40
-rw-r--r--test/cxxfilt/ts/qualifiers/Makefile5
-rw-r--r--test/cxxfilt/ts/qualifiers/tclist36
-rw-r--r--test/cxxfilt/ts/substitute/Makefile5
-rw-r--r--test/cxxfilt/ts/substitute/tclist56
-rw-r--r--test/cxxfilt/ts/template/Makefile5
-rw-r--r--test/cxxfilt/ts/template/tclist10
-rw-r--r--test/elfcopy/plugin/os.FreeBSD.mk2
16 files changed, 857 insertions, 193 deletions
diff --git a/elfdump/elfdump.c b/elfdump/elfdump.c
index 2e8620c2d492..6194554b85d8 100644
--- a/elfdump/elfdump.c
+++ b/elfdump/elfdump.c
@@ -50,7 +50,7 @@
#include "_elftc.h"
-ELFTC_VCSID("$Id: elfdump.c 3497 2016-10-17 20:57:22Z emaste $");
+ELFTC_VCSID("$Id: elfdump.c 3521 2017-06-04 20:07:09Z jkoshy $");
#if defined(ELFTC_NEED_ELF_NOTE_DEFINITION)
#include "native-elf-format.h"
@@ -2226,8 +2226,8 @@ elf_print_svr4_hash64(struct elfdump *ed, struct section *s)
uint64_t *buf;
uint64_t *bucket, *chain;
uint64_t nbucket, nchain;
- uint64_t *bl, *c, maxl, total;
- uint64_t i, j;
+ uint64_t *bl, *c, j, maxl, total;
+ size_t i;
int elferr, first;
char idx[10];
diff --git a/libelftc/_libelftc.h b/libelftc/_libelftc.h
index ba0b10112a57..a56e29ee4a5b 100644
--- a/libelftc/_libelftc.h
+++ b/libelftc/_libelftc.h
@@ -24,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: _libelftc.h 3174 2015-03-27 17:13:41Z emaste $
+ * $Id: _libelftc.h 3531 2017-06-05 05:08:43Z kaiwang27 $
*/
#ifndef __LIBELFTC_H_
@@ -82,6 +82,8 @@ bool vector_str_init(struct vector_str *_vs);
bool vector_str_pop(struct vector_str *_vs);
bool vector_str_push(struct vector_str *_vs, const char *_str,
size_t _len);
+bool vector_str_push_vector(struct vector_str *_dst,
+ struct vector_str *_org);
bool vector_str_push_vector_head(struct vector_str *_dst,
struct vector_str *_org);
char *vector_str_substr(const struct vector_str *_vs, size_t _begin,
diff --git a/libelftc/libelftc_dem_gnu3.c b/libelftc/libelftc_dem_gnu3.c
index bd571228fb1a..9f04999ed5b6 100644
--- a/libelftc/libelftc_dem_gnu3.c
+++ b/libelftc/libelftc_dem_gnu3.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com>
+ * Copyright (c) 2015-2017 Kai Wang <kaiwang27@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,7 +37,7 @@
#include "_libelftc.h"
-ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3512 2016-12-29 07:04:19Z kaiwang27 $");
+ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3560 2017-06-25 00:28:23Z kaiwang27 $");
/**
* @file cpp_demangle.c
@@ -50,7 +51,7 @@ ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3512 2016-12-29 07:04:19Z kaiwang27 $");
enum type_qualifier {
TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT,
- TYPE_CST, TYPE_VEC
+ TYPE_CST, TYPE_VEC, TYPE_RREF
};
struct vector_type_qualifier {
@@ -64,27 +65,47 @@ enum read_cmd {
READ_TYPE, READ_FUNC, READ_PTRMEM
};
+struct read_cmd_item {
+ enum read_cmd cmd;
+ void *data;
+};
+
struct vector_read_cmd {
size_t size, capacity;
- enum read_cmd *r_container;
+ struct read_cmd_item *r_container;
+};
+
+enum push_qualifier {
+ PUSH_ALL_QUALIFIER,
+ PUSH_CV_QUALIFIER,
+ PUSH_NON_CV_QUALIFIER,
};
struct cpp_demangle_data {
struct vector_str output; /* output string vector */
- struct vector_str output_tmp;
struct vector_str subst; /* substitution string vector */
struct vector_str tmpl;
struct vector_str class_type;
+ struct vector_str *cur_output; /* ptr to current output vec */
struct vector_read_cmd cmd;
- bool paren; /* parenthesis opened */
- bool pfirst; /* first element of parameter */
bool mem_rst; /* restrict member function */
bool mem_vat; /* volatile member function */
bool mem_cst; /* const member function */
+ bool mem_ref; /* lvalue-ref member func */
+ bool mem_rref; /* rvalue-ref member func */
+ bool is_tmpl; /* template args */
+ bool is_functype; /* function type */
+ bool ref_qualifier; /* ref qualifier */
+ enum type_qualifier ref_qualifier_type; /* ref qualifier type */
+ enum push_qualifier push_qualifier; /* which qualifiers to push */
int func_type;
const char *cur; /* current mangled name ptr */
const char *last_sname; /* last source name */
- int push_head;
+};
+
+struct type_delimit {
+ bool paren;
+ bool firstp;
};
#define CPP_DEMANGLE_TRY_LIMIT 128
@@ -105,6 +126,7 @@ static int cpp_demangle_push_fp(struct cpp_demangle_data *,
char *(*)(const char *, size_t));
static int cpp_demangle_push_str(struct cpp_demangle_data *, const char *,
size_t);
+static int cpp_demangle_pop_str(struct cpp_demangle_data *);
static int cpp_demangle_push_subst(struct cpp_demangle_data *,
const char *, size_t);
static int cpp_demangle_push_subst_v(struct cpp_demangle_data *,
@@ -137,16 +159,18 @@ static int cpp_demangle_read_number_as_string(struct cpp_demangle_data *,
static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *);
static int cpp_demangle_read_offset(struct cpp_demangle_data *);
static int cpp_demangle_read_offset_number(struct cpp_demangle_data *);
-static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *);
+static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *,
+ struct vector_type_qualifier *);
static int cpp_demangle_read_sname(struct cpp_demangle_data *);
static int cpp_demangle_read_subst(struct cpp_demangle_data *);
static int cpp_demangle_read_subst_std(struct cpp_demangle_data *);
static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *,
- const char *, size_t);
+ const char *);
static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *);
static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *);
static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *);
-static int cpp_demangle_read_type(struct cpp_demangle_data *, int);
+static int cpp_demangle_read_type(struct cpp_demangle_data *,
+ struct type_delimit *);
static int cpp_demangle_read_type_flat(struct cpp_demangle_data *,
char **);
static int cpp_demangle_read_uqname(struct cpp_demangle_data *);
@@ -158,10 +182,12 @@ static char *decode_fp_to_float80(const char *, size_t);
static char *decode_fp_to_long_double(const char *, size_t);
static int hex_to_dec(char);
static void vector_read_cmd_dest(struct vector_read_cmd *);
-static int vector_read_cmd_find(struct vector_read_cmd *, enum read_cmd);
+static struct read_cmd_item *vector_read_cmd_find(struct vector_read_cmd *,
+ enum read_cmd);
static int vector_read_cmd_init(struct vector_read_cmd *);
static int vector_read_cmd_pop(struct vector_read_cmd *);
-static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd);
+static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd,
+ void *);
static void vector_type_qualifier_dest(struct vector_type_qualifier *);
static int vector_type_qualifier_init(struct vector_type_qualifier *);
static int vector_type_qualifier_push(struct vector_type_qualifier *,
@@ -178,9 +204,12 @@ char *
cpp_demangle_gnu3(const char *org)
{
struct cpp_demangle_data ddata;
+ struct vector_str ret_type;
+ struct type_delimit td;
ssize_t org_len;
unsigned int limit;
char *rtn;
+ bool has_ret, more_type;
if (org == NULL || (org_len = strlen(org)) < 2)
return (NULL);
@@ -200,26 +229,75 @@ cpp_demangle_gnu3(const char *org)
return (NULL);
rtn = NULL;
+ has_ret = more_type = false;
if (!cpp_demangle_read_encoding(&ddata))
goto clean;
+ /*
+ * Pop function name from substitution candidate list.
+ */
+ if (*ddata.cur != 0 && ddata.subst.size >= 1) {
+ if (!vector_str_pop(&ddata.subst))
+ goto clean;
+ }
+
+ td.paren = false;
+ td.firstp = true;
limit = 0;
+
+ /*
+ * The first type is a return type if we just demangled template
+ * args. (the template args is right next to the function name,
+ * which means it's a template function)
+ */
+ if (ddata.is_tmpl) {
+ ddata.is_tmpl = false;
+ if (!vector_str_init(&ret_type))
+ goto clean;
+ ddata.cur_output = &ret_type;
+ has_ret = true;
+ }
+
while (*ddata.cur != '\0') {
/*
* Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4
*/
if (*ddata.cur == '@' && *(ddata.cur + 1) == '@')
break;
- if (!cpp_demangle_read_type(&ddata, 1))
- goto clean;
+
+ if (has_ret) {
+ /* Read return type */
+ if (!cpp_demangle_read_type(&ddata, NULL))
+ goto clean;
+ } else {
+ /* Read function arg type */
+ if (!cpp_demangle_read_type(&ddata, &td))
+ goto clean;
+ }
+
+ if (has_ret) {
+ /* Push return type to the beginning */
+ if (!VEC_PUSH_STR(&ret_type, " "))
+ goto clean;
+ if (!vector_str_push_vector_head(&ddata.output,
+ &ret_type))
+ goto clean;
+ ddata.cur_output = &ddata.output;
+ vector_str_dest(&ret_type);
+ has_ret = false;
+ more_type = true;
+ } else if (more_type)
+ more_type = false;
if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
goto clean;
}
+ if (more_type)
+ goto clean;
if (ddata.output.size == 0)
goto clean;
- if (ddata.paren && !VEC_PUSH_STR(&ddata.output, ")"))
+ if (td.paren && !VEC_PUSH_STR(&ddata.output, ")"))
goto clean;
if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile"))
goto clean;
@@ -227,10 +305,17 @@ cpp_demangle_gnu3(const char *org)
goto clean;
if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict"))
goto clean;
+ if (ddata.mem_ref && !VEC_PUSH_STR(&ddata.output, " &"))
+ goto clean;
+ if (ddata.mem_rref && !VEC_PUSH_STR(&ddata.output, " &&"))
+ goto clean;
rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
clean:
+ if (has_ret)
+ vector_str_dest(&ret_type);
+
cpp_demangle_data_dest(&ddata);
return (rtn);
@@ -247,7 +332,6 @@ cpp_demangle_data_dest(struct cpp_demangle_data *d)
vector_str_dest(&d->class_type);
vector_str_dest(&d->tmpl);
vector_str_dest(&d->subst);
- vector_str_dest(&d->output_tmp);
vector_str_dest(&d->output);
}
@@ -260,43 +344,42 @@ cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur)
if (!vector_str_init(&d->output))
return (0);
- if (!vector_str_init(&d->output_tmp))
- goto clean1;
if (!vector_str_init(&d->subst))
- goto clean2;
+ goto clean1;
if (!vector_str_init(&d->tmpl))
- goto clean3;
+ goto clean2;
if (!vector_str_init(&d->class_type))
- goto clean4;
+ goto clean3;
if (!vector_read_cmd_init(&d->cmd))
- goto clean5;
+ goto clean4;
assert(d->output.container != NULL);
- assert(d->output_tmp.container != NULL);
assert(d->subst.container != NULL);
assert(d->tmpl.container != NULL);
assert(d->class_type.container != NULL);
- d->paren = false;
- d->pfirst = false;
d->mem_rst = false;
d->mem_vat = false;
d->mem_cst = false;
+ d->mem_ref = false;
+ d->mem_rref = false;
+ d->is_tmpl = false;
+ d->is_functype = false;
+ d->ref_qualifier = false;
+ d->push_qualifier = PUSH_ALL_QUALIFIER;
d->func_type = 0;
d->cur = cur;
+ d->cur_output = &d->output;
d->last_sname = NULL;
- d->push_head = 0;
return (1);
-clean5:
- vector_str_dest(&d->class_type);
clean4:
- vector_str_dest(&d->tmpl);
+ vector_str_dest(&d->class_type);
clean3:
- vector_str_dest(&d->subst);
+ vector_str_dest(&d->tmpl);
clean2:
- vector_str_dest(&d->output_tmp);
+ vector_str_dest(&d->subst);
clean1:
vector_str_dest(&d->output);
@@ -341,10 +424,24 @@ cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str,
if (ddata == NULL || str == NULL || len == 0)
return (0);
- if (ddata->push_head > 0)
- return (vector_str_push(&ddata->output_tmp, str, len));
+ /*
+ * is_tmpl is used to check if the type (function arg) is right next
+ * to template args, and should always be cleared whenever new string
+ * pushed.
+ */
+ ddata->is_tmpl = false;
+
+ return (vector_str_push(ddata->cur_output, str, len));
+}
+
+static int
+cpp_demangle_pop_str(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
- return (vector_str_push(&ddata->output, str, len));
+ return (vector_str_pop(ddata->cur_output));
}
static int
@@ -386,9 +483,11 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
struct vector_type_qualifier *v, const char *type_str)
{
struct vector_str subst_v;
+ enum type_qualifier t;
size_t idx, e_idx, e_len;
- int rtn;
char *buf;
+ int rtn;
+ bool cv;
if (ddata == NULL || v == NULL)
return (0);
@@ -404,10 +503,14 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
goto clean;
}
+ cv = true;
e_idx = 0;
while (idx > 0) {
switch (v->q_container[idx - 1]) {
case TYPE_PTR:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (!DEM_PUSH_STR(ddata, "*"))
goto clean;
if (type_str != NULL) {
@@ -420,6 +523,9 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_REF:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (!DEM_PUSH_STR(ddata, "&"))
goto clean;
if (type_str != NULL) {
@@ -431,7 +537,25 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
}
break;
+ case TYPE_RREF:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
+ if (!DEM_PUSH_STR(ddata, "&&"))
+ goto clean;
+ if (type_str != NULL) {
+ if (!VEC_PUSH_STR(&subst_v, "&&"))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata,
+ &subst_v))
+ goto clean;
+ }
+ break;
+
case TYPE_CMX:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (!DEM_PUSH_STR(ddata, " complex"))
goto clean;
if (type_str != NULL) {
@@ -444,6 +568,9 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_IMG:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (!DEM_PUSH_STR(ddata, " imaginary"))
goto clean;
if (type_str != NULL) {
@@ -457,6 +584,9 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_EXT:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (v->ext_name.size == 0 ||
e_idx > v->ext_name.size - 1)
goto clean;
@@ -489,11 +619,22 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_RST:
+ if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+ cv)
+ break;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+ break;
if (!DEM_PUSH_STR(ddata, " restrict"))
goto clean;
if (type_str != NULL) {
if (!VEC_PUSH_STR(&subst_v, " restrict"))
goto clean;
+ if (idx - 1 > 0) {
+ t = v->q_container[idx - 2];
+ if (t == TYPE_RST || t == TYPE_VAT ||
+ t == TYPE_CST)
+ break;
+ }
if (!cpp_demangle_push_subst_v(ddata,
&subst_v))
goto clean;
@@ -501,11 +642,22 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_VAT:
+ if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+ cv)
+ break;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+ break;
if (!DEM_PUSH_STR(ddata, " volatile"))
goto clean;
if (type_str != NULL) {
if (!VEC_PUSH_STR(&subst_v, " volatile"))
goto clean;
+ if (idx - 1 > 0) {
+ t = v->q_container[idx - 2];
+ if (t == TYPE_RST || t == TYPE_VAT ||
+ t == TYPE_CST)
+ break;
+ }
if (!cpp_demangle_push_subst_v(ddata,
&subst_v))
goto clean;
@@ -513,11 +665,22 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_CST:
+ if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+ cv)
+ break;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+ break;
if (!DEM_PUSH_STR(ddata, " const"))
goto clean;
if (type_str != NULL) {
if (!VEC_PUSH_STR(&subst_v, " const"))
goto clean;
+ if (idx - 1 > 0) {
+ t = v->q_container[idx - 2];
+ if (t == TYPE_RST || t == TYPE_VAT ||
+ t == TYPE_CST)
+ break;
+ }
if (!cpp_demangle_push_subst_v(ddata,
&subst_v))
goto clean;
@@ -525,6 +688,9 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
break;
case TYPE_VEC:
+ cv = false;
+ if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+ break;
if (v->ext_name.size == 0 ||
e_idx > v->ext_name.size - 1)
goto clean;
@@ -614,7 +780,7 @@ cpp_demangle_read_array(struct cpp_demangle_data *ddata)
if (*(++ddata->cur) == '\0')
return (0);
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
if (!DEM_PUSH_STR(ddata, "[]"))
@@ -630,7 +796,7 @@ cpp_demangle_read_array(struct cpp_demangle_data *ddata)
assert(num_len > 0);
if (*(++ddata->cur) == '\0')
return (0);
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
if (!DEM_PUSH_STR(ddata, "["))
return (0);
@@ -660,7 +826,7 @@ cpp_demangle_read_array(struct cpp_demangle_data *ddata)
free(exp);
return (0);
}
- if (!cpp_demangle_read_type(ddata, 0)) {
+ if (!cpp_demangle_read_type(ddata, NULL)) {
free(exp);
return (0);
}
@@ -777,11 +943,11 @@ cpp_demangle_read_expression(struct cpp_demangle_data *ddata)
switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
case SIMPLE_HASH('s', 't'):
ddata->cur += 2;
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('s', 'r'):
ddata->cur += 2;
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
if (!cpp_demangle_read_uqname(ddata))
return (0);
@@ -1058,8 +1224,7 @@ cpp_demangle_read_expression_flat(struct cpp_demangle_data *ddata, char **str)
size_t i, p_idx, idx, exp_len;
char *exp;
- output = ddata->push_head > 0 ? &ddata->output_tmp :
- &ddata->output;
+ output = &ddata->output;
p_idx = output->size;
@@ -1136,8 +1301,12 @@ static int
cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
struct vector_type_qualifier *v)
{
+ struct type_delimit td;
+ struct read_cmd_item *rc;
size_t class_type_size, class_type_len, limit;
const char *class_type;
+ int i;
+ bool paren, non_cv_qualifier;
if (ddata == NULL || *ddata->cur != 'F' || v == NULL)
return (0);
@@ -1148,12 +1317,43 @@ cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
*ext_c = 1;
++ddata->cur;
}
- if (!cpp_demangle_read_type(ddata, 0))
+
+ /* Return type */
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
+
if (*ddata->cur != 'E') {
- if (!DEM_PUSH_STR(ddata, "("))
+ if (!DEM_PUSH_STR(ddata, " "))
+ return (0);
+
+ non_cv_qualifier = false;
+ if (v->size > 0) {
+ for (i = 0; (size_t) i < v->size; i++) {
+ if (v->q_container[i] != TYPE_RST &&
+ v->q_container[i] != TYPE_VAT &&
+ v->q_container[i] != TYPE_CST) {
+ non_cv_qualifier = true;
+ break;
+ }
+ }
+ }
+
+ paren = false;
+ rc = vector_read_cmd_find(&ddata->cmd, READ_PTRMEM);
+ if (non_cv_qualifier || rc != NULL) {
+ if (!DEM_PUSH_STR(ddata, "("))
+ return (0);
+ paren = true;
+ }
+
+ /* Push non-cv qualifiers. */
+ ddata->push_qualifier = PUSH_NON_CV_QUALIFIER;
+ if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
return (0);
- if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM)) {
+
+ if (rc) {
+ if (non_cv_qualifier && !DEM_PUSH_STR(ddata, " "))
+ return (0);
if ((class_type_size = ddata->class_type.size) == 0)
return (0);
class_type =
@@ -1167,40 +1367,67 @@ cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
return (0);
if (!DEM_PUSH_STR(ddata, "::*"))
return (0);
- ++ddata->func_type;
- } else {
- if (!cpp_demangle_push_type_qualifier(ddata, v,
- (const char *) NULL))
- return (0);
- vector_type_qualifier_dest(v);
- if (!vector_type_qualifier_init(v))
+ /* Push pointer-to-member qualifiers. */
+ ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+ if (!cpp_demangle_push_type_qualifier(ddata, rc->data,
+ NULL))
return (0);
+ ++ddata->func_type;
}
- if (!DEM_PUSH_STR(ddata, ")("))
- return (0);
+ if (paren) {
+ if (!DEM_PUSH_STR(ddata, ")"))
+ return (0);
+ paren = false;
+ }
+ td.paren = false;
+ td.firstp = true;
limit = 0;
+ ddata->is_functype = true;
for (;;) {
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, &td))
return (0);
if (*ddata->cur == 'E')
break;
if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
return (0);
}
-
- if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM) == 1) {
- if (!cpp_demangle_push_type_qualifier(ddata, v,
- (const char *) NULL))
- return (0);
- vector_type_qualifier_dest(v);
- if (!vector_type_qualifier_init(v))
+ ddata->is_functype = false;
+ if (td.paren) {
+ if (!DEM_PUSH_STR(ddata, ")"))
return (0);
+ td.paren = false;
}
- if (!DEM_PUSH_STR(ddata, ")"))
+ /* Push CV qualifiers. */
+ ddata->push_qualifier = PUSH_CV_QUALIFIER;
+ if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
return (0);
+
+ ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+
+ /* Release type qualifier vector. */
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+
+ /* Push ref-qualifiers. */
+ if (ddata->ref_qualifier) {
+ switch (ddata->ref_qualifier_type) {
+ case TYPE_REF:
+ if (!DEM_PUSH_STR(ddata, " &"))
+ return (0);
+ break;
+ case TYPE_RREF:
+ if (!DEM_PUSH_STR(ddata, " &&"))
+ return (0);
+ break;
+ default:
+ return (0);
+ }
+ ddata->ref_qualifier = false;
+ }
}
++ddata->cur;
@@ -1306,7 +1533,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
goto clean3;
if (*ddata->cur++ != '_')
goto clean3;
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
goto clean3;
if (!DEM_PUSH_STR(ddata, "-in-"))
goto clean3;
@@ -1328,7 +1555,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'h'):
/* virtual function non-virtual override thunk */
@@ -1358,7 +1585,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'J'):
/* java class */
@@ -1367,7 +1594,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'S'):
/* RTTI name (NTBS) */
@@ -1376,7 +1603,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'T'):
/* VTT table */
@@ -1385,7 +1612,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'v'):
/* virtual function virtual override thunk */
@@ -1406,7 +1633,7 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == '\0')
return (0);
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('T', 'W'):
/* TLS wrapper function */
@@ -1424,30 +1651,74 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
static int
cpp_demangle_read_local_name(struct cpp_demangle_data *ddata)
{
+ struct vector_str local_name;
+ struct type_delimit td;
size_t limit;
+ bool more_type;
if (ddata == NULL)
return (0);
if (*(++ddata->cur) == '\0')
return (0);
- if (!cpp_demangle_read_encoding(ddata))
+
+ vector_str_init(&local_name);
+ ddata->cur_output = &local_name;
+
+ if (!cpp_demangle_read_encoding(ddata)) {
+ vector_str_dest(&local_name);
return (0);
+ }
+ ddata->cur_output = &ddata->output;
+
+ td.paren = false;
+ td.firstp = true;
+ more_type = false;
limit = 0;
- for (;;) {
- if (!cpp_demangle_read_type(ddata, 1))
+
+ /*
+ * The first type is a return type if we just demangled template
+ * args. (the template args is right next to the function name,
+ * which means it's a template function)
+ */
+ if (ddata->is_tmpl) {
+ ddata->is_tmpl = false;
+
+ /* Read return type */
+ if (!cpp_demangle_read_type(ddata, NULL)) {
+ vector_str_dest(&local_name);
+ return (0);
+ }
+
+ more_type = true;
+ }
+
+ /* Now we can push the name after possible return type is handled. */
+ if (!vector_str_push_vector(&ddata->output, &local_name)) {
+ vector_str_dest(&local_name);
+ return (0);
+ }
+ vector_str_dest(&local_name);
+
+ while (*ddata->cur != '\0') {
+ if (!cpp_demangle_read_type(ddata, &td))
return (0);
+ if (more_type)
+ more_type = false;
if (*ddata->cur == 'E')
break;
if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
return (0);
}
+ if (more_type)
+ return (0);
+
if (*(++ddata->cur) == '\0')
return (0);
- if (ddata->paren == true) {
+ if (td.paren == true) {
if (!DEM_PUSH_STR(ddata, ")"))
return (0);
- ddata->paren = false;
+ td.paren = false;
}
if (*ddata->cur == 's')
++ddata->cur;
@@ -1477,7 +1748,7 @@ cpp_demangle_read_name(struct cpp_demangle_data *ddata)
if (ddata == NULL || *ddata->cur == '\0')
return (0);
- output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ output = ddata->cur_output;
subst_str = NULL;
@@ -1539,8 +1810,7 @@ cpp_demangle_read_name_flat(struct cpp_demangle_data *ddata, char **str)
size_t i, p_idx, idx, name_len;
char *name;
- output = ddata->push_head > 0 ? &ddata->output_tmp :
- &ddata->output;
+ output = ddata->cur_output;
p_idx = output->size;
@@ -1577,8 +1847,7 @@ cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
if (*(++ddata->cur) == '\0')
return (0);
- while (*ddata->cur == 'r' || *ddata->cur == 'V' ||
- *ddata->cur == 'K') {
+ do {
switch (*ddata->cur) {
case 'r':
ddata->mem_rst = true;
@@ -1589,11 +1858,19 @@ cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
case 'K':
ddata->mem_cst = true;
break;
+ case 'R':
+ ddata->mem_ref = true;
+ break;
+ case 'O':
+ ddata->mem_rref = true;
+ break;
+ default:
+ goto next;
}
- ++ddata->cur;
- }
+ } while (*(++ddata->cur));
- output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+next:
+ output = ddata->cur_output;
if (!vector_str_init(&v))
return (0);
@@ -1619,6 +1896,8 @@ cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
goto clean;
}
+ if (p_idx == output->size)
+ goto next_comp;
if ((subst_str = vector_str_substr(output, p_idx,
output->size - 1, &subst_str_len)) == NULL)
goto clean;
@@ -1630,10 +1909,12 @@ cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
if (!cpp_demangle_push_subst_v(ddata, &v))
goto clean;
+
+ next_comp:
if (*ddata->cur == 'E')
break;
- else if (*ddata->cur != 'I' &&
- *ddata->cur != 'C' && *ddata->cur != 'D') {
+ else if (*ddata->cur != 'I' && *ddata->cur != 'C' &&
+ *ddata->cur != 'D' && p_idx != output->size) {
if (!DEM_PUSH_STR(ddata, "::"))
goto clean;
if (!VEC_PUSH_STR(&v, "::"))
@@ -1776,7 +2057,8 @@ cpp_demangle_read_offset_number(struct cpp_demangle_data *ddata)
}
static int
-cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
+cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata,
+ struct vector_type_qualifier *v)
{
size_t class_type_len, i, idx, p_idx;
int p_func_type, rtn;
@@ -1786,7 +2068,7 @@ cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
return (0);
p_idx = ddata->output.size;
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
if ((class_type = vector_str_substr(&ddata->output, p_idx,
@@ -1799,14 +2081,14 @@ cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
if (!vector_str_pop(&ddata->output))
goto clean1;
- if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM))
+ if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM, v))
goto clean1;
if (!vector_str_push(&ddata->class_type, class_type, class_type_len))
goto clean2;
p_func_type = ddata->func_type;
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
goto clean3;
if (p_func_type == ddata->func_type) {
@@ -1828,6 +2110,10 @@ clean2:
clean1:
free(class_type);
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+
return (rtn);
}
@@ -1851,7 +2137,7 @@ cpp_demangle_read_sname(struct cpp_demangle_data *ddata)
return (0);
assert(ddata->output.size > 0);
- if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == 0)
+ if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == NULL)
ddata->last_sname =
ddata->output.container[ddata->output.size - 1];
@@ -1877,7 +2163,7 @@ cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::allocator", 14));
+ "std::allocator"));
return (1);
case SIMPLE_HASH('S', 'b'):
@@ -1887,40 +2173,46 @@ cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::basic_string", 17));
+ "std::basic_string"));
return (1);
case SIMPLE_HASH('S', 'd'):
/* std::basic_iostream<char, std::char_traits<char> > */
- if (!DEM_PUSH_STR(ddata, "std::basic_iostream"))
+ if (!DEM_PUSH_STR(ddata, "std::basic_iostream<char, "
+ "std::char_traits<char> >"))
return (0);
ddata->last_sname = "basic_iostream";
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::basic_iostream", 19));
+ "std::basic_iostream<char, std::char_traits"
+ "<char> >"));
return (1);
case SIMPLE_HASH('S', 'i'):
/* std::basic_istream<char, std::char_traits<char> > */
- if (!DEM_PUSH_STR(ddata, "std::basic_istream"))
+ if (!DEM_PUSH_STR(ddata, "std::basic_istream<char, "
+ "std::char_traits<char> >"))
return (0);
ddata->last_sname = "basic_istream";
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::basic_istream", 18));
+ "std::basic_istream<char, std::char_traits"
+ "<char> >"));
return (1);
case SIMPLE_HASH('S', 'o'):
/* std::basic_ostream<char, std::char_traits<char> > */
- if (!DEM_PUSH_STR(ddata, "std::basic_ostream"))
+ if (!DEM_PUSH_STR(ddata, "std::basic_ostream<char, "
+ "std::char_traits<char> >"))
return (0);
ddata->last_sname = "basic_ostream";
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::basic_ostream", 18));
+ "std::basic_ostream<char, std::char_traits"
+ "<char> >"));
return (1);
case SIMPLE_HASH('S', 's'):
@@ -1930,13 +2222,15 @@ cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
*
* a.k.a std::string
*/
- if (!DEM_PUSH_STR(ddata, "std::string"))
+ if (!DEM_PUSH_STR(ddata, "std::basic_string<char, "
+ "std::char_traits<char>, std::allocator<char> >"))
return (0);
ddata->last_sname = "string";
ddata->cur += 2;
if (*ddata->cur == 'I')
return (cpp_demangle_read_subst_stdtmpl(ddata,
- "std::string", 11));
+ "std::basic_string<char, std::char_traits<char>,"
+ " std::allocator<char> >"));
return (1);
case SIMPLE_HASH('S', 't'):
@@ -1947,6 +2241,14 @@ cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
if (*(++ddata->cur) == '\0')
return (0);
+ /* Skip unknown substitution abbreviations. */
+ if (!(*ddata->cur >= '0' && *ddata->cur <= '9') &&
+ !(*ddata->cur >= 'A' && *ddata->cur <= 'Z') &&
+ *ddata->cur != '_') {
+ ++ddata->cur;
+ return (1);
+ }
+
/* substitution */
if (*ddata->cur == '_')
return (cpp_demangle_get_subst(ddata, 0));
@@ -1996,7 +2298,7 @@ cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata)
ddata->cur += 2;
- output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ output = ddata->cur_output;
p_idx = output->size;
if (!cpp_demangle_read_uqname(ddata))
@@ -2036,17 +2338,20 @@ clean:
static int
cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata,
- const char *str, size_t len)
+ const char *str)
{
struct vector_str *output;
- size_t p_idx, substr_len;
+ size_t p_idx, substr_len, len;
int rtn;
char *subst_str, *substr;
- if (ddata == NULL || str == NULL || len == 0)
+ if (ddata == NULL || str == NULL)
return (0);
- output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ if ((len = strlen(str)) == 0)
+ return (0);
+
+ output = ddata->cur_output;
p_idx = output->size;
substr = NULL;
@@ -2089,10 +2394,13 @@ cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *ddata)
case 'L':
return (cpp_demangle_read_expr_primary(ddata));
case 'X':
- return (cpp_demangle_read_expression(ddata));
+ ++ddata->cur;
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ return (*ddata->cur++ == 'E');
}
- return (cpp_demangle_read_type(ddata, 0));
+ return (cpp_demangle_read_type(ddata, NULL));
}
static int
@@ -2107,14 +2415,14 @@ cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata)
++ddata->cur;
- if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL))
+ if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL, NULL))
return (0);
if (!DEM_PUSH_STR(ddata, "<"))
return (0);
limit = 0;
- v = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ v = &ddata->output;
for (;;) {
idx = v->size;
if (!cpp_demangle_read_tmpl_arg(ddata))
@@ -2139,6 +2447,7 @@ cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata)
return (0);
} else if (!DEM_PUSH_STR(ddata, ">"))
return (0);
+ ddata->is_tmpl = true;
break;
} else if (*ddata->cur != 'I' &&
!DEM_PUSH_STR(ddata, ", "))
@@ -2190,46 +2499,42 @@ cpp_demangle_read_tmpl_param(struct cpp_demangle_data *ddata)
}
static int
-cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit)
+cpp_demangle_read_type(struct cpp_demangle_data *ddata,
+ struct type_delimit *td)
{
struct vector_type_qualifier v;
- struct vector_str *output;
- size_t p_idx, type_str_len;
+ struct vector_str *output, sv;
+ size_t p_idx, type_str_len, subst_str_len;
int extern_c, is_builtin;
long len;
- char *type_str, *exp_str, *num_str;
+ const char *p;
+ char *type_str, *exp_str, *num_str, *subst_str;
+ bool skip_ref_qualifier, omit_void;
if (ddata == NULL)
return (0);
- output = &ddata->output;
- if (!strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) {
- ddata->push_head++;
- output = &ddata->output_tmp;
- } else if (delimit == 1) {
- if (ddata->paren == false) {
+ output = ddata->cur_output;
+ if (td) {
+ if (td->paren == false) {
if (!DEM_PUSH_STR(ddata, "("))
return (0);
if (ddata->output.size < 2)
return (0);
- ddata->paren = true;
- ddata->pfirst = true;
- /* Need pop function name */
- if (ddata->subst.size == 1 &&
- !vector_str_pop(&ddata->subst))
- return (0);
+ td->paren = true;
}
- if (ddata->pfirst)
- ddata->pfirst = false;
- else if (*ddata->cur != 'I' &&
- !DEM_PUSH_STR(ddata, ", "))
- return (0);
+ if (!td->firstp) {
+ if (*ddata->cur != 'I') {
+ if (!DEM_PUSH_STR(ddata, ", "))
+ return (0);
+ }
+ }
}
assert(output != NULL);
/*
- * [r, V, K] [P, R, C, G, U] builtin, function, class-enum, array
+ * [r, V, K] [P, R, O, C, G, U] builtin, function, class-enum, array
* pointer-to-member, template-param, template-template-param, subst
*/
@@ -2240,7 +2545,14 @@ cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit)
is_builtin = 1;
p_idx = output->size;
type_str = exp_str = num_str = NULL;
+ skip_ref_qualifier = false;
+
again:
+
+ /* Clear ref-qualifier flag */
+ if (*ddata->cur != 'R' && *ddata->cur != 'O' && *ddata->cur != 'E')
+ ddata->ref_qualifier = false;
+
/* builtin type */
switch (*ddata->cur) {
case 'a':
@@ -2269,6 +2581,8 @@ again:
if (!vector_type_qualifier_push(&v, TYPE_CMX))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'c':
@@ -2288,6 +2602,18 @@ again:
case 'D':
++ddata->cur;
switch (*ddata->cur) {
+ case 'a':
+ /* auto */
+ if (!DEM_PUSH_STR(ddata, "auto"))
+ goto clean;
+ ++ddata->cur;
+ break;
+ case 'c':
+ /* decltype(auto) */
+ if (!DEM_PUSH_STR(ddata, "decltype(auto)"))
+ goto clean;
+ ++ddata->cur;
+ break;
case 'd':
/* IEEE 754r decimal floating point (64 bits) */
if (!DEM_PUSH_STR(ddata, "decimal64"))
@@ -2352,6 +2678,8 @@ again:
++ddata->cur;
if (!vector_type_qualifier_push(&v, TYPE_VEC))
goto clean;
+ if (td)
+ td->firstp = false;
goto again;
default:
goto clean;
@@ -2365,6 +2693,16 @@ again:
++ddata->cur;
goto rtn;
+ case 'E':
+ /* unexpected end except ref-qualifiers */
+ if (ddata->ref_qualifier && ddata->is_functype) {
+ skip_ref_qualifier = true;
+ /* Pop the delimiter. */
+ cpp_demangle_pop_str(ddata);
+ goto rtn;
+ }
+ goto clean;
+
case 'f':
/* float */
if (!DEM_PUSH_STR(ddata, "float"))
@@ -2391,6 +2729,8 @@ again:
if (!vector_type_qualifier_push(&v, TYPE_IMG))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'h':
@@ -2407,6 +2747,32 @@ again:
++ddata->cur;
goto rtn;
+ case 'I':
+ /* template args. */
+ /* handles <substitute><template-args> */
+ p_idx = output->size;
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_init(&sv)) {
+ free(subst_str);
+ goto clean;
+ }
+ if (!vector_str_push(&sv, subst_str, subst_str_len)) {
+ free(subst_str);
+ vector_str_dest(&sv);
+ goto clean;
+ }
+ free(subst_str);
+ if (!cpp_demangle_push_subst_v(ddata, &sv)) {
+ vector_str_dest(&sv);
+ goto clean;
+ }
+ vector_str_dest(&sv);
+ goto rtn;
+
case 'j':
/* unsigned int */
if (!DEM_PUSH_STR(ddata, "unsigned int"))
@@ -2419,6 +2785,8 @@ again:
if (!vector_type_qualifier_push(&v, TYPE_CST))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'l':
@@ -2438,7 +2806,7 @@ again:
goto rtn;
case 'M':
/* pointer to member */
- if (!cpp_demangle_read_pointer_to_member(ddata))
+ if (!cpp_demangle_read_pointer_to_member(ddata, &v))
goto clean;
is_builtin = 0;
goto rtn;
@@ -2457,11 +2825,26 @@ again:
++ddata->cur;
goto rtn;
+ case 'O':
+ /* rvalue reference */
+ if (ddata->ref_qualifier)
+ goto clean;
+ if (!vector_type_qualifier_push(&v, TYPE_RREF))
+ goto clean;
+ ddata->ref_qualifier = true;
+ ddata->ref_qualifier_type = TYPE_RREF;
+ ++ddata->cur;
+ if (td)
+ td->firstp = false;
+ goto again;
+
case 'P':
/* pointer */
if (!vector_type_qualifier_push(&v, TYPE_PTR))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'r':
@@ -2469,13 +2852,21 @@ again:
if (!vector_type_qualifier_push(&v, TYPE_RST))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'R':
/* reference */
+ if (ddata->ref_qualifier)
+ goto clean;
if (!vector_type_qualifier_push(&v, TYPE_REF))
goto clean;
+ ddata->ref_qualifier = true;
+ ddata->ref_qualifier_type = TYPE_REF;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 's':
@@ -2516,6 +2907,7 @@ again:
case 'U':
/* vendor extended type qualifier */
+ ++ddata->cur;
if (!cpp_demangle_read_number(ddata, &len))
goto clean;
if (len <= 0)
@@ -2525,11 +2917,29 @@ again:
ddata->cur += len;
if (!vector_type_qualifier_push(&v, TYPE_EXT))
goto clean;
+ if (td)
+ td->firstp = false;
goto again;
case 'v':
/* void */
- if (!DEM_PUSH_STR(ddata, "void"))
+ omit_void = false;
+ if (td && td->firstp) {
+ /*
+ * peek into next bytes and see if we should omit
+ * the "void".
+ */
+ omit_void = true;
+ for (p = ddata->cur + 1; *p != '\0'; p++) {
+ if (*p == 'E')
+ break;
+ if (*p != 'R' && *p != 'O') {
+ omit_void = false;
+ break;
+ }
+ }
+ }
+ if (!omit_void && !DEM_PUSH_STR(ddata, "void"))
goto clean;
++ddata->cur;
goto rtn;
@@ -2539,6 +2949,8 @@ again:
if (!vector_type_qualifier_push(&v, TYPE_VAT))
goto clean;
++ddata->cur;
+ if (td)
+ td->firstp = false;
goto again;
case 'w':
@@ -2575,9 +2987,9 @@ again:
is_builtin = 0;
rtn:
- if ((type_str = vector_str_substr(output, p_idx, output->size - 1,
- &type_str_len)) == NULL)
- goto clean;
+
+ type_str = vector_str_substr(output, p_idx, output->size - 1,
+ &type_str_len);
if (is_builtin == 0) {
if (!vector_str_find(&ddata->subst, type_str, type_str_len) &&
@@ -2585,40 +2997,18 @@ rtn:
goto clean;
}
- if (!cpp_demangle_push_type_qualifier(ddata, &v, type_str))
+ if (!skip_ref_qualifier &&
+ !cpp_demangle_push_type_qualifier(ddata, &v, type_str))
goto clean;
+ if (td)
+ td->firstp = false;
+
free(type_str);
free(exp_str);
free(num_str);
vector_type_qualifier_dest(&v);
- if (ddata->push_head > 0) {
- if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata)
- == 0)
- return (0);
-
- if (--ddata->push_head > 0)
- return (1);
-
- if (!VEC_PUSH_STR(&ddata->output_tmp, " "))
- return (0);
-
- if (!vector_str_push_vector_head(&ddata->output,
- &ddata->output_tmp))
- return (0);
-
- vector_str_dest(&ddata->output_tmp);
- if (!vector_str_init(&ddata->output_tmp))
- return (0);
-
- if (!DEM_PUSH_STR(ddata, "("))
- return (0);
-
- ddata->paren = true;
- ddata->pfirst = true;
- }
-
return (1);
clean:
free(type_str);
@@ -2636,12 +3026,11 @@ cpp_demangle_read_type_flat(struct cpp_demangle_data *ddata, char **str)
size_t i, p_idx, idx, type_len;
char *type;
- output = ddata->push_head > 0 ? &ddata->output_tmp :
- &ddata->output;
+ output = ddata->cur_output;
p_idx = output->size;
- if (!cpp_demangle_read_type(ddata, 0))
+ if (!cpp_demangle_read_type(ddata, NULL))
return (0);
if ((type = vector_str_substr(output, p_idx, output->size - 1,
@@ -2736,7 +3125,7 @@ cpp_demangle_read_uqname(struct cpp_demangle_data *ddata)
if (!DEM_PUSH_STR(ddata, "operator(cast)"))
return (0);
ddata->cur += 2;
- return (cpp_demangle_read_type(ddata, 1));
+ return (cpp_demangle_read_type(ddata, NULL));
case SIMPLE_HASH('d', 'a'):
/* operator delete [] */
@@ -3046,9 +3435,7 @@ cpp_demangle_read_uqname(struct cpp_demangle_data *ddata)
/* ctor-dtor-name */
switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
case SIMPLE_HASH('C', '1'):
- /* FALLTHROUGH */
case SIMPLE_HASH('C', '2'):
- /* FALLTHROUGH */
case SIMPLE_HASH('C', '3'):
if (ddata->last_sname == NULL)
return (0);
@@ -3062,9 +3449,7 @@ cpp_demangle_read_uqname(struct cpp_demangle_data *ddata)
return (1);
case SIMPLE_HASH('D', '0'):
- /* FALLTHROUGH */
case SIMPLE_HASH('D', '1'):
- /* FALLTHROUGH */
case SIMPLE_HASH('D', '2'):
if (ddata->last_sname == NULL)
return (0);
@@ -3468,20 +3853,19 @@ vector_read_cmd_dest(struct vector_read_cmd *v)
free(v->r_container);
}
-/* return -1 at failed, 0 at not found, 1 at found. */
-static int
+static struct read_cmd_item *
vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
{
- size_t i;
+ int i;
if (v == NULL || dst == READ_FAIL)
- return (-1);
+ return (NULL);
- for (i = 0; i < v->size; ++i)
- if (v->r_container[i] == dst)
- return (1);
+ for (i = (int) v->size - 1; i >= 0; i--)
+ if (v->r_container[i].cmd == dst)
+ return (&v->r_container[i]);
- return (0);
+ return (NULL);
}
static int
@@ -3494,7 +3878,7 @@ vector_read_cmd_init(struct vector_read_cmd *v)
v->size = 0;
v->capacity = VECTOR_DEF_CAPACITY;
- if ((v->r_container = malloc(sizeof(enum read_cmd) * v->capacity))
+ if ((v->r_container = malloc(sizeof(*v->r_container) * v->capacity))
== NULL)
return (0);
@@ -3509,15 +3893,16 @@ vector_read_cmd_pop(struct vector_read_cmd *v)
return (0);
--v->size;
- v->r_container[v->size] = READ_FAIL;
+ v->r_container[v->size].cmd = READ_FAIL;
+ v->r_container[v->size].data = NULL;
return (1);
}
static int
-vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
+vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd, void *data)
{
- enum read_cmd *tmp_r_ctn;
+ struct read_cmd_item *tmp_r_ctn;
size_t tmp_cap;
size_t i;
@@ -3526,8 +3911,7 @@ vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
if (v->size == v->capacity) {
tmp_cap = v->capacity * BUFFER_GROWFACTOR;
- if ((tmp_r_ctn = malloc(sizeof(enum read_cmd) * tmp_cap))
- == NULL)
+ if ((tmp_r_ctn = malloc(sizeof(*tmp_r_ctn) * tmp_cap)) == NULL)
return (0);
for (i = 0; i < v->size; ++i)
tmp_r_ctn[i] = v->r_container[i];
@@ -3536,7 +3920,8 @@ vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
v->capacity = tmp_cap;
}
- v->r_container[v->size] = cmd;
+ v->r_container[v->size].cmd = cmd;
+ v->r_container[v->size].data = data;
++v->size;
return (1);
diff --git a/libelftc/libelftc_vstr.c b/libelftc/libelftc_vstr.c
index 4b0977efa0f5..934b5dba4c96 100644
--- a/libelftc/libelftc_vstr.c
+++ b/libelftc/libelftc_vstr.c
@@ -33,7 +33,7 @@
#include "_libelftc.h"
-ELFTC_VCSID("$Id: libelftc_vstr.c 2065 2011-10-26 15:24:47Z jkoshy $");
+ELFTC_VCSID("$Id: libelftc_vstr.c 3531 2017-06-05 05:08:43Z kaiwang27 $");
/**
* @file vector_str.c
@@ -281,6 +281,47 @@ vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org)
}
/**
+ * @brief Push org vector to the tail of det vector.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_push_vector(struct vector_str *dst, struct vector_str *org)
+{
+ size_t i, j, tmp_cap;
+ char **tmp_ctn;
+
+ if (dst == NULL || org == NULL)
+ return (false);
+
+ tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR;
+
+ if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
+ return (false);
+
+ for (i = 0; i < dst->size; ++i)
+ tmp_ctn[i] = dst->container[i];
+
+ for (i = 0; i < org->size; ++i)
+ if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) ==
+ NULL) {
+ for (j = 0; j < i + dst->size; ++j)
+ free(tmp_ctn[j]);
+
+ free(tmp_ctn);
+
+ return (false);
+ }
+
+ free(dst->container);
+
+ dst->container = tmp_ctn;
+ dst->capacity = tmp_cap;
+ dst->size += org->size;
+
+ return (true);
+}
+
+/**
* @brief Get new allocated flat string from vector between begin and end.
*
* If r_len is not NULL, string length will be returned.
diff --git a/test/cxxfilt/tet_scen b/test/cxxfilt/tet_scen
index ec503cd8389d..9ec6da840fa6 100644
--- a/test/cxxfilt/tet_scen
+++ b/test/cxxfilt/tet_scen
@@ -2,16 +2,40 @@
all
"Starting Test Suite"
+ ^builtin
^misc
+ ^qualifiers
^regression
+ ^substitute
+ ^template
"Complete Test Suite"
+builtin
+ "Starting builtin Test"
+ /ts/builtin/tc
+ "Complete builtin Test"
+
misc
"Starting misc Test"
/ts/misc/tc
"Complete misc Test"
+qualifiers
+ "Starting qualifiers Test"
+ /ts/qualifiers/tc
+ "Complete qualifiers Test"
+
regression
"Starting regression Test"
/ts/regression/tc
"Complete regression Test"
+
+substitute
+ "Starting substitute Test"
+ /ts/substitute/tc
+ "Complete substitute Test"
+
+template
+ "Starting template Test"
+ /ts/template/tc
+ "Complete template Test"
diff --git a/test/cxxfilt/ts/Makefile b/test/cxxfilt/ts/Makefile
index 9e2f728033c4..45e4e5560918 100644
--- a/test/cxxfilt/ts/Makefile
+++ b/test/cxxfilt/ts/Makefile
@@ -2,7 +2,11 @@
TOP= ../../..
+SUBDIR+= builtin
SUBDIR+= misc
+SUBDIR+= qualifiers
SUBDIR+= regression
+SUBDIR+= substitute
+SUBDIR+= template
.include "${TOP}/mk/elftoolchain.subdir.mk"
diff --git a/test/cxxfilt/ts/builtin/Makefile b/test/cxxfilt/ts/builtin/Makefile
new file mode 100644
index 000000000000..ecc228b09b30
--- /dev/null
+++ b/test/cxxfilt/ts/builtin/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+TOP= ../../../..
+
+.include "../common/ts.mk"
diff --git a/test/cxxfilt/ts/builtin/tclist b/test/cxxfilt/ts/builtin/tclist
new file mode 100644
index 000000000000..3c8ae278332e
--- /dev/null
+++ b/test/cxxfilt/ts/builtin/tclist
@@ -0,0 +1,48 @@
+# <builtin-type> ::= v # void
+# ::= w # wchar_t
+# ::= b # bool
+# ::= c # char
+# ::= a # signed char
+# ::= h # unsigned char
+# ::= s # short
+# ::= t # unsigned short
+# ::= i # int
+# ::= j # unsigned int
+# ::= l # long
+# ::= m # unsigned long
+# ::= x # long long, __int64
+# ::= y # unsigned long long, __int64
+# ::= n # __int128
+# ::= o # unsigned __int128
+# ::= f # float
+# ::= d # double
+# ::= e # long double, __float80
+# ::= g # __float128
+# ::= z # ellipsis
+# ::= Dd # IEEE 754r decimal floating point (64 bits)
+# ::= De # IEEE 754r decimal floating point (128 bits)
+# ::= Df # IEEE 754r decimal floating point (32 bits)
+# ::= Dh # IEEE 754r half-precision floating point (16 bits)
+# ::= Di # char32_t
+# ::= Ds # char16_t
+# ::= Da # auto
+# ::= Dc # decltype(auto)
+# ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+# ::= u <source-name> # vendor extended type
+
+"_Z3barv", "bar()"
+"_Z3barPv", "bar(void*)"
+"_Z3bariPv", "bar(int, void*)"
+"_Z3fooww", "foo(wchar_t, wchar_t)"
+"_Z3foob", "foo(bool)"
+"_Z3foocah", "foo(char, signed char, unsigned char)"
+"_Z3barstij", "bar(short, unsigned short, int, unsigned int)"
+"_Z3barlmxy", "bar(long, unsigned long, long long, unsigned long long)"
+"_Z3barno", "bar(__int128, unsigned __int128)"
+"_Z3foofdeg", "foo(float, double, long double, __float128)"
+"_Z3fooiPcz", "foo(int, char*, ...)"
+"_Z3fooDdDeDfDh", "foo(decimal64, decimal128, decimal32, half)"
+"_Z3barDiDs", "bar(char32_t, char16_t)"
+"_Z3barIiEDai", "auto bar<int>(int)"
+"_Z3barIiEDci", "decltype(auto) bar<int>(int)"
+"_Z3barIiEDni", "decltype(nullptr) bar<int>(int)"
diff --git a/test/cxxfilt/ts/misc/tclist b/test/cxxfilt/ts/misc/tclist
index afc1cf62fcbb..ebe3e65c1d1b 100644
--- a/test/cxxfilt/ts/misc/tclist
+++ b/test/cxxfilt/ts/misc/tclist
@@ -1,11 +1,11 @@
# simple function
-
"_Z1f", "f"
"_Z1fi", "f(int)"
"_Z1fic", "f(int, char)"
+"_Z1f3bar", "f(bar)"
+"_Z1fFviE", "f(void (int))"
# namespace
-
"_ZN12elftoolchainE", "elftoolchain"
"_ZN11elftoolchainE", "_ZN11elftoolchainE"
"_ZN12elftoolchain", "_ZN12elftoolchain"
@@ -13,3 +13,39 @@
"_ZN12elftoolchain3foo3barEi", "elftoolchain::foo::bar(int)"
"_ZN12elftoolchain3foo3barEic", "elftoolchain::foo::bar(int, char)"
+# non-static member function with qualifiers <nested-name>
+# N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+"_ZNKR12elftoolchain3fooEi", "elftoolchain::foo(int) const &"
+"_ZNKO12elftoolchain3fooEi", "elftoolchain::foo(int) const &&"
+
+# function type with qualifiers. (note that the place to encode qualifiers
+# is different than <nested-name>)
+# <function-type> ::= [<CV-qualifiers>] [Dx] F [Y] <bare-function-type>
+ [<ref-qualifier>] E
+"_Z3fooKFviRE", "foo(void (int) const &)"
+"_Z3fooKFviOE", "foo(void (int) const &&)"
+
+# Pointer-to-member type and type qualifiers
+# <pointer-to-member-type> ::= M <class type> <member type>
+"_Z3barM12elftoolchainFviE", "bar(void (elftoolchain::*)(int))"
+"_Z3barM12elftoolchainKFviRE", "bar(void (elftoolchain::*)(int) const &)"
+"_Z3fooFvvEM1AFvvE", "foo(void (), void (A::*)())"
+"_Z3fooPFvvEM1AFvvE", "foo(void (*)(), void (A::*)())"
+"_Z3fooPFvvREM1AFvvE", "foo(void (*)() &, void (A::*)())"
+"_Z3fooPFvvREM1AFvvOE", "foo(void (*)() &, void (A::*)() &&)"
+"_Z3fooKFvvREM1AFvvE", "foo(void () const &, void (A::*)())"
+"_Z3fooKPFvvREM1AFvvE", "foo(void (* const)() &, void (A::*)())"
+"_Z3fooPKFvvREM1AFvvE", "foo(void (*)() const &, void (A::*)())"
+"_Z3fooPKFvvREPM1AFvvE", "foo(void (*)() const &, void (A::**)())"
+"_Z3fooPKFviREPM1AFvidE", "foo(void (*)(int) const &, void (A::**)(int, double))"
+"_Z3fooPrKFvvREPKVM1APKFvvE", "foo(void (*)() const restrict &, void (* A::* volatile const*)() const)"
+
+# local names
+
+
+
+# abbreviation St
+"_ZSt3foo", '::std::foo'
+"_ZNSt3for3barE", 'std::for::bar'
+
+# c++11 decltype
diff --git a/test/cxxfilt/ts/qualifiers/Makefile b/test/cxxfilt/ts/qualifiers/Makefile
new file mode 100644
index 000000000000..ecc228b09b30
--- /dev/null
+++ b/test/cxxfilt/ts/qualifiers/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+TOP= ../../../..
+
+.include "../common/ts.mk"
diff --git a/test/cxxfilt/ts/qualifiers/tclist b/test/cxxfilt/ts/qualifiers/tclist
new file mode 100644
index 000000000000..98e725c7a6a2
--- /dev/null
+++ b/test/cxxfilt/ts/qualifiers/tclist
@@ -0,0 +1,36 @@
+# <type> ::= <CV-qualifiers> <type>
+# ::= P <type> # pointer-to
+# ::= R <type> # reference-to
+# ::= O <type> # rvalue reference-to (C++0x)
+# ::= C <type> # complex pair (C 2000)
+# ::= G <type> # imaginary (C 2000)
+# ::= U <source-name> [<template-args>] <type> # vendor extended type qualifier
+
+# <CV-qualifiers> ::= [r] [V] [K]
+"_Z3foorPirPirPi", "foo(int* restrict, int* restrict, int* restrict)"
+"_Z3fooVPd", "foo(double* volatile)"
+
+# Pointer
+"_Z3fooPi", "foo(int*)"
+"_Z3fooPPi", "foo(int**)"
+"_Z3fooKPi", "foo(int* const)"
+"_Z3fooPKi", "foo(int const*)"
+"_Z3fooKPKi", "foo(int const* const)"
+"_Z3fooKPPi", "foo(int** const)"
+"_Z3fooPKPi", "foo(int* const*)"
+"_Z3fooPPKi", "foo(int const**)"
+"_Z3fooKPKPi", "foo(int* const* const)"
+
+# Reference
+"_Z3barRi", "bar(int&)"
+"_Z3barRKi", "bar(int const&)"
+"_ZplR1XS0_", "operator+(X&, X&)"
+"_ZrsRK1XS1_", "operator>>(X const&, X const&)"
+"_ZN1XaSEO1X", "X::operator=(X&&)"
+
+# Complex
+"_Z3fooCd", "foo(double complex)"
+"_Z3fooGdGf", "foo(double imaginary, float imaginary)"
+
+# Vendor
+"_Z3fooPU3farc", "foo(char far*)"
diff --git a/test/cxxfilt/ts/substitute/Makefile b/test/cxxfilt/ts/substitute/Makefile
new file mode 100644
index 000000000000..ecc228b09b30
--- /dev/null
+++ b/test/cxxfilt/ts/substitute/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+TOP= ../../../..
+
+.include "../common/ts.mk"
diff --git a/test/cxxfilt/ts/substitute/tclist b/test/cxxfilt/ts/substitute/tclist
new file mode 100644
index 000000000000..41173dc6fa82
--- /dev/null
+++ b/test/cxxfilt/ts/substitute/tclist
@@ -0,0 +1,56 @@
+# <substitution> ::= S <seq-id> _
+# ::= S_
+
+"_ZN1N1TIiiE2mfES_IddE", "N::T<int, int>::mf(N<double, double>)"
+"_ZN1N1TIiiE2mfES0_IddE", "N::T<int, int>::mf(N::T<double, double>)"
+"_ZN1N1TIiiE2mfES1_IddE", "N::T<int, int>::mf(N::T<int, int><double, double>)"
+"_ZN1N1TIiiE2mfES2_IddE", "_ZN1N1TIiiE2mfES2_IddE"
+# wrong result:
+# "_ZN1N1TIiiE2mfES2_IddE", "N::T<int, int>::mf(N::T<int, int>::mf<double, double>)"
+
+"_ZN1f1gEP1hNS_1iE", "f::g(h*, f::i)"
+"_ZN1f1gEP1hNS0_1iE", "f::g(h*, h::i)"
+# wrong result:
+# "_ZN1f1gEP1hNS0_1iE", "f::g(h*, f::g::i)"
+"_ZN1f1gEP1hNS1_1iE", "f::g(h*, h*::i)"
+
+"_Z3fooN1A1B1TES_", "foo(A::B::T, A)"
+"_Z3fooN1A1B1TES0_", "foo(A::B::T, A::B)"
+"_Z3fooN1A1B1TES1_", "foo(A::B::T, A::B::T)"
+
+"_Z3foo5Hello5WorldS_S0_", "foo(Hello, World, Hello, World)"
+
+# qualifiers with builtin type should be substitute candidates
+"_Z3fooPiS_", "foo(int*, int*)"
+"_Z3fooKPiS_", "foo(int* const, int*)"
+"_Z3fooKPiS0_", "foo(int* const, int* const)"
+"_Z3fooRKiS_", "foo(int const&, int const)"
+"_Z3fooRKiS0_", "foo(int const&, int const&)"
+"_Z3foorKiS_", "foo(int const restrict, int const restrict)"
+"_Z3fooPrKiS_", "foo(int const restrict*, int const restrict)"
+"_Z3fooPrKiS0_", "foo(int const restrict*, int const restrict*)"
+"_Z3foorPKiS_", "foo(int const* restrict, int const)"
+"_Z3foorPKiS0_", "foo(int const* restrict, int const*)"
+"_Z3foorPKiS1_", "foo(int const* restrict, int const* restrict)"
+"_Z3foorKPiS_", "foo(int* const restrict, int*)"
+"_Z3foorKPiS0_", "foo(int* const restrict, int* const restrict)"
+
+# qualifers with non-builin type
+"_Z3fooP3BarS_", "foo(Bar*, Bar)"
+"_Z3fooP3BarS0_", "foo(Bar*, Bar*)"
+"_Z3fooPK3BarS_", "foo(Bar const*, Bar)"
+"_Z3fooPK3BarS1_", "foo(Bar const*, Bar const*)"
+"_Z3foorKP3BarS0_", "foo(Bar* const restrict, Bar*)"
+"_Z3foorKP3BarS1_", "foo(Bar* const restrict, Bar* const restrict)"
+
+# vendor extended qualifiers and substitution
+# note that ABI requires that "the type with all the K, V, and r qualifiers
+# " plus any vendor extended types in the same order-insensitive set is
+# substitutible". Here vendor extended type is not handled as above
+# requirement.
+"_Z3fooU3barKiS_", "foo(int const bar, int const)"
+"_Z3fooU3barKiS0_", "foo(int const bar, int const bar)"
+
+# bug introduced with a botched fix for omitting "void"
+"_Z3barvPvS_", "bar(void, void*, void*)"
+# wrong result: bar(void, void*, void, void*)
diff --git a/test/cxxfilt/ts/template/Makefile b/test/cxxfilt/ts/template/Makefile
new file mode 100644
index 000000000000..ecc228b09b30
--- /dev/null
+++ b/test/cxxfilt/ts/template/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+TOP= ../../../..
+
+.include "../common/ts.mk"
diff --git a/test/cxxfilt/ts/template/tclist b/test/cxxfilt/ts/template/tclist
new file mode 100644
index 000000000000..bb1a6234b605
--- /dev/null
+++ b/test/cxxfilt/ts/template/tclist
@@ -0,0 +1,10 @@
+# Misc
+"_Z1TIiE", "T<int>"
+"_Z1TIidE", "T<int, double>"
+"_Z1TIidET_T0_", "int T<int, double>(double)"
+"_ZN3Foo3BarIiiE1fEii", "Foo::Bar<int, int>::f(int, int)"
+"_ZN3Foo3BarIiiE1fIiiEEii", "int Foo::Bar<int, int>::f<int, int>(int)"
+"_ZN3Foo3BarIiiE1fE1TIiE", "Foo::Bar<int, int>::f(T<int>)"
+"_ZN3Foo3BarIiiE1fE1TIiEi", "Foo::Bar<int, int>::f(T<int>, int)"
+"_ZN3Foo3BarIiiE1fE1TIiEii", "Foo::Bar<int, int>::f(T<int>, int, int)"
+"_Z3foo1TIiEdh", "foo(T<int>, double, unsigned char)"
diff --git a/test/elfcopy/plugin/os.FreeBSD.mk b/test/elfcopy/plugin/os.FreeBSD.mk
new file mode 100644
index 000000000000..c29af70518a9
--- /dev/null
+++ b/test/elfcopy/plugin/os.FreeBSD.mk
@@ -0,0 +1,2 @@
+DPADD+= ${LIBBZ2}
+LDADD+= -lbz2