@@ -1,5 +1,10 @@
-*- text -*-
+* The addr2line, c++filt, nm and objdump tools now have a limit on the maximum amount of recursion
+ that is allowed whilst demangling strings. The default value for this
+ limit is 1024. The --recurse-limit=N option can be used to change the
+ limit, or remove it entirely if N is zero.
+
* Objdump's --disassemble option can now take a parameter, specifying the
starting symbol for disassembly. Disassembly will continue from this
symbol up to the next symbol.
@@ -45,6 +45,9 @@ static bfd_boolean do_demangle; /* -C, demangle names. */
static bfd_boolean pretty_print; /* -p, print on one line. */
static bfd_boolean base_names; /* -s, strip directory names. */
+/* Flags passed to the name demangler. */
+static int demangle_flags = DMGL_PARAMS | DMGL_ANSI | DMGL_RECURSE_LIMIT;
+
static int naddr; /* Number of addresses to process. */
static char **addr; /* Hex addresses to process. */
@@ -59,6 +62,8 @@ static struct option long_options[] =
{"functions", no_argument, NULL, 'f'},
{"inlines", no_argument, NULL, 'i'},
{"pretty-print", no_argument, NULL, 'p'},
+ {"recurse-limit", required_argument, NULL, 'r'},
+ {"recursion-limit", required_argument, NULL, 'r'},
{"section", required_argument, NULL, 'j'},
{"target", required_argument, NULL, 'b'},
{"help", no_argument, NULL, 'H'},
@@ -91,6 +96,7 @@ usage (FILE *stream, int status)
-s --basenames Strip directory names\n\
-f --functions Show function names\n\
-C --demangle[=style] Demangle function names\n\
+ -r --recurse-limit=<N> Set the recursion limit for name demangling\n\
-h --help Display this information\n\
-v --version Display the program's version\n\
\n"));
@@ -289,7 +295,7 @@ translate_addresses (bfd *abfd, asection *section)
name = "??";
else if (do_demangle)
{
- alloc = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (abfd, name, demangle_flags);
if (alloc != NULL)
name = alloc;
}
@@ -442,7 +448,7 @@ main (int argc, char **argv)
file_name = NULL;
section_name = NULL;
target = NULL;
- while ((c = getopt_long (argc, argv, "ab:Ce:sfHhij:pVv", long_options, (int *) 0))
+ while ((c = getopt_long (argc, argv, "ab:Ce:r:sfHhij:pVv", long_options, (int *) 0))
!= EOF)
{
switch (c)
@@ -469,6 +475,18 @@ main (int argc, char **argv)
cplus_demangle_set_style (style);
}
break;
+ case 'r':
+ {
+ unsigned long limit = strtoul (optarg, NULL, 0);
+ if (limit > 1)
+ {
+ cplus_demangle_set_recursion_limit (limit);
+ demangle_flags |= DMGL_RECURSE_LIMIT;
+ }
+ else
+ demangle_flags &= ~ DMGL_RECURSE_LIMIT;
+ }
+ break;
case 'e':
file_name = optarg;
break;
@@ -29,7 +29,7 @@
#include "safe-ctype.h"
#include "bucomm.h"
-static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
+static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE | DMGL_RECURSE_LIMIT;
static int strip_underscore = TARGET_PREPENDS_UNDERSCORE;
static const struct option long_options[] =
@@ -42,6 +42,8 @@ static const struct option long_options[] =
{"no-verbose", no_argument, NULL, 'i'},
{"types", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
+ {"recurse-limit", required_argument, NULL, 'r'},
+ {"recursion-limit", required_argument, NULL, 'r'},
{NULL, no_argument, NULL, 0}
};
@@ -102,6 +104,7 @@ Options are:\n\
fprintf (stream, "\
[-p|--no-params] Do not display function arguments\n\
[-i|--no-verbose] Do not show implementation details (if any)\n\
+ [-r|--recurse-limit <N>] Set recursion limit to <N>. [Default 1024]\n\
[-t|--types] Also attempt to demangle type encodings\n\
[-s|--format ");
print_demangler_list (stream);
@@ -180,7 +183,7 @@ main (int argc, char **argv)
expandargv (&argc, &argv);
- while ((c = getopt_long (argc, argv, "_hinps:tv", long_options, (int *) 0)) != EOF)
+ while ((c = getopt_long (argc, argv, "_hinpr:s:tv", long_options, (int *) 0)) != EOF)
{
switch (c)
{
@@ -195,6 +198,18 @@ main (int argc, char **argv)
case 'p':
flags &= ~ DMGL_PARAMS;
break;
+ case 'r':
+ {
+ unsigned long limit = strtoul (optarg, NULL, 0);
+ if (limit > 1)
+ {
+ cplus_demangle_set_recursion_limit (limit);
+ flags |= DMGL_RECURSE_LIMIT;
+ }
+ else
+ flags &= ~ DMGL_RECURSE_LIMIT;
+ }
+ break;
case 't':
flags |= DMGL_TYPES;
break;
@@ -1802,7 +1802,7 @@ gen_def_file (void)
for (i = 0, exp = d_exports; exp; i++, exp = exp->next)
{
char *quote = strchr (exp->name, '.') ? "\"" : "";
- char *res = cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_PARAMS);
+ char *res = cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT);
if (res)
{
@@ -769,7 +769,8 @@ nm [@option{-A}|@option{-o}|@option{--print-file-name}] [@option{-a}|@option{--d
[@option{-s}|@option{--print-armap}] [@option{-t} @var{radix}|@option{--radix=}@var{radix}]
[@option{-u}|@option{--undefined-only}] [@option{-V}|@option{--version}]
[@option{-X 32_64}] [@option{--defined-only}] [@option{--no-demangle}]
- [@option{--plugin} @var{name}] [@option{--size-sort}] [@option{--special-syms}]
+ [@option{--plugin} @var{name}] [@option{--recurse-limit=}@var{N}]
+ [@option{--size-sort}] [@option{--special-syms}]
[@option{--synthetic}] [@option{--with-symbol-versions}] [@option{--target=}@var{bfdname}]
[@var{objfile}@dots{}]
@c man end
@@ -939,6 +940,17 @@ for more information on demangling.
@item --no-demangle
Do not demangle low-level symbol names. This is the default.
+@item --recurse-limit=@var{N}
+@itemx --recursion-limit @var{N}
+Sets a limit on the amount of recursion performed whilst demangling
+strings. Since the name mangling formats allow for an inifinite
+level of recursion it is possible to create strings whose decoding
+will exhaust the amount of stack space available on the host machine,
+triggering a memory fault. The limit tries to prevent this from
+happening by restricting recursion to a maximum amount. The default
+value for this limit is 1024. To disable the limit set its value to
+0.
+
@item -D
@itemx --dynamic
@cindex dynamic symbols
@@ -2098,6 +2110,7 @@ objdump [@option{-a}|@option{--archive-headers}]
[@option{--adjust-vma=}@var{offset}]
[@option{--dwarf-depth=@var{n}}]
[@option{--dwarf-start=@var{n}}]
+ [@option{--recurse-limit=@var{n}}]
[@option{--special-syms}]
[@option{--prefix=}@var{prefix}]
[@option{--prefix-strip=}@var{level}]
@@ -2174,6 +2187,17 @@ mangling styles. The optional demangling style argument can be used to
choose an appropriate demangling style for your compiler. @xref{c++filt},
for more information on demangling.
+@item --recurse-limit=@var{N}
+@itemx --recursion-limit @var{N}
+Sets a limit on the amount of recursion performed whilst demangling
+strings. Since the name mangling formats allow for an inifinite
+level of recursion it is possible to create strings whose decoding
+will exhaust the amount of stack space available on the host machine,
+triggering a memory fault. The limit tries to prevent this from
+happening by restricting recursion to a maximum amount. The default
+value for this limit is 1024. To disable the limit set its value to
+0.
+
@item -g
@itemx --debugging
Display debugging information. This attempts to parse STABS
@@ -3403,6 +3427,7 @@ c++filt [@option{-_}|@option{--strip-underscore}]
[@option{-p}|@option{--no-params}]
[@option{-t}|@option{--types}]
[@option{-i}|@option{--no-verbose}]
+ [@option{-r} @var{N}|@option{--recurse-limit=}@var{N}]
[@option{-s} @var{format}|@option{--format=}@var{format}]
[@option{--help}] [@option{--version}] [@var{symbol}@dots{}]
@c man end
@@ -3507,6 +3532,18 @@ demangled to ``signed char''.
Do not include implementation details (if any) in the demangled
output.
+@item -r @var{N}
+@itemx --recurse-limit=@var{N}
+@itemx --recursion-limit @var{N}
+Sets a limit on the amount of recursion performed whilst demangling
+strings. Since the name mangling formats allow for an inifinite
+level of recursion it is possible to create strings whose decoding
+will exhaust the amount of stack space available on the host machine,
+triggering a memory fault. The limit tries to prevent this from
+happening by restricting recursion to a maximum amount. The default
+value for this limit is 1024. To disable the limit set its value to
+0.
+
@item -s @var{format}
@itemx --format=@var{format}
@command{c++filt} can decode various methods of mangling, used by
@@ -3580,6 +3617,7 @@ c++filt @var{option} @var{symbol}
addr2line [@option{-a}|@option{--addresses}]
[@option{-b} @var{bfdname}|@option{--target=}@var{bfdname}]
[@option{-C}|@option{--demangle}[=@var{style}]]
+ [@option{-r} @var{N}|@option{--recurse-limit=}@var{N}]
[@option{-e} @var{filename}|@option{--exe=}@var{filename}]
[@option{-f}|@option{--functions}] [@option{-s}|@option{--basename}]
[@option{-i}|@option{--inlines}]
@@ -3705,6 +3743,22 @@ Read offsets relative to the specified section instead of absolute addresses.
Make the output more human friendly: each location are printed on one line.
If option @option{-i} is specified, lines for all enclosing scopes are
prefixed with @samp{(inlined by)}.
+
+@item -r @var{N}
+@itemx --recurse-limit=@var{N}
+@itemx --recursion-limit @var{N}
+Sets a limit on the amount of recursion performed whilst demangling
+strings. Since the name mangling formats allow for an inifinite
+level of recursion it is possible to create strings whose decoding
+will exhaust the amount of stack space available on the host machine,
+triggering a memory fault. The limit tries to prevent this from
+happening by restricting recursion to a maximum amount. The default
+value for this limit is 1024. To disable the limit set its value to
+0.
+
+Note this option is only effective if the @option{-C} or
+@option{--demangle} option has been enabled.
+
@end table
@c man end
@@ -162,6 +162,8 @@ static int line_numbers = 0; /* Print line numbers for symbols. */
static int allow_special_symbols = 0; /* Allow special symbols. */
static int with_symbol_versions = 0; /* Include symbol version information in the output. */
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT;
+
/* When to print the names of files. Not mutually exclusive in SYSV format. */
static int filename_per_file = 0; /* Once per file, on its own line. */
static int filename_per_symbol = 0; /* Once per symbol, at start of line. */
@@ -194,9 +196,13 @@ static const char *plugin_target = NULL;
static bfd *lineno_cache_bfd;
static bfd *lineno_cache_rel_bfd;
-#define OPTION_TARGET 200
-#define OPTION_PLUGIN (OPTION_TARGET + 1)
-#define OPTION_SIZE_SORT (OPTION_PLUGIN + 1)
+enum long_option_values
+{
+ OPTION_TARGET = 200,
+ OPTION_PLUGIN,
+ OPTION_SIZE_SORT,
+ OPTION_RECURSE_LIMIT
+};
static struct option long_options[] =
{
@@ -217,6 +223,8 @@ static struct option long_options[] =
{"print-file-name", no_argument, 0, 'o'},
{"print-size", no_argument, 0, 'S'},
{"radix", required_argument, 0, 't'},
+ {"recurse-limit", required_argument, NULL, OPTION_RECURSE_LIMIT},
+ {"recursion-limit", required_argument, NULL, OPTION_RECURSE_LIMIT},
{"reverse-sort", no_argument, &reverse_sort, 1},
{"size-sort", no_argument, 0, OPTION_SIZE_SORT},
{"special-syms", no_argument, &allow_special_symbols, 1},
@@ -245,6 +253,7 @@ usage (FILE *stream, int status)
`gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
or `gnat'\n\
--no-demangle Do not demangle low-level symbol names\n\
+ --recurse-limit=N Set demangling recursion limit to N. [Default 1024]\n\
-D, --dynamic Display dynamic symbols instead of normal symbols\n\
--defined-only Display only defined symbols\n\
-e (ignored)\n\
@@ -407,7 +416,7 @@ print_symname (const char *form, const char *name, bfd *abfd)
{
if (do_demangle && *name)
{
- char *res = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ char *res = bfd_demangle (abfd, name, demangle_flags);
if (res != NULL)
{
@@ -1687,6 +1696,18 @@ main (int argc, char **argv)
cplus_demangle_set_style (style);
}
break;
+ case OPTION_RECURSE_LIMIT:
+ {
+ unsigned long limit = strtoul (optarg, NULL, 0);
+ if (limit > 1)
+ {
+ cplus_demangle_set_recursion_limit (limit);
+ demangle_flags |= DMGL_RECURSE_LIMIT;
+ }
+ else
+ demangle_flags &= ~ DMGL_RECURSE_LIMIT;
+ }
+ break;
case 'D':
dynamic = 1;
break;
@@ -120,6 +120,8 @@ static size_t prefix_length;
static bfd_boolean unwind_inlines; /* --inlines. */
static const char * disasm_sym; /* Disassembly start symbol. */
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT;
+
/* A structure to record the sections mentioned in -j switches. */
struct only
{
@@ -252,6 +254,7 @@ usage (FILE *stream, int status)
The STYLE, if specified, can be `auto', `gnu',\n\
`lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
or `gnat'\n\
+ --recurse-limit=N Set demangling recursion limit to N. [Default 1024]\n\
-w, --wide Format output for more than 80 columns\n\
-z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling\n\
--start-address=ADDR Only process data whose address is >= ADDR\n\
@@ -302,6 +305,7 @@ enum option_values
OPTION_DWARF_DEPTH,
OPTION_DWARF_CHECK,
OPTION_DWARF_START,
+ OPTION_RECURSE_LIMIT,
OPTION_INLINES
};
@@ -333,6 +337,8 @@ static struct option long_options[]=
{"line-numbers", no_argument, NULL, 'l'},
{"no-show-raw-insn", no_argument, &show_raw_insn, -1},
{"prefix-addresses", no_argument, &prefix_addresses, 1},
+ {"recurse-limit", required_argument, NULL, OPTION_RECURSE_LIMIT},
+ {"recursion-limit", required_argument, NULL, OPTION_RECURSE_LIMIT},
{"reloc", no_argument, NULL, 'r'},
{"section", required_argument, NULL, 'j'},
{"section-headers", no_argument, NULL, 'h'},
@@ -884,7 +890,7 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf,
if (do_demangle && name[0] != '\0')
{
/* Demangle the name. */
- alloc = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (abfd, name, demangle_flags);
if (alloc != NULL)
name = alloc;
}
@@ -2290,7 +2296,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
if (do_demangle && name[0] != '\0')
{
/* Demangle the name. */
- alloc = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (abfd, name, demangle_flags);
if (alloc != NULL)
name = alloc;
}
@@ -3268,7 +3274,7 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean dynamic)
/* If we want to demangle the name, we demangle it
here, and temporarily clobber it while calling
bfd_print_symbol. FIXME: This is a gross hack. */
- alloc = bfd_demangle (cur_bfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (cur_bfd, name, demangle_flags);
if (alloc != NULL)
(*current)->name = alloc;
bfd_print_symbol (cur_bfd, stdout, *current,
@@ -3927,6 +3933,18 @@ main (int argc, char **argv)
cplus_demangle_set_style (style);
}
break;
+ case OPTION_RECURSE_LIMIT:
+ {
+ unsigned long limit = strtoul (optarg, NULL, 0);
+ if (limit > 1)
+ {
+ cplus_demangle_set_recursion_limit (limit);
+ demangle_flags |= DMGL_RECURSE_LIMIT;
+ }
+ else
+ demangle_flags &= ~ DMGL_RECURSE_LIMIT;
+ }
+ break;
case 'w':
do_wide = wide_output = TRUE;
break;
@@ -286,6 +286,8 @@ static const struct debug_write_fns tg_fns =
pr_end_function, /* Same, does nothing. */
tg_lineno
};
+
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT;
/* Print out the generic debugging information recorded in dhandle. */
@@ -2600,7 +2602,7 @@ tg_variable (void *p, const char *name, enum debug_var_kind kind,
dname = NULL;
if (info->demangler)
- dname = info->demangler (info->abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ dname = info->demangler (info->abfd, name, demangle_flags);
from_class = NULL;
if (dname != NULL)
@@ -2661,7 +2663,7 @@ tg_start_function (void *p, const char *name, bfd_boolean global)
dname = NULL;
if (info->demangler)
- dname = info->demangler (info->abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ dname = info->demangler (info->abfd, name, demangle_flags);
if (! substitute_type (info, dname ? dname : name))
return FALSE;
@@ -215,6 +215,8 @@ static debug_type stab_demangle_v3_arg
(void *, struct stab_handle *, struct demangle_component *, debug_type,
bfd_boolean *);
+static int demangle_flags = DMGL_ANSI | DMGL_RECURSE_LIMIT;
+
/* Save a string in memory. */
static char *
@@ -4517,7 +4519,7 @@ stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
free (s1);
- s3 = cplus_demangle (s2, DMGL_ANSI);
+ s3 = cplus_demangle (s2, demangle_flags);
free (s2);
@@ -5243,7 +5245,7 @@ stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
void *mem;
debug_type *pargs;
- dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
+ dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | demangle_flags, &mem);
if (dc == NULL)
{
stab_bad_demangle (physname);
@@ -5418,7 +5420,7 @@ stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
/* We print this component to get a class name which we can
use. FIXME: This probably won't work if the template uses
template parameters which refer to an outer template. */
- p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
+ p = cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Failed to print demangled template\n"));
@@ -5498,7 +5500,7 @@ stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
/* We print this component in order to find out the type name.
FIXME: Should we instead expose the
demangle_builtin_type_info structure? */
- p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
+ p = cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Couldn't get demangled builtin type\n"));
@@ -93,6 +93,12 @@ if ![info exists WINDRES] then {
if ![info exists DLLTOOL] then {
set DLLTOOL [findfile $base_dir/dlltool]
}
+if ![info exists CXXFILT] then {
+ set CXXFILT [findfile $base_dir/cxxfilt]
+}
+if ![info exists CXXFILTFLAGS] then {
+ set CXXFILTFLAGS ""
+}
if ![file isdirectory tmpdir] {catch "exec mkdir tmpdir" status}
@@ -0,0 +1,44 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+proc test_cxxfilt {options mangled_string demangled_string} {
+ global CXXFILT
+ global CXXFILTFLAGS
+
+ set testname "cxxfilt: demangling $mangled_string"
+ set got [binutils_run $CXXFILT "$options $CXXFILTFLAGS $mangled_string"]
+
+ if ![regexp $demangled_string $got] then {
+ fail "$testname"
+ verbose 0 "expected: $demangled_string"
+ return
+ }
+
+ pass $testname
+}
+
+# Mangled and demangled strings stolen from libiberty/testsuite/demangle-expected.
+test_cxxfilt {} \
+ "AddAlignment__9ivTSolverUiP12ivInteractorP7ivTGlue" \
+ "ivTSolver::AddAlignment(unsigned int, ivInteractor ., ivTGlue .)*"
+
+test_cxxfilt {--format=lucid} \
+ "__ct__12strstreambufFPFl_PvPFPv_v" \
+ "strstreambuf..strstreambuf(void .(.)(long), void (.)(void .))*"
+
+test_cxxfilt {--recurse-limit=2} \
+ "Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_" \
+ "foo(int, int., int.., int..., int...., int....., int......, int......., int........, int........., int.........., int..........., int............, int............., int.............., int...............)*"