diff --git a/SOURCES/binutils-CVE-2018-12699-part1-PR22955.patch b/SOURCES/binutils-CVE-2018-12699-part1-PR22955.patch new file mode 100644 index 0000000..0263229 --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part1-PR22955.patch @@ -0,0 +1,1238 @@ +diff -rup binutils.orig/binutils/stabs.c binutils-2.30/binutils/stabs.c +--- binutils.orig/binutils/stabs.c 2024-10-29 14:00:27.334403933 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-10-29 14:02:25.532712776 +0000 +@@ -145,42 +145,51 @@ struct stab_tag + }; + + static char *savestring (const char *, int); +-static bfd_vma parse_number (const char **, bfd_boolean *); ++ + static void bad_stab (const char *); + static void warn_stab (const char *, const char *); + static bfd_boolean parse_stab_string +- (void *, struct stab_handle *, int, int, bfd_vma, const char *); ++ (void *, struct stab_handle *, int, int, bfd_vma, ++ const char *, const char *); + static debug_type parse_stab_type +- (void *, struct stab_handle *, const char *, const char **, debug_type **); +-static bfd_boolean parse_stab_type_number (const char **, int *); ++ (void *, struct stab_handle *, const char *, const char **, ++ debug_type **, const char *); ++static bfd_boolean parse_stab_type_number ++ (const char **, int *, const char *); + static debug_type parse_stab_range_type +- (void *, struct stab_handle *, const char *, const char **, const int *); +-static debug_type parse_stab_sun_builtin_type (void *, const char **); +-static debug_type parse_stab_sun_floating_type (void *, const char **); +-static debug_type parse_stab_enum_type (void *, const char **); ++ (void *, struct stab_handle *, const char *, const char **, ++ const int *, const char *); ++static debug_type parse_stab_sun_builtin_type ++ (void *, const char **, const char *); ++static debug_type parse_stab_sun_floating_type ++ (void *, const char **, const char *); ++static debug_type parse_stab_enum_type ++ (void *, const char **, const char *); + static debug_type parse_stab_struct_type + (void *, struct stab_handle *, const char *, const char **, +- bfd_boolean, const int *); ++ bfd_boolean, const int *, const char *); + static bfd_boolean parse_stab_baseclasses +- (void *, struct stab_handle *, const char **, debug_baseclass **); ++ (void *, struct stab_handle *, const char **, debug_baseclass **, ++ const char *); + static bfd_boolean parse_stab_struct_fields +- (void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *); ++ (void *, struct stab_handle *, const char **, debug_field **, ++ bfd_boolean *, const char *); + static bfd_boolean parse_stab_cpp_abbrev +- (void *, struct stab_handle *, const char **, debug_field *); ++ (void *, struct stab_handle *, const char **, debug_field *, const char *); + static bfd_boolean parse_stab_one_struct_field + (void *, struct stab_handle *, const char **, const char *, +- debug_field *, bfd_boolean *); ++ debug_field *, bfd_boolean *, const char *); + static bfd_boolean parse_stab_members + (void *, struct stab_handle *, const char *, const char **, const int *, +- debug_method **); ++ debug_method **, const char *); + static debug_type parse_stab_argtypes + (void *, struct stab_handle *, debug_type, const char *, const char *, + debug_type, const char *, bfd_boolean, bfd_boolean, const char **); + static bfd_boolean parse_stab_tilde_field + (void *, struct stab_handle *, const char **, const int *, debug_type *, +- bfd_boolean *); ++ bfd_boolean *, const char *); + static debug_type parse_stab_array_type +- (void *, struct stab_handle *, const char **, bfd_boolean); ++ (void *, struct stab_handle *, const char **, bfd_boolean, const char *); + static void push_bincl (struct stab_handle *, const char *, bfd_vma); + static const char *pop_bincl (struct stab_handle *); + static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma); +@@ -222,7 +231,7 @@ savestring (const char *start, int len) + /* Read a number from a string. */ + + static bfd_vma +-parse_number (const char **pp, bfd_boolean *poverflow) ++parse_number (const char **pp, bfd_boolean *poverflow, const char *p_end) + { + unsigned long ul; + const char *orig; +@@ -231,6 +240,8 @@ parse_number (const char **pp, bfd_boole + *poverflow = FALSE; + + orig = *pp; ++ if (orig >= p_end) ++ return (bfd_vma) 0; + + /* Stop early if we are passed an empty string. */ + if (*orig == 0) +@@ -409,6 +420,7 @@ bfd_boolean + parse_stab (void *dhandle, void *handle, int type, int desc, bfd_vma value, + const char *string) + { ++ const char * string_end; + struct stab_handle *info = (struct stab_handle *) handle; + + /* gcc will emit two N_SO strings per compilation unit, one for the +@@ -443,6 +455,8 @@ parse_stab (void *dhandle, void *handle, + /* Now process whatever type we just got. */ + } + ++ string_end = string + strlen (string); ++ + switch (type) + { + case N_FN: +@@ -652,7 +666,7 @@ parse_stab (void *dhandle, void *handle, + info->within_function = TRUE; + } + +- if (! parse_stab_string (dhandle, info, type, desc, value, string)) ++ if (! parse_stab_string (dhandle, info, type, desc, value, string, string_end)) + return FALSE; + } + break; +@@ -680,7 +694,8 @@ parse_stab (void *dhandle, void *handle, + + static bfd_boolean + parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype, +- int desc ATTRIBUTE_UNUSED, bfd_vma value, const char *string) ++ int desc ATTRIBUTE_UNUSED, bfd_vma value, ++ const char *string, const char * string_end) + { + const char *p; + char *name; +@@ -743,6 +758,11 @@ parse_stab_string (void *dhandle, struct + ++p; + if (ISDIGIT (*p) || *p == '(' || *p == '-') + type = 'l'; ++ else if (*p == 0) ++ { ++ bad_stab (string); ++ return FALSE; ++ } + else + type = *p++; + +@@ -787,7 +807,7 @@ parse_stab_string (void *dhandle, struct + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, +- &p, (debug_type **) NULL); ++ &p, (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (*p != ',') +@@ -812,7 +832,7 @@ parse_stab_string (void *dhandle, struct + case 'C': + /* The name of a caught exception. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, +- &p, (debug_type **) NULL); ++ &p, (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_label (dhandle, name, dtype, value)) +@@ -825,7 +845,7 @@ parse_stab_string (void *dhandle, struct + case 'F': + /* A function definition. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_function (dhandle, name, dtype, type == 'F', value)) +@@ -839,7 +859,7 @@ parse_stab_string (void *dhandle, struct + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL) ++ (debug_type **) NULL, string_end) + == DEBUG_TYPE_NULL) + return FALSE; + } +@@ -853,7 +873,7 @@ parse_stab_string (void *dhandle, struct + /* A global symbol. The value must be extracted from the + symbol table. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (name != NULL) +@@ -889,7 +909,7 @@ parse_stab_string (void *dhandle, struct + case 'l': + case 's': + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, +@@ -901,7 +921,7 @@ parse_stab_string (void *dhandle, struct + /* A function parameter. */ + if (*p != 'F') + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + else + { + /* pF is a two-letter code that means a function parameter in +@@ -909,7 +929,7 @@ parse_stab_string (void *dhandle, struct + value. Translate it into a pointer-to-function type. */ + ++p; + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype != DEBUG_TYPE_NULL) + { + debug_type ftype; +@@ -939,7 +959,7 @@ parse_stab_string (void *dhandle, struct + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL) ++ (debug_type **) NULL, string_end) + == DEBUG_TYPE_NULL) + return FALSE; + } +@@ -949,7 +969,7 @@ parse_stab_string (void *dhandle, struct + case 'R': + /* Parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG, +@@ -960,7 +980,7 @@ parse_stab_string (void *dhandle, struct + case 'r': + /* Register variable (either global or local). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER, +@@ -974,7 +994,7 @@ parse_stab_string (void *dhandle, struct + case 'S': + /* Static symbol at top level of file. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC, +@@ -984,7 +1004,7 @@ parse_stab_string (void *dhandle, struct + + case 't': + /* A typedef. */ +- dtype = parse_stab_type (dhandle, info, name, &p, &slot); ++ dtype = parse_stab_type (dhandle, info, name, &p, &slot, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (name == NULL) +@@ -1017,7 +1037,7 @@ parse_stab_string (void *dhandle, struct + ++p; + } + +- dtype = parse_stab_type (dhandle, info, name, &p, &slot); ++ dtype = parse_stab_type (dhandle, info, name, &p, &slot, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (name == NULL) +@@ -1068,7 +1088,7 @@ parse_stab_string (void *dhandle, struct + case 'V': + /* Static symbol of local scope */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + /* FIXME: gdb checks os9k_stabs here. */ +@@ -1080,7 +1100,7 @@ parse_stab_string (void *dhandle, struct + case 'v': + /* Reference parameter. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE, +@@ -1091,7 +1111,7 @@ parse_stab_string (void *dhandle, struct + case 'a': + /* Reference parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG, +@@ -1105,7 +1125,7 @@ parse_stab_string (void *dhandle, struct + that Pascal uses it too, but when I tried it Pascal used + "x:3" (local symbol) instead. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, +- (debug_type **) NULL); ++ (debug_type **) NULL, string_end); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, +@@ -1156,7 +1176,12 @@ parse_stab_string (void *dhandle, struct + store the slot used if the type is being defined. */ + + static debug_type +-parse_stab_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, debug_type **slotp) ++parse_stab_type (void * dhandle, ++ struct stab_handle * info, ++ const char * type_name, ++ const char ** pp, ++ debug_type ** slotp, ++ const char * p_end) + { + const char *orig; + int typenums[2]; +@@ -1169,6 +1194,8 @@ parse_stab_type (void *dhandle, struct s + *slotp = NULL; + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + size = -1; + stringp = FALSE; +@@ -1186,7 +1213,7 @@ parse_stab_type (void *dhandle, struct s + } + else + { +- if (! parse_stab_type_number (pp, typenums)) ++ if (! parse_stab_type_number (pp, typenums, p_end)) + return DEBUG_TYPE_NULL; + + if (**pp != '=') +@@ -1249,6 +1276,10 @@ parse_stab_type (void *dhandle, struct s + stringp = TRUE; + break; + ++ case 0: ++ bad_stab (orig); ++ return DEBUG_TYPE_NULL; ++ + default: + /* Ignore unrecognized type attributes, so future + compilers can invent new ones. */ +@@ -1279,6 +1310,10 @@ parse_stab_type (void *dhandle, struct s + case 'e': + code = DEBUG_KIND_ENUM; + break; ++ case 0: ++ bad_stab (orig); ++ return DEBUG_TYPE_NULL; ++ + default: + /* Complain and keep going, so compilers can invent new + cross-reference types. */ +@@ -1352,7 +1387,7 @@ parse_stab_type (void *dhandle, struct s + hold = *pp; + + /* Peek ahead at the number to detect void. */ +- if (! parse_stab_type_number (pp, xtypenums)) ++ if (! parse_stab_type_number (pp, xtypenums, p_end)) + return DEBUG_TYPE_NULL; + + if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) +@@ -1369,7 +1404,7 @@ parse_stab_type (void *dhandle, struct s + This means that we can deal with something like + t(1,2)=(3,4)=... which the Lucid compiler uses. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (dtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } +@@ -1388,7 +1423,8 @@ parse_stab_type (void *dhandle, struct s + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, +- (debug_type **) NULL)); ++ (debug_type **) NULL, ++ p_end)); + break; + + case '&': +@@ -1396,7 +1432,7 @@ parse_stab_type (void *dhandle, struct s + dtype = (debug_make_reference_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL))); ++ (debug_type **) NULL, p_end))); + break; + + case 'f': +@@ -1405,7 +1441,7 @@ parse_stab_type (void *dhandle, struct s + dtype = (debug_make_function_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL), ++ (debug_type **) NULL, p_end), + (debug_type *) NULL, FALSE)); + break; + +@@ -1416,7 +1452,8 @@ parse_stab_type (void *dhandle, struct s + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, +- (debug_type **) NULL)); ++ (debug_type **) NULL, ++ p_end)); + break; + + case 'B': +@@ -1425,7 +1462,7 @@ parse_stab_type (void *dhandle, struct s + dtype = (debug_make_volatile_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL))); ++ (debug_type **) NULL, p_end))); + break; + + case '@': +@@ -1438,7 +1475,7 @@ parse_stab_type (void *dhandle, struct s + /* Member type. */ + + domain = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + +@@ -1450,7 +1487,7 @@ parse_stab_type (void *dhandle, struct s + ++*pp; + + memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (memtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + +@@ -1466,7 +1503,7 @@ parse_stab_type (void *dhandle, struct s + + ++*pp; + return_type = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + if (**pp != ';') +@@ -1489,7 +1526,7 @@ parse_stab_type (void *dhandle, struct s + bfd_boolean varargs; + + domain = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + +@@ -1501,7 +1538,7 @@ parse_stab_type (void *dhandle, struct s + ++*pp; + + return_type = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + +@@ -1527,7 +1564,7 @@ parse_stab_type (void *dhandle, struct s + } + + args[n] = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (args[n] == DEBUG_TYPE_NULL) + /* There is a potential resource leak here, but it is not important. */ + /* coverity[leaked_storage: FALSE] */ +@@ -1557,30 +1594,30 @@ parse_stab_type (void *dhandle, struct s + + case 'r': + /* Range type. */ +- dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums); ++ dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums, p_end); + break; + + case 'b': + /* FIXME: gdb checks os9k_stabs here. */ + /* Sun ACC builtin int type. */ +- dtype = parse_stab_sun_builtin_type (dhandle, pp); ++ dtype = parse_stab_sun_builtin_type (dhandle, pp, p_end); + break; + + case 'R': + /* Sun ACC builtin float type. */ +- dtype = parse_stab_sun_floating_type (dhandle, pp); ++ dtype = parse_stab_sun_floating_type (dhandle, pp, p_end); + break; + + case 'e': + /* Enumeration type. */ +- dtype = parse_stab_enum_type (dhandle, pp); ++ dtype = parse_stab_enum_type (dhandle, pp, p_end); + break; + + case 's': + case 'u': + /* Struct or union type. */ + dtype = parse_stab_struct_type (dhandle, info, type_name, pp, +- descriptor == 's', typenums); ++ descriptor == 's', typenums, p_end); + break; + + case 'a': +@@ -1592,7 +1629,7 @@ parse_stab_type (void *dhandle, struct s + } + ++*pp; + +- dtype = parse_stab_array_type (dhandle, info, pp, stringp); ++ dtype = parse_stab_array_type (dhandle, info, pp, stringp, p_end); + break; + + case 'S': +@@ -1600,7 +1637,8 @@ parse_stab_type (void *dhandle, struct s + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, +- (debug_type **) NULL), ++ (debug_type **) NULL, ++ p_end), + stringp); + break; + +@@ -1633,7 +1671,7 @@ parse_stab_type (void *dhandle, struct s + storing them in the vector TYPENUMS. */ + + static bfd_boolean +-parse_stab_type_number (const char **pp, int *typenums) ++parse_stab_type_number (const char **pp, int *typenums, const char *p_end) + { + const char *orig; + +@@ -1642,34 +1680,39 @@ parse_stab_type_number (const char **pp, + if (**pp != '(') + { + typenums[0] = 0; +- typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL); ++ typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end); ++ return TRUE; + } +- else ++ ++ ++*pp; ++ typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end); ++ if (**pp != ',') + { +- ++*pp; +- typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL); +- if (**pp != ',') +- { +- bad_stab (orig); +- return FALSE; +- } +- ++*pp; +- typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL); +- if (**pp != ')') +- { +- bad_stab (orig); +- return FALSE; +- } +- ++*pp; ++ bad_stab (orig); ++ return FALSE; ++ } ++ ++ ++*pp; ++ typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end); ++ if (**pp != ')') ++ { ++ bad_stab (orig); ++ return FALSE; + } + ++ ++*pp; + return TRUE; + } + + /* Parse a range type. */ + + static debug_type +-parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, const int *typenums) ++parse_stab_range_type (void * dhandle, ++ struct stab_handle * info, ++ const char * type_name, ++ const char ** pp, ++ const int * typenums, ++ const char * p_end) + { + const char *orig; + int rangenums[2]; +@@ -1680,12 +1723,14 @@ parse_stab_range_type (void *dhandle, st + bfd_boolean ov2, ov3; + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + index_type = DEBUG_TYPE_NULL; + + /* First comes a type we are a subrange of. + In C it is usually 0, 1 or the type being defined. */ +- if (! parse_stab_type_number (pp, rangenums)) ++ if (! parse_stab_type_number (pp, rangenums, p_end)) + return DEBUG_TYPE_NULL; + + self_subrange = (rangenums[0] == typenums[0] +@@ -1695,7 +1740,7 @@ parse_stab_range_type (void *dhandle, st + { + *pp = orig; + index_type = parse_stab_type (dhandle, info, (const char *) NULL, +- pp, (debug_type **) NULL); ++ pp, (debug_type **) NULL, p_end); + if (index_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } +@@ -1706,7 +1751,7 @@ parse_stab_range_type (void *dhandle, st + /* The remaining two operands are usually lower and upper bounds of + the range. But in some special cases they mean something else. */ + s2 = *pp; +- n2 = parse_number (pp, &ov2); ++ n2 = parse_number (pp, &ov2, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1715,7 +1760,7 @@ parse_stab_range_type (void *dhandle, st + ++*pp; + + s3 = *pp; +- n3 = parse_number (pp, &ov3); ++ n3 = parse_number (pp, &ov3, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1853,13 +1898,15 @@ parse_stab_range_type (void *dhandle, st + FIXME. */ + + static debug_type +-parse_stab_sun_builtin_type (void *dhandle, const char **pp) ++parse_stab_sun_builtin_type (void *dhandle, const char **pp, const char * p_end) + { + const char *orig; + bfd_boolean unsignedp; + bfd_vma bits; + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + switch (**pp) + { +@@ -1888,7 +1935,7 @@ parse_stab_sun_builtin_type (void *dhand + by this type, except that unsigned short is 4 instead of 2. + Since this information is redundant with the third number, + we will ignore it. */ +- (void) parse_number (pp, (bfd_boolean *) NULL); ++ (void) parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1897,7 +1944,7 @@ parse_stab_sun_builtin_type (void *dhand + ++*pp; + + /* The second number is always 0, so ignore it too. */ +- (void) parse_number (pp, (bfd_boolean *) NULL); ++ (void) parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1906,7 +1953,7 @@ parse_stab_sun_builtin_type (void *dhand + ++*pp; + + /* The third number is the number of bits for this type. */ +- bits = parse_number (pp, (bfd_boolean *) NULL); ++ bits = parse_number (pp, (bfd_boolean *) NULL, p_end); + + /* The type *should* end with a semicolon. If it are embedded + in a larger type the semicolon may be the only way to know where +@@ -1926,17 +1973,19 @@ parse_stab_sun_builtin_type (void *dhand + /* Parse a builtin floating type generated by the Sun compiler. */ + + static debug_type +-parse_stab_sun_floating_type (void *dhandle, const char **pp) ++parse_stab_sun_floating_type (void *dhandle, const char **pp, const char *p_end) + { + const char *orig; + bfd_vma details; + bfd_vma bytes; + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + /* The first number has more details about the type, for example + FN_COMPLEX. */ +- details = parse_number (pp, (bfd_boolean *) NULL); ++ details = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1944,7 +1993,7 @@ parse_stab_sun_floating_type (void *dhan + } + + /* The second number is the number of bytes occupied by this type */ +- bytes = parse_number (pp, (bfd_boolean *) NULL); ++ bytes = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -1962,7 +2011,7 @@ parse_stab_sun_floating_type (void *dhan + /* Handle an enum type. */ + + static debug_type +-parse_stab_enum_type (void *dhandle, const char **pp) ++parse_stab_enum_type (void *dhandle, const char **pp, const char * p_end) + { + const char *orig; + const char **names; +@@ -1971,6 +2020,8 @@ parse_stab_enum_type (void *dhandle, con + unsigned int alloc; + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + /* FIXME: gdb checks os9k_stabs here. */ + +@@ -1978,8 +2029,14 @@ parse_stab_enum_type (void *dhandle, con + my guess is it's a type of some sort. Just ignore it. */ + if (**pp == '-') + { +- while (**pp != ':') ++ while (**pp != ':' && **pp != 0) + ++*pp; ++ ++ if (**pp == 0) ++ { ++ bad_stab (orig); ++ return DEBUG_TYPE_NULL; ++ } + ++*pp; + } + +@@ -2011,7 +2068,7 @@ parse_stab_enum_type (void *dhandle, con + name = savestring (*pp, p - *pp); + + *pp = p + 1; +- val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); ++ val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ',') + { + bad_stab (orig); +@@ -2053,9 +2110,13 @@ parse_stab_enum_type (void *dhandle, con + *PP will point to "4a:1,0,32;;". */ + + static debug_type +-parse_stab_struct_type (void *dhandle, struct stab_handle *info, +- const char *tagname, const char **pp, +- bfd_boolean structp, const int *typenums) ++parse_stab_struct_type (void * dhandle, ++ struct stab_handle * info, ++ const char * tagname, ++ const char ** pp, ++ bfd_boolean structp, ++ const int * typenums, ++ const char * p_end) + { + bfd_vma size; + debug_baseclass *baseclasses; +@@ -2066,14 +2127,14 @@ parse_stab_struct_type (void *dhandle, s + bfd_boolean ownvptr; + + /* Get the size. */ +- size = parse_number (pp, (bfd_boolean *) NULL); ++ size = parse_number (pp, (bfd_boolean *) NULL, p_end); + + /* Get the other information. */ +- if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses) +- || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics) +- || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods) ++ if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses, p_end) ++ || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics, p_end) ++ || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods, p_end) + || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase, +- &ownvptr)) ++ &ownvptr, p_end)) + { + if (fields != NULL) + free (fields); +@@ -2116,8 +2177,11 @@ parse_stab_struct_type (void *dhandle, s + Return TRUE for success, FALSE for failure. */ + + static bfd_boolean +-parse_stab_baseclasses (void *dhandle, struct stab_handle *info, +- const char **pp, debug_baseclass **retp) ++parse_stab_baseclasses (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ debug_baseclass ** retp, ++ const char * p_end) + { + const char *orig; + unsigned int c, i; +@@ -2126,6 +2190,8 @@ parse_stab_baseclasses (void *dhandle, s + *retp = NULL; + + orig = *pp; ++ if (orig >= p_end) ++ return FALSE; + + if (**pp != '!') + { +@@ -2134,7 +2200,7 @@ parse_stab_baseclasses (void *dhandle, s + } + ++*pp; + +- c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL); ++ c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL, p_end); + + if (**pp != ',') + { +@@ -2160,6 +2226,9 @@ parse_stab_baseclasses (void *dhandle, s + case '1': + is_virtual = TRUE; + break; ++ case 0: ++ bad_stab (orig); ++ return FALSE; + default: + warn_stab (orig, _("unknown virtual character for baseclass")); + is_virtual = FALSE; +@@ -2178,6 +2247,9 @@ parse_stab_baseclasses (void *dhandle, s + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; ++ case 0: ++ bad_stab (orig); ++ return FALSE; + default: + warn_stab (orig, _("unknown visibility character for baseclass")); + visibility = DEBUG_VISIBILITY_PUBLIC; +@@ -2188,7 +2260,7 @@ parse_stab_baseclasses (void *dhandle, s + /* The remaining value is the bit offset of the portion of the + object corresponding to this baseclass. Always zero in the + absence of multiple inheritance. */ +- bitpos = parse_number (pp, (bfd_boolean *) NULL); ++ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ',') + { + bad_stab (orig); +@@ -2197,7 +2269,7 @@ parse_stab_baseclasses (void *dhandle, s + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (type == DEBUG_TYPE_NULL) + return FALSE; + +@@ -2239,9 +2311,12 @@ parse_stab_baseclasses (void *dhandle, s + Returns 1 for success, 0 for failure. */ + + static bfd_boolean +-parse_stab_struct_fields (void *dhandle, struct stab_handle *info, +- const char **pp, debug_field **retp, +- bfd_boolean *staticsp) ++parse_stab_struct_fields (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ debug_field ** retp, ++ bfd_boolean * staticsp, ++ const char * p_end) + { + const char *orig; + const char *p; +@@ -2253,6 +2328,8 @@ parse_stab_struct_fields (void *dhandle, + *staticsp = FALSE; + + orig = *pp; ++ if (orig >= p_end) ++ return FALSE; + + c = 0; + alloc = 10; +@@ -2281,7 +2358,7 @@ parse_stab_struct_fields (void *dhandle, + if ((*p == '$' || *p == '.') && p[1] != '_') + { + ++*pp; +- if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c)) ++ if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c, p_end)) + { + free (fields); + return FALSE; +@@ -2307,7 +2384,7 @@ parse_stab_struct_fields (void *dhandle, + break; + + if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c, +- staticsp)) ++ staticsp, p_end)) + /* There is a potential resource leak here, but it is not important. */ + /* coverity[leaked_storage: FALSE] */ + return FALSE; +@@ -2325,8 +2402,11 @@ parse_stab_struct_fields (void *dhandle, + /* Special GNU C++ name. */ + + static bfd_boolean +-parse_stab_cpp_abbrev (void *dhandle, struct stab_handle *info, +- const char **pp, debug_field *retp) ++parse_stab_cpp_abbrev (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ debug_field * retp, ++ const char * p_end) + { + const char *orig; + int cpp_abbrev; +@@ -2339,6 +2419,8 @@ parse_stab_cpp_abbrev (void *dhandle, st + *retp = DEBUG_FIELD_NULL; + + orig = *pp; ++ if (orig >= p_end) ++ return FALSE; + + if (**pp != 'v') + { +@@ -2348,6 +2430,11 @@ parse_stab_cpp_abbrev (void *dhandle, st + ++*pp; + + cpp_abbrev = **pp; ++ if (cpp_abbrev == 0) ++ { ++ bad_stab (orig); ++ return FALSE; ++ } + ++*pp; + + /* At this point, *pp points to something like "22:23=*22...", where +@@ -2356,7 +2443,7 @@ parse_stab_cpp_abbrev (void *dhandle, st + name, and construct the field name. */ + + context = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (context == DEBUG_TYPE_NULL) + return FALSE; + +@@ -2392,7 +2479,7 @@ parse_stab_cpp_abbrev (void *dhandle, st + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (**pp != ',') + { + bad_stab (orig); +@@ -2402,7 +2489,7 @@ parse_stab_cpp_abbrev (void *dhandle, st + } + ++*pp; + +- bitpos = parse_number (pp, (bfd_boolean *) NULL); ++ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -2423,9 +2510,13 @@ parse_stab_cpp_abbrev (void *dhandle, st + /* Parse a single field in a struct or union. */ + + static bfd_boolean +-parse_stab_one_struct_field (void *dhandle, struct stab_handle *info, +- const char **pp, const char *p, +- debug_field *retp, bfd_boolean *staticsp) ++parse_stab_one_struct_field (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ const char * p, ++ debug_field * retp, ++ bfd_boolean * staticsp, ++ const char * p_end) + { + const char *orig; + char *name; +@@ -2435,6 +2526,8 @@ parse_stab_one_struct_field (void *dhand + bfd_vma bitsize; + + orig = *pp; ++ if (orig >= p_end) ++ return FALSE; + + /* FIXME: gdb checks ARM_DEMANGLING here. */ + +@@ -2458,6 +2551,9 @@ parse_stab_one_struct_field (void *dhand + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; ++ case 0: ++ bad_stab (orig); ++ return FALSE; + default: + warn_stab (orig, _("unknown visibility character for field")); + visibility = DEBUG_VISIBILITY_PUBLIC; +@@ -2467,7 +2563,7 @@ parse_stab_one_struct_field (void *dhand + } + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (type == DEBUG_TYPE_NULL) + { + free (name); +@@ -2507,7 +2603,7 @@ parse_stab_one_struct_field (void *dhand + } + ++*pp; + +- bitpos = parse_number (pp, (bfd_boolean *) NULL); ++ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ',') + { + bad_stab (orig); +@@ -2516,7 +2612,7 @@ parse_stab_one_struct_field (void *dhand + } + ++*pp; + +- bitsize = parse_number (pp, (bfd_boolean *) NULL); ++ bitsize = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -2564,9 +2660,13 @@ parse_stab_one_struct_field (void *dhand + name (such as `+=') and `.' marks the end of the operator name. */ + + static bfd_boolean +-parse_stab_members (void *dhandle, struct stab_handle *info, +- const char *tagname, const char **pp, +- const int *typenums, debug_method **retp) ++parse_stab_members (void * dhandle, ++ struct stab_handle * info, ++ const char * tagname, ++ const char ** pp, ++ const int * typenums, ++ debug_method ** retp, ++ const char * p_end) + { + const char *orig; + debug_method *methods; +@@ -2579,6 +2679,8 @@ parse_stab_members (void *dhandle, struc + *retp = NULL; + + orig = *pp; ++ if (orig >= p_end) ++ return FALSE; + + alloc = 0; + methods = NULL; +@@ -2648,7 +2750,7 @@ parse_stab_members (void *dhandle, struc + else + { + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (type == DEBUG_TYPE_NULL) + goto fail; + +@@ -2683,6 +2785,9 @@ parse_stab_members (void *dhandle, struc + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; ++ case 0: ++ bad_stab (orig); ++ goto fail; + default: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; +@@ -2731,7 +2836,7 @@ parse_stab_members (void *dhandle, struc + bit is supposedly set to distinguish + pointers-to-methods from virtual function indices. */ + ++*pp; +- voffset = parse_number (pp, (bfd_boolean *) NULL); ++ voffset = parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -2753,7 +2858,8 @@ parse_stab_members (void *dhandle, struc + look_ahead_type = parse_stab_type (dhandle, info, + (const char *) NULL, + pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, ++ p_end); + if (**pp == ':') + { + /* g++ version 1 overloaded methods. */ +@@ -3014,9 +3120,13 @@ parse_stab_argtypes (void *dhandle, stru + so we can look for the vptr base class info. */ + + static bfd_boolean +-parse_stab_tilde_field (void *dhandle, struct stab_handle *info, +- const char **pp, const int *typenums, +- debug_type *retvptrbase, bfd_boolean *retownvptr) ++parse_stab_tilde_field (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ const int * typenums, ++ debug_type * retvptrbase, ++ bfd_boolean * retownvptr, ++ const char * p_end) + { + const char *orig; + const char *hold; +@@ -3026,14 +3136,15 @@ parse_stab_tilde_field (void *dhandle, s + *retownvptr = FALSE; + + orig = *pp; +- ++ if (orig >= p_end) ++ return FALSE; ++ + /* If we are positioned at a ';', then skip it. */ + if (**pp == ';') + ++*pp; + + if (**pp != '~') + return TRUE; +- + ++*pp; + + if (**pp == '=' || **pp == '+' || **pp == '-') +@@ -3045,14 +3156,13 @@ parse_stab_tilde_field (void *dhandle, s + + if (**pp != '%') + return TRUE; +- + ++*pp; + + hold = *pp; + + /* The next number is the type number of the base class (possibly + our own class) which supplies the vtable for this class. */ +- if (! parse_stab_type_number (pp, vtypenums)) ++ if (! parse_stab_type_number (pp, vtypenums, p_end)) + return FALSE; + + if (vtypenums[0] == typenums[0] +@@ -3066,7 +3176,7 @@ parse_stab_tilde_field (void *dhandle, s + *pp = hold; + + vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + for (p = *pp; *p != ';' && *p != '\0'; p++) + ; + if (*p != ';') +@@ -3086,8 +3196,11 @@ parse_stab_tilde_field (void *dhandle, s + /* Read a definition of an array type. */ + + static debug_type +-parse_stab_array_type (void *dhandle, struct stab_handle *info, +- const char **pp, bfd_boolean stringp) ++parse_stab_array_type (void * dhandle, ++ struct stab_handle * info, ++ const char ** pp, ++ bfd_boolean stringp, ++ const char * p_end) + { + const char *orig; + const char *p; +@@ -3105,13 +3218,16 @@ parse_stab_array_type (void *dhandle, st + for these, produce a type like float[][]. */ + + orig = *pp; ++ if (orig >= p_end) ++ return DEBUG_TYPE_NULL; + + /* FIXME: gdb checks os9k_stabs here. */ + + /* If the index type is type 0, we take it as int. */ + p = *pp; +- if (! parse_stab_type_number (&p, typenums)) ++ if (! parse_stab_type_number (&p, typenums, p_end)) + return DEBUG_TYPE_NULL; ++ + if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=') + { + index_type = debug_find_named_type (dhandle, "int"); +@@ -3126,7 +3242,7 @@ parse_stab_array_type (void *dhandle, st + else + { + index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + } + + if (**pp != ';') +@@ -3140,13 +3256,13 @@ parse_stab_array_type (void *dhandle, st + + adjustable = FALSE; + +- if (! ISDIGIT (**pp) && **pp != '-') ++ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0) + { + ++*pp; + adjustable = TRUE; + } + +- lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); ++ lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -3156,13 +3272,13 @@ parse_stab_array_type (void *dhandle, st + } + ++*pp; + +- if (! ISDIGIT (**pp) && **pp != '-') ++ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0) + { + ++*pp; + adjustable = TRUE; + } + +- upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); ++ upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end); + if (**pp != ';') + { + bad_stab (orig); +@@ -3173,7 +3289,7 @@ parse_stab_array_type (void *dhandle, st + ++*pp; + + element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, +- (debug_type **) NULL); ++ (debug_type **) NULL, p_end); + if (element_type == DEBUG_TYPE_NULL) + /* There is a potential resource leak here, but it is not important. */ + /* coverity[leaked_storage: FALSE] */ +Only in binutils-2.30/binutils: stabs.c.orig +Only in binutils-2.30/binutils: stabs.c.rej diff --git a/SOURCES/binutils-CVE-2018-12699-part2-PR87861.patch b/SOURCES/binutils-CVE-2018-12699-part2-PR87861.patch new file mode 100644 index 0000000..007db2f --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part2-PR87861.patch @@ -0,0 +1,1210 @@ +diff -rup binutils.orig.1/binutils/NEWS binutils-2.30/binutils/NEWS +--- binutils.orig.1/binutils/NEWS 2024-10-29 14:04:54.266101412 +0000 ++++ binutils-2.30/binutils/NEWS 2024-10-29 14:15:21.886239329 +0000 +@@ -1,5 +1,16 @@ + -*- 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 value for this limit is defined by the DEMANGLE_RECRUSE_LIMIT ++ constant declared in the include/demangle.h header file. At the time ++ of writing this constant has the value of 1024. ++ ++ The --no-recurse-limit option can be used to remove the limit, restoring ++ the behaviour of earlier versions of these tools. This may be needed in ++ order to dmangle truly complicated names, but it also leaves the tools ++ vulnerable to stack exhaustion from maliciously constructed mangled names. ++ + * Tools which display names or strings (readelf, strings, nm, objdump) + have a new command line option which controls how unicode characters are + handled. By default they are treated as normal for the tool. Using +diff -rup binutils.orig.1/binutils/addr2line.c binutils-2.30/binutils/addr2line.c +--- binutils.orig.1/binutils/addr2line.c 2024-10-29 14:04:54.258101392 +0000 ++++ binutils-2.30/binutils/addr2line.c 2024-10-29 14:14:33.062109460 +0000 +@@ -45,6 +45,9 @@ static bfd_boolean do_demangle; /* -C, + 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; ++ + static int naddr; /* Number of addresses to process. */ + static char **addr; /* Hex addresses to process. */ + +@@ -59,6 +62,10 @@ static struct option long_options[] = + {"functions", no_argument, NULL, 'f'}, + {"inlines", no_argument, NULL, 'i'}, + {"pretty-print", no_argument, NULL, 'p'}, ++ {"recurse-limit", no_argument, NULL, 'R'}, ++ {"recursion-limit", no_argument, NULL, 'R'}, ++ {"no-recurse-limit", no_argument, NULL, 'r'}, ++ {"no-recursion-limit", no_argument, NULL, 'r'}, + {"section", required_argument, NULL, 'j'}, + {"target", required_argument, NULL, 'b'}, + {"help", no_argument, NULL, 'H'}, +@@ -91,6 +98,8 @@ 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 Enable a limit on recursion whilst demangling. [Default]\n\ ++ -r --no-recurse-limit Disable a limit on recursion whilst demangling\n\ + -h --help Display this information\n\ + -v --version Display the program's version\n\ + \n")); +@@ -289,7 +298,7 @@ translate_addresses (bfd *abfd, asection + 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; + } +@@ -441,7 +450,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:rRsfHhij:pVv", long_options, (int *) 0)) + != EOF) + { + switch (c) +@@ -468,6 +477,12 @@ main (int argc, char **argv) + cplus_demangle_set_style (style); + } + break; ++ case 'r': ++ demangle_flags |= DMGL_NO_RECURSE_LIMIT; ++ break; ++ case 'R': ++ demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT; ++ break; + case 'e': + file_name = optarg; + break; +diff -rup binutils.orig.1/binutils/cxxfilt.c binutils-2.30/binutils/cxxfilt.c +--- binutils.orig.1/binutils/cxxfilt.c 2024-10-29 14:04:54.258101392 +0000 ++++ binutils-2.30/binutils/cxxfilt.c 2024-10-29 14:14:33.062109460 +0000 +@@ -42,6 +42,10 @@ static const struct option long_options[ + {"no-verbose", no_argument, NULL, 'i'}, + {"types", no_argument, NULL, 't'}, + {"version", no_argument, NULL, 'v'}, ++ {"recurse-limit", no_argument, NULL, 'R'}, ++ {"recursion-limit", no_argument, NULL, 'R'}, ++ {"no-recurse-limit", no_argument, NULL, 'r'}, ++ {"no-recursion-limit", no_argument, NULL, 'r'}, + {NULL, no_argument, NULL, 0} + }; + +@@ -102,6 +106,8 @@ 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] Enable a limit on recursion whilst demangling. [Default]\n\ ++ ]-r|--no-recurse-limit] Disable a limit on recursion whilst demangling\n\ + [-t|--types] Also attempt to demangle type encodings\n\ + [-s|--format "); + print_demangler_list (stream); +@@ -180,7 +186,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, "_hinprRs:tv", long_options, (int *) 0)) != EOF) + { + switch (c) + { +@@ -195,6 +201,12 @@ main (int argc, char **argv) + case 'p': + flags &= ~ DMGL_PARAMS; + break; ++ case 'r': ++ flags |= DMGL_NO_RECURSE_LIMIT; ++ break; ++ case 'R': ++ flags &= ~ DMGL_NO_RECURSE_LIMIT; ++ break; + case 't': + flags |= DMGL_TYPES; + break; +diff -rup binutils.orig.1/binutils/doc/binutils.texi binutils-2.30/binutils/doc/binutils.texi +--- binutils.orig.1/binutils/doc/binutils.texi 2024-10-29 14:04:54.257101390 +0000 ++++ binutils-2.30/binutils/doc/binutils.texi 2024-10-29 14:14:33.062109460 +0000 +@@ -769,7 +769,9 @@ nm [@option{-A}|@option{-o}|@option{--pr + [@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{--no-recurse-limit}|@option{--recurse-limit}]] ++ [@option{--size-sort}] [@option{--special-syms}] + [@option{--synthetic}] [@option{--with-symbol-versions}] [@option{--target=}@var{bfdname}] + [@var{objfile}@dots{}] + @c man end +@@ -936,6 +938,22 @@ for more information on demangling. + @item --no-demangle + Do not demangle low-level symbol names. This is the default. + ++@item --recurse-limit ++@itemx --no-recurse-limit ++@itemx --recursion-limit ++@itemx --no-recursion-limit ++Enables or disables 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 1024 levels of nesting. ++ ++The default is for this limit to be enabled, but disabling it may be ++necessary in order to demangle truly complicated names. Note however ++that if the recursion limit is disabled then stack exhaustion is ++possible and any bug reports about such an event will be rejected. ++ + @item -D + @itemx --dynamic + @cindex dynamic symbols +@@ -2105,6 +2123,7 @@ objdump [@option{-a}|@option{--archive-h + [@option{--adjust-vma=}@var{offset}] + [@option{--dwarf-depth=@var{n}}] + [@option{--dwarf-start=@var{n}}] ++ [@option{--no-recurse-limit}|@option{--recurse-limit}] + [@option{--special-syms}] + [@option{--prefix=}@var{prefix}] + [@option{--prefix-strip=}@var{level}] +@@ -2182,6 +2201,22 @@ mangling styles. The optional demangling + choose an appropriate demangling style for your compiler. @xref{c++filt}, + for more information on demangling. + ++@item --recurse-limit ++@itemx --no-recurse-limit ++@itemx --recursion-limit ++@itemx --no-recursion-limit ++Enables or disables 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 1024 levels of nesting. ++ ++The default is for this limit to be enabled, but disabling it may be ++necessary in order to demangle truly complicated names. Note however ++that if the recursion limit is disabled then stack exhaustion is ++possible and any bug reports about such an event will be rejected. ++ + @item -g + @itemx --debugging + Display debugging information. This attempts to parse STABS and IEEE +@@ -3440,6 +3475,8 @@ c++filt [@option{-_}|@option{--strip-und + [@option{-p}|@option{--no-params}] + [@option{-t}|@option{--types}] + [@option{-i}|@option{--no-verbose}] ++ [@option{-r}|@option{--no-recurse-limit}] ++ [@option{-R}|@option{--recurse-limit}] + [@option{-s} @var{format}|@option{--format=}@var{format}] + [@option{--help}] [@option{--version}] [@var{symbol}@dots{}] + @c man end +@@ -3544,6 +3581,28 @@ demangled to ``signed char''. + Do not include implementation details (if any) in the demangled + output. + ++@item -r ++@itemx -R ++@itemx --recurse-limit ++@itemx --no-recurse-limit ++@itemx --recursion-limit ++@itemx --no-recursion-limit ++Enables or disables 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 1024 levels of nesting. ++ ++The default is for this limit to be enabled, but disabling it may be ++necessary in order to demangle truly complicated names. Note however ++that if the recursion limit is disabled then stack exhaustion is ++possible and any bug reports about such an event will be rejected. ++ ++The @option{-r} option is a synonym for the ++@option{--no-recurse-limit} option. The @option{-R} option is a ++synonym for the @option{--recurse-limit} option. ++ + @item -s @var{format} + @itemx --format=@var{format} + @command{c++filt} can decode various methods of mangling, used by +@@ -3617,6 +3676,8 @@ 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}|@option{--no-recurse-limit}] ++ [@option{-R}|@option{--recurse-limit}] + [@option{-e} @var{filename}|@option{--exe=}@var{filename}] + [@option{-f}|@option{--functions}] [@option{-s}|@option{--basename}] + [@option{-i}|@option{--inlines}] +@@ -3742,6 +3803,32 @@ Read offsets relative to the specified s + 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 ++@itemx -R ++@itemx --recurse-limit ++@itemx --no-recurse-limit ++@itemx --recursion-limit ++@itemx --no-recursion-limit ++Enables or disables 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 1024 levels of nesting. ++ ++The default is for this limit to be enabled, but disabling it may be ++necessary in order to demangle truly complicated names. Note however ++that if the recursion limit is disabled then stack exhaustion is ++possible and any bug reports about such an event will be rejected. ++ ++The @option{-r} option is a synonym for the ++@option{--no-recurse-limit} option. The @option{-R} option is a ++synonym for the @option{--recurse-limit} option. ++ ++Note this option is only effective if the @option{-C} or ++@option{--demangle} option has been enabled. ++ + @end table + + @c man end +diff -rup binutils.orig.1/binutils/nm.c binutils-2.30/binutils/nm.c +--- binutils.orig.1/binutils/nm.c 2024-10-29 14:04:54.266101412 +0000 ++++ binutils-2.30/binutils/nm.c 2024-10-29 14:14:33.063109462 +0000 +@@ -167,6 +167,8 @@ static int line_numbers = 0; /* Print li + 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; ++ + /* 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. */ +@@ -211,9 +213,14 @@ typedef enum unicode_display_type + + static unicode_display_type unicode_display = unicode_default; + +-#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, ++ OPTION_NO_RECURSE_LIMIT ++}; + + static struct option long_options[] = + { +@@ -226,6 +233,8 @@ static struct option long_options[] = + {"line-numbers", no_argument, 0, 'l'}, + {"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */ + {"no-demangle", no_argument, &do_demangle, 0}, ++ {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, ++ {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, + {"no-sort", no_argument, 0, 'p'}, + {"numeric-sort", no_argument, 0, 'n'}, + {"plugin", required_argument, 0, OPTION_PLUGIN}, +@@ -234,6 +243,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", no_argument, NULL, OPTION_RECURSE_LIMIT}, ++ {"recursion-limit", no_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}, +@@ -263,6 +274,8 @@ 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 Enable a demangling recursion limit. This is the default.\n\ ++ --no-recurse-limit Disable a demangling recursion limit.\n\ + -D, --dynamic Display dynamic symbols instead of normal symbols\n\ + --defined-only Display only defined symbols\n\ + -e (ignored)\n\ +@@ -610,7 +623,7 @@ print_symname (const char *form, const c + { + 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) + { +@@ -1892,6 +1905,12 @@ main (int argc, char **argv) + cplus_demangle_set_style (style); + } + break; ++ case OPTION_RECURSE_LIMIT: ++ demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT; ++ break; ++ case OPTION_NO_RECURSE_LIMIT: ++ demangle_flags |= DMGL_NO_RECURSE_LIMIT; ++ break; + case 'D': + dynamic = 1; + break; +diff -rup binutils.orig.1/binutils/objdump.c binutils-2.30/binutils/objdump.c +--- binutils.orig.1/binutils/objdump.c 2024-10-29 14:04:54.266101412 +0000 ++++ binutils-2.30/binutils/objdump.c 2024-10-29 14:14:33.063109462 +0000 +@@ -119,6 +119,8 @@ static int prefix_strip; /* --prefix-st + static size_t prefix_length; + static bfd_boolean unwind_inlines; /* --inlines. */ + ++static int demangle_flags = DMGL_ANSI | DMGL_PARAMS; ++ + /* A structure to record the sections mentioned in -j switches. */ + struct only + { +@@ -264,6 +266,8 @@ 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 Enable a limit on recursion whilst demangling. [Default]\n\ ++ --no-recurse-limit Disable a limit on recursion whilst demangling\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\ +@@ -314,6 +318,8 @@ enum option_values + OPTION_DWARF_DEPTH, + OPTION_DWARF_CHECK, + OPTION_DWARF_START, ++ OPTION_RECURSE_LIMIT, ++ OPTION_NO_RECURSE_LIMIT, + OPTION_INLINES + }; + +@@ -345,6 +351,10 @@ 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", no_argument, NULL, OPTION_RECURSE_LIMIT}, ++ {"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT}, ++ {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, ++ {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, + {"reloc", no_argument, NULL, 'r'}, + {"section", required_argument, NULL, 'j'}, + {"section-headers", no_argument, NULL, 'h'}, +@@ -1082,7 +1092,7 @@ objdump_print_symname (bfd *abfd, struct + 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; + } +@@ -3436,7 +3446,7 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED + /* 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, +@@ -4107,6 +4117,12 @@ main (int argc, char **argv) + cplus_demangle_set_style (style); + } + break; ++ case OPTION_RECURSE_LIMIT: ++ demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT; ++ break; ++ case OPTION_NO_RECURSE_LIMIT: ++ demangle_flags |= DMGL_NO_RECURSE_LIMIT; ++ break; + case 'w': + do_wide = wide_output = TRUE; + break; +diff -rup binutils.orig.1/binutils/prdbg.c binutils-2.30/binutils/prdbg.c +--- binutils.orig.1/binutils/prdbg.c 2024-10-29 14:04:54.258101392 +0000 ++++ binutils-2.30/binutils/prdbg.c 2024-10-29 14:14:33.063109462 +0000 +@@ -286,6 +286,8 @@ static const struct debug_write_fns tg_f + pr_end_function, /* Same, does nothing. */ + tg_lineno + }; ++ ++static int demangle_flags = DMGL_ANSI | DMGL_PARAMS; + + /* Print out the generic debugging information recorded in dhandle. */ + +@@ -2600,7 +2602,7 @@ tg_variable (void *p, const char *name, + + 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 * + + 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; +diff -rup binutils.orig.1/binutils/stabs.c binutils-2.30/binutils/stabs.c +--- binutils.orig.1/binutils/stabs.c 2024-10-29 14:04:54.267101415 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-10-29 14:14:33.063109462 +0000 +@@ -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; ++ + /* Save a string in memory. */ + + static char * +@@ -4551,7 +4553,7 @@ stab_demangle_template (struct stab_dema + + free (s1); + +- s3 = cplus_demangle (s2, DMGL_ANSI); ++ s3 = cplus_demangle (s2, demangle_flags); + + free (s2); + +@@ -5277,7 +5279,7 @@ stab_demangle_v3_argtypes (void *dhandle + 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); +@@ -5452,7 +5454,7 @@ stab_demangle_v3_arg (void *dhandle, str + /* 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")); +@@ -5534,7 +5536,7 @@ stab_demangle_v3_arg (void *dhandle, str + /* 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")); +diff -rup binutils.orig.1/binutils/testsuite/config/default.exp binutils-2.30/binutils/testsuite/config/default.exp +--- binutils.orig.1/binutils/testsuite/config/default.exp 2024-10-29 14:04:54.266101412 +0000 ++++ binutils-2.30/binutils/testsuite/config/default.exp 2024-10-29 14:14:33.064109465 +0000 +@@ -72,6 +72,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} + +diff -rup binutils.orig.1/include/demangle.h binutils-2.30/include/demangle.h +--- binutils.orig.1/include/demangle.h 2024-10-29 14:04:54.545102141 +0000 ++++ binutils-2.30/include/demangle.h 2024-10-29 14:14:33.064109465 +0000 +@@ -68,6 +68,17 @@ extern "C" { + /* If none of these are set, use 'current_demangling_style' as the default. */ + #define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) + ++/* Disable a limit on the depth of recursion in mangled strings. ++ Note if this limit is disabled then stack exhaustion is possible when ++ demangling pathologically complicated strings. Bug reports about stack ++ exhaustion when the option is enabled will be rejected. */ ++#define DMGL_NO_RECURSE_LIMIT (1 << 18) ++ ++/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as ++ the maximum depth of recursion allowed. It should be enough for any ++ real-world mangled name. */ ++#define DEMANGLE_RECURSION_LIMIT 1024 ++ + /* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though +@@ -392,6 +403,9 @@ enum demangle_component_type + template argument, and the right subtree is either NULL or + another TEMPLATE_ARGLIST node. */ + DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, ++ /* A template parameter object (C++20). The left subtree is the ++ corresponding template argument. */ ++ DEMANGLE_COMPONENT_TPARM_OBJ, + /* An initializer list. The left subtree is either an explicit type or + NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */ + DEMANGLE_COMPONENT_INITIALIZER_LIST, +diff -rup binutils.orig.1/libiberty/config.in binutils-2.30/libiberty/config.in +--- binutils.orig.1/libiberty/config.in 2024-10-29 14:04:54.532102107 +0000 ++++ binutils-2.30/libiberty/config.in 2024-10-29 14:14:33.064109465 +0000 +@@ -195,6 +195,9 @@ + /* Define to 1 if you have the `on_exit' function. */ + #undef HAVE_ON_EXIT + ++/* Define to 1 if you have the `pipe2' function. */ ++#undef HAVE_PIPE2 ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_PROCESS_H + +diff -rup binutils.orig.1/libiberty/configure binutils-2.30/libiberty/configure +--- binutils.orig.1/libiberty/configure 2024-10-29 14:04:54.532102107 +0000 ++++ binutils-2.30/libiberty/configure 2024-10-29 14:14:33.065109468 +0000 +@@ -5727,7 +5727,7 @@ funcs="$funcs setproctitle" + vars="sys_errlist sys_nerr sys_siglist" + + checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \ +- getsysinfo gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic \ ++ getsysinfo gettimeofday on_exit pipe2 psignal pstat_getdynamic pstat_getstatic \ + realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \ + sysmp table times wait3 wait4" + +@@ -5743,7 +5743,7 @@ if test "x" = "y"; then + index insque \ + memchr memcmp memcpy memmem memmove memset mkstemps \ + on_exit \ +- psignal pstat_getdynamic pstat_getstatic putenv \ ++ pipe2 psignal pstat_getdynamic pstat_getstatic putenv \ + random realpath rename rindex \ + sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \ + stpcpy stpncpy strcasecmp strchr strdup \ +diff -rup binutils.orig.1/libiberty/configure.ac binutils-2.30/libiberty/configure.ac +--- binutils.orig.1/libiberty/configure.ac 2024-10-29 14:04:54.532102107 +0000 ++++ binutils-2.30/libiberty/configure.ac 2024-10-29 14:14:33.065109468 +0000 +@@ -391,7 +391,7 @@ funcs="$funcs setproctitle" + vars="sys_errlist sys_nerr sys_siglist" + + checkfuncs="__fsetlocking canonicalize_file_name dup3 getrlimit getrusage \ +- getsysinfo gettimeofday on_exit psignal pstat_getdynamic pstat_getstatic \ ++ getsysinfo gettimeofday on_exit pipe2 psignal pstat_getdynamic pstat_getstatic \ + realpath setrlimit sbrk spawnve spawnvpe strerror strsignal sysconf sysctl \ + sysmp table times wait3 wait4" + +@@ -407,7 +407,7 @@ if test "x" = "y"; then + index insque \ + memchr memcmp memcpy memmem memmove memset mkstemps \ + on_exit \ +- psignal pstat_getdynamic pstat_getstatic putenv \ ++ pipe2 psignal pstat_getdynamic pstat_getstatic putenv \ + random realpath rename rindex \ + sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \ + stpcpy stpncpy strcasecmp strchr strdup \ +diff -rup binutils.orig.1/libiberty/cp-demangle.c binutils-2.30/libiberty/cp-demangle.c +--- binutils.orig.1/libiberty/cp-demangle.c 2024-10-29 14:04:54.532102107 +0000 ++++ binutils-2.30/libiberty/cp-demangle.c 2024-10-29 14:14:33.065109468 +0000 +@@ -625,6 +625,9 @@ d_dump (struct demangle_component *dc, i + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + printf ("template parameter %ld\n", dc->u.s_number.number); + return; ++ case DEMANGLE_COMPONENT_TPARM_OBJ: ++ printf ("template parameter object\n"); ++ break; + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + printf ("function parameter %ld\n", dc->u.s_number.number); + return; +@@ -1007,6 +1010,7 @@ d_make_comp (struct d_info *di, enum dem + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_TRINARY_ARG2: ++ case DEMANGLE_COMPONENT_TPARM_OBJ: + if (left == NULL) + return NULL; + break; +@@ -2007,6 +2011,7 @@ d_java_resource (struct d_info *di) + ::= TT + ::= TI + ::= TS ++ ::= TA + ::= GV <(object) name> + ::= T <(base) encoding> + ::= Tc <(base) encoding> +@@ -2099,6 +2104,10 @@ d_special_name (struct d_info *di) + return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER, + d_name (di), NULL); + ++ case 'A': ++ return d_make_comp (di, DEMANGLE_COMPONENT_TPARM_OBJ, ++ d_template_arg (di), NULL); ++ + default: + return NULL; + } +@@ -2843,21 +2852,35 @@ d_ref_qualifier (struct d_info *di, stru + static struct demangle_component * + d_function_type (struct d_info *di) + { +- struct demangle_component *ret; ++ struct demangle_component *ret = NULL; + +- if (! d_check_char (di, 'F')) +- return NULL; +- if (d_peek_char (di) == 'Y') ++ if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0) + { +- /* Function has C linkage. We don't print this information. +- FIXME: We should print it in verbose mode. */ +- d_advance (di, 1); ++ if (di->recursion_level > DEMANGLE_RECURSION_LIMIT) ++ /* FIXME: There ought to be a way to report ++ that the recursion limit has been reached. */ ++ return NULL; ++ ++ di->recursion_level ++; + } +- ret = d_bare_function_type (di, 1); +- ret = d_ref_qualifier (di, ret); + +- if (! d_check_char (di, 'E')) +- return NULL; ++ if (d_check_char (di, 'F')) ++ { ++ if (d_peek_char (di) == 'Y') ++ { ++ /* Function has C linkage. We don't print this information. ++ FIXME: We should print it in verbose mode. */ ++ d_advance (di, 1); ++ } ++ ret = d_bare_function_type (di, 1); ++ ret = d_ref_qualifier (di, ret); ++ ++ if (! d_check_char (di, 'E')) ++ ret = NULL; ++ } ++ ++ if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0) ++ di->recursion_level --; + return ret; + } + +@@ -3327,11 +3350,11 @@ d_expression_1 (struct d_info *di) + { + /* Brace-enclosed initializer list, untyped or typed. */ + struct demangle_component *type = NULL; ++ d_advance (di, 2); + if (peek == 't') + type = cplus_demangle_type (di); + if (!d_peek_next_char (di)) + return NULL; +- d_advance (di, 2); + return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, + type, d_exprlist (di, 'E')); + } +@@ -4101,6 +4124,7 @@ d_count_templates_scopes (int *num_templ + case DEMANGLE_COMPONENT_VECTOR_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: ++ case DEMANGLE_COMPONENT_TPARM_OBJ: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: +@@ -4872,6 +4896,11 @@ d_print_comp_inner (struct d_print_info + } + return; + ++ case DEMANGLE_COMPONENT_TPARM_OBJ: ++ d_append_string (dpi, "template parameter object for "); ++ d_print_comp (dpi, options, d_left (dc)); ++ return; ++ + case DEMANGLE_COMPONENT_CTOR: + d_print_comp (dpi, options, dc->u.s_ctor.name); + return; +@@ -6188,6 +6217,7 @@ cplus_demangle_init_info (const char *ma + di->expansion = 0; + di->is_expression = 0; + di->is_conversion = 0; ++ di->recursion_level = 0; + } + + /* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI +@@ -6227,6 +6257,20 @@ d_demangle_callback (const char *mangled + + cplus_demangle_init_info (mangled, options, strlen (mangled), &di); + ++ /* PR 87675 - Check for a mangled string that is so long ++ that we do not have enough stack space to demangle it. */ ++ if (((options & DMGL_NO_RECURSE_LIMIT) == 0) ++ /* This check is a bit arbitrary, since what we really want to do is to ++ compare the sizes of the di.comps and di.subs arrays against the ++ amount of stack space remaining. But there is no portable way to do ++ this, so instead we use the recursion limit as a guide to the maximum ++ size of the arrays. */ ++ && (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT) ++ { ++ /* FIXME: We need a way to indicate that a stack limit has been reached. */ ++ return 0; ++ } ++ + { + #ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; +diff -rup binutils.orig.1/libiberty/cp-demangle.h binutils-2.30/libiberty/cp-demangle.h +--- binutils.orig.1/libiberty/cp-demangle.h 2024-10-29 14:04:54.532102107 +0000 ++++ binutils-2.30/libiberty/cp-demangle.h 2024-10-29 14:14:33.065109468 +0000 +@@ -122,6 +122,9 @@ struct d_info + /* Non-zero if we are parsing the type operand of a conversion + operator, but not when in an expression. */ + int is_conversion; ++ /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to ++ the current recursion level. */ ++ unsigned int recursion_level; + }; + + /* To avoid running past the ending '\0', don't: +diff -rup binutils.orig.1/libiberty/cplus-dem.c binutils-2.30/libiberty/cplus-dem.c +--- binutils.orig.1/libiberty/cplus-dem.c 2024-10-29 14:04:54.530102102 +0000 ++++ binutils-2.30/libiberty/cplus-dem.c 2024-10-29 14:14:33.065109468 +0000 +@@ -146,6 +146,7 @@ struct work_stuff + int *proctypevec; /* Indices of currently processed remembered typevecs. */ + int proctypevec_size; + int nproctypes; ++ unsigned int recursion_level; + }; + + #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +@@ -1292,12 +1293,14 @@ squangle_mop_up (struct work_stuff *work + free ((char *) work -> btypevec); + work->btypevec = NULL; + work->bsize = 0; ++ work->numb = 0; + } + if (work -> ktypevec != NULL) + { + free ((char *) work -> ktypevec); + work->ktypevec = NULL; + work->ksize = 0; ++ work->numk = 0; + } + } + +@@ -1331,8 +1334,15 @@ work_stuff_copy_to_from (struct work_stu + + for (i = 0; i < from->numk; i++) + { +- int len = strlen (from->ktypevec[i]) + 1; ++ int len; + ++ if (from->ktypevec[i] == NULL) ++ { ++ to->ktypevec[i] = NULL; ++ continue; ++ } ++ ++ len = strlen (from->ktypevec[i]) + 1; + to->ktypevec[i] = XNEWVEC (char, len); + memcpy (to->ktypevec[i], from->ktypevec[i], len); + } +@@ -1342,8 +1352,15 @@ work_stuff_copy_to_from (struct work_stu + + for (i = 0; i < from->numb; i++) + { +- int len = strlen (from->btypevec[i]) + 1; ++ int len; + ++ if (from->btypevec[i] == NULL) ++ { ++ to->btypevec[i] = NULL; ++ continue; ++ } ++ ++ len = strlen (from->btypevec[i]) + 1; + to->btypevec[i] = XNEWVEC (char , len); + memcpy (to->btypevec[i], from->btypevec[i], len); + } +@@ -1401,6 +1418,7 @@ delete_non_B_K_work_stuff (struct work_s + + free ((char*) work->tmpl_argvec); + work->tmpl_argvec = NULL; ++ work->ntmpl_args = 0; + } + if (work->previous_argument) + { +@@ -4471,12 +4489,14 @@ remember_Btype (struct work_stuff *work, + char *tem; + + tem = XNEWVEC (char, len + 1); +- memcpy (tem, start, len); ++ if (len > 0) ++ memcpy (tem, start, len); + tem[len] = '\0'; + work -> btypevec[index] = tem; + } + + /* Lose all the info related to B and K type codes. */ ++ + static void + forget_B_and_K_types (struct work_stuff *work) + { +@@ -4502,6 +4522,7 @@ forget_B_and_K_types (struct work_stuff + } + } + } ++ + /* Forget the remembered types, but not the type vector itself. */ + + static void +@@ -4696,6 +4717,16 @@ demangle_nested_args (struct work_stuff + int result; + int saved_nrepeats; + ++ if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) ++ { ++ if (work->recursion_level > DEMANGLE_RECURSION_LIMIT) ++ /* FIXME: There ought to be a way to report ++ that the recursion limit has been reached. */ ++ return 0; ++ ++ work->recursion_level ++; ++ } ++ + /* The G++ name-mangling algorithm does not remember types on nested + argument lists, unless -fsquangling is used, and in that case the + type vector updated by remember_type is not used. So, we turn +@@ -4722,6 +4753,9 @@ demangle_nested_args (struct work_stuff + --work->forgetting_types; + work->nrepeats = saved_nrepeats; + ++ if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) ++ --work->recursion_level; ++ + return result; + } + +diff -rup binutils.orig.1/libiberty/pex-unix.c binutils-2.30/libiberty/pex-unix.c +--- binutils.orig.1/libiberty/pex-unix.c 2024-10-29 14:04:54.531102105 +0000 ++++ binutils-2.30/libiberty/pex-unix.c 2024-10-29 14:14:33.065109468 +0000 +@@ -298,8 +298,6 @@ pex_wait (struct pex_obj *obj, pid_t pid + #endif /* ! defined (HAVE_WAITPID) */ + #endif /* ! defined (HAVE_WAIT4) */ + +-static void pex_child_error (struct pex_obj *, const char *, const char *, int) +- ATTRIBUTE_NORETURN; + static int pex_unix_open_read (struct pex_obj *, const char *, int); + static int pex_unix_open_write (struct pex_obj *, const char *, int, int); + static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, +@@ -366,28 +364,6 @@ pex_unix_close (struct pex_obj *obj ATTR + return close (fd); + } + +-/* Report an error from a child process. We don't use stdio routines, +- because we might be here due to a vfork call. */ +- +-static void +-pex_child_error (struct pex_obj *obj, const char *executable, +- const char *errmsg, int err) +-{ +- int retval = 0; +-#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0) +- writeerr (obj->pname); +- writeerr (": error trying to exec '"); +- writeerr (executable); +- writeerr ("': "); +- writeerr (errmsg); +- writeerr (": "); +- writeerr (xstrerror (err)); +- writeerr ("\n"); +-#undef writeerr +- /* Exit with -2 if the error output failed, too. */ +- _exit (retval == 0 ? -1 : -2); +-} +- + /* Execute a child. */ + + #if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE) +@@ -592,21 +568,53 @@ pex_unix_exec_child (struct pex_obj *obj + int in, int out, int errdes, + int toclose, const char **errmsg, int *err) + { +- pid_t pid; ++ pid_t pid = -1; ++ /* Tuple to communicate error from child to parent. We can safely ++ transfer string literal pointers as both run with identical ++ address mappings. */ ++ struct fn_err ++ { ++ const char *fn; ++ int err; ++ }; ++ volatile int do_pipe = 0; ++ volatile int pipes[2]; /* [0]:reader,[1]:writer. */ ++#ifdef O_CLOEXEC ++ do_pipe = 1; ++#endif ++ if (do_pipe) ++ { ++#ifdef HAVE_PIPE2 ++ if (pipe2 ((int *)pipes, O_CLOEXEC)) ++ do_pipe = 0; ++#else ++ if (pipe ((int *)pipes)) ++ do_pipe = 0; ++ else ++ { ++ if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1) ++ { ++ close (pipes[0]); ++ close (pipes[1]); ++ do_pipe = 0; ++ } ++ } ++#endif ++ } + + /* We declare these to be volatile to avoid warnings from gcc about + them being clobbered by vfork. */ +- volatile int sleep_interval; ++ volatile int sleep_interval = 1; + volatile int retries; + + /* We vfork and then set environ in the child before calling execvp. + This clobbers the parent's environ so we need to restore it. + It would be nice to use one of the exec* functions that takes an +- environment as a parameter, but that may have portability issues. */ +- char **save_environ = environ; ++ environment as a parameter, but that may have portability ++ issues. It is marked volatile so the child doesn't consider it a ++ dead variable and therefore clobber where ever it is stored. */ ++ char **volatile save_environ = environ; + +- sleep_interval = 1; +- pid = -1; + for (retries = 0; retries < 4; ++retries) + { + pid = vfork (); +@@ -619,104 +627,138 @@ pex_unix_exec_child (struct pex_obj *obj + switch (pid) + { + case -1: ++ if (do_pipe) ++ { ++ close (pipes[0]); ++ close (pipes[1]); ++ } + *err = errno; + *errmsg = VFORK_STRING; + return (pid_t) -1; + + case 0: + /* Child process. */ +- if (in != STDIN_FILE_NO) +- { +- if (dup2 (in, STDIN_FILE_NO) < 0) +- pex_child_error (obj, executable, "dup2", errno); +- if (close (in) < 0) +- pex_child_error (obj, executable, "close", errno); +- } +- if (out != STDOUT_FILE_NO) +- { +- if (dup2 (out, STDOUT_FILE_NO) < 0) +- pex_child_error (obj, executable, "dup2", errno); +- if (close (out) < 0) +- pex_child_error (obj, executable, "close", errno); +- } +- if (errdes != STDERR_FILE_NO) +- { +- if (dup2 (errdes, STDERR_FILE_NO) < 0) +- pex_child_error (obj, executable, "dup2", errno); +- if (close (errdes) < 0) +- pex_child_error (obj, executable, "close", errno); +- } +- if (toclose >= 0) +- { +- if (close (toclose) < 0) +- pex_child_error (obj, executable, "close", errno); +- } +- if ((flags & PEX_STDERR_TO_STDOUT) != 0) +- { +- if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) +- pex_child_error (obj, executable, "dup2", errno); +- } +- +- if (env) +- { +- /* NOTE: In a standard vfork implementation this clobbers the +- parent's copy of environ "too" (in reality there's only one copy). +- This is ok as we restore it below. */ +- environ = (char**) env; +- } +- +- if ((flags & PEX_SEARCH) != 0) +- { +- execvp (executable, to_ptr32 (argv)); +- pex_child_error (obj, executable, "execvp", errno); +- } +- else +- { +- execv (executable, to_ptr32 (argv)); +- pex_child_error (obj, executable, "execv", errno); +- } ++ { ++ struct fn_err failed; ++ failed.fn = NULL; ++ ++ if (do_pipe) ++ close (pipes[0]); ++ if (!failed.fn && in != STDIN_FILE_NO) ++ { ++ if (dup2 (in, STDIN_FILE_NO) < 0) ++ failed.fn = "dup2", failed.err = errno; ++ else if (close (in) < 0) ++ failed.fn = "close", failed.err = errno; ++ } ++ if (!failed.fn && out != STDOUT_FILE_NO) ++ { ++ if (dup2 (out, STDOUT_FILE_NO) < 0) ++ failed.fn = "dup2", failed.err = errno; ++ else if (close (out) < 0) ++ failed.fn = "close", failed.err = errno; ++ } ++ if (!failed.fn && errdes != STDERR_FILE_NO) ++ { ++ if (dup2 (errdes, STDERR_FILE_NO) < 0) ++ failed.fn = "dup2", failed.err = errno; ++ else if (close (errdes) < 0) ++ failed.fn = "close", failed.err = errno; ++ } ++ if (!failed.fn && toclose >= 0) ++ { ++ if (close (toclose) < 0) ++ failed.fn = "close", failed.err = errno; ++ } ++ if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0) ++ { ++ if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) ++ failed.fn = "dup2", failed.err = errno; ++ } ++ if (!failed.fn) ++ { ++ if (env) ++ /* NOTE: In a standard vfork implementation this clobbers ++ the parent's copy of environ "too" (in reality there's ++ only one copy). This is ok as we restore it below. */ ++ environ = (char**) env; ++ if ((flags & PEX_SEARCH) != 0) ++ { ++ execvp (executable, to_ptr32 (argv)); ++ failed.fn = "execvp", failed.err = errno; ++ } ++ else ++ { ++ execv (executable, to_ptr32 (argv)); ++ failed.fn = "execv", failed.err = errno; ++ } ++ } ++ ++ /* Something failed, report an error. We don't use stdio ++ routines, because we might be here due to a vfork call. */ ++ ssize_t retval = 0; ++ ++ if (!do_pipe ++ || write (pipes[1], &failed, sizeof (failed)) != sizeof (failed)) ++ { ++ /* The parent will not see our scream above, so write to ++ stdout. */ ++#define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s))) ++ writeerr (obj->pname); ++ writeerr (": error trying to exec '"); ++ writeerr (executable); ++ writeerr ("': "); ++ writeerr (failed.fn); ++ writeerr (": "); ++ writeerr (xstrerror (failed.err)); ++ writeerr ("\n"); ++#undef writeerr ++ } + ++ /* Exit with -2 if the error output failed, too. */ ++ _exit (retval < 0 ? -2 : -1); ++ } + /* NOTREACHED */ + return (pid_t) -1; + + default: + /* Parent process. */ ++ { ++ /* Restore environ. Note that the parent either doesn't run ++ until the child execs/exits (standard vfork behaviour), or ++ if it does run then vfork is behaving more like fork. In ++ either case we needn't worry about clobbering the child's ++ copy of environ. */ ++ environ = save_environ; ++ ++ struct fn_err failed; ++ failed.fn = NULL; ++ if (do_pipe) ++ { ++ close (pipes[1]); ++ ssize_t len = read (pipes[0], &failed, sizeof (failed)); ++ if (len < 0) ++ failed.fn = NULL; ++ close (pipes[0]); ++ } + +- /* Restore environ. +- Note that the parent either doesn't run until the child execs/exits +- (standard vfork behaviour), or if it does run then vfork is behaving +- more like fork. In either case we needn't worry about clobbering +- the child's copy of environ. */ +- environ = save_environ; +- +- if (in != STDIN_FILE_NO) +- { ++ if (!failed.fn && in != STDIN_FILE_NO) + if (close (in) < 0) +- { +- *err = errno; +- *errmsg = "close"; +- return (pid_t) -1; +- } +- } +- if (out != STDOUT_FILE_NO) +- { ++ failed.fn = "close", failed.err = errno; ++ if (!failed.fn && out != STDOUT_FILE_NO) + if (close (out) < 0) +- { +- *err = errno; +- *errmsg = "close"; +- return (pid_t) -1; +- } +- } +- if (errdes != STDERR_FILE_NO) +- { ++ failed.fn = "close", failed.err = errno; ++ if (!failed.fn && errdes != STDERR_FILE_NO) + if (close (errdes) < 0) +- { +- *err = errno; +- *errmsg = "close"; +- return (pid_t) -1; +- } +- } ++ failed.fn = "close", failed.err = errno; + ++ if (failed.fn) ++ { ++ *err = failed.err; ++ *errmsg = failed.fn; ++ return (pid_t) -1; ++ } ++ } + return pid; + } + } diff --git a/SOURCES/binutils-CVE-2018-12699-part3-PR22957.patch b/SOURCES/binutils-CVE-2018-12699-part3-PR22957.patch new file mode 100644 index 0000000..5fe11be --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part3-PR22957.patch @@ -0,0 +1,13 @@ +diff -rup binutils.orig.2/binutils/stabs.c binutils-2.30/binutils/stabs.c +--- binutils.orig.2/binutils/stabs.c 2024-10-29 14:21:27.910212960 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-10-29 14:22:14.304336367 +0000 +@@ -3364,6 +3363,9 @@ pop_bincl (struct stab_handle *info) + return info->main_filename; + info->bincl_stack = o->next_stack; + ++ if (o->file >= info->files) ++ return info->main_filename; ++ + o->file_types = info->file_types[o->file]; + + if (info->bincl_stack == NULL) diff --git a/SOURCES/binutils-CVE-2018-12699-part4-PR16615.patch b/SOURCES/binutils-CVE-2018-12699-part4-PR16615.patch new file mode 100644 index 0000000..124f772 --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part4-PR16615.patch @@ -0,0 +1,4809 @@ +diff -rup binutils.orig.3/binutils/cxxfilt.c binutils-2.30/binutils/cxxfilt.c +--- binutils.orig.3/binutils/cxxfilt.c 2024-10-29 14:24:58.307808434 +0000 ++++ binutils-2.30/binutils/cxxfilt.c 2024-10-29 14:30:41.737838327 +0000 +@@ -165,11 +165,6 @@ standard_symbol_characters (void) + non-digit character. + + So have fun. */ +-static const char * +-hp_symbol_characters (void) +-{ +- return "_$.<>#,*&[]:(){}"; +-} + + extern int main (int, char **); + +@@ -245,20 +240,13 @@ main (int argc, char **argv) + + switch (current_demangling_style) + { +- case gnu_demangling: +- case lucid_demangling: +- case arm_demangling: ++ case auto_demangling: ++ case gnu_v3_demangling: + case java_demangling: +- case edg_demangling: + case gnat_demangling: +- case gnu_v3_demangling: + case dlang_demangling: + case rust_demangling: +- case auto_demangling: +- valid_symbols = standard_symbol_characters (); +- break; +- case hp_demangling: +- valid_symbols = hp_symbol_characters (); ++ valid_symbols = standard_symbol_characters (); + break; + default: + /* Folks should explicitly indicate the appropriate alphabet for +diff -rup binutils.orig.3/binutils/stabs.c binutils-2.30/binutils/stabs.c +--- binutils.orig.3/binutils/stabs.c 2024-10-29 14:24:58.307808434 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-10-29 14:29:55.666700166 +0000 +@@ -3065,18 +3065,8 @@ parse_stab_argtypes (void *dhandle, stru + && fieldname[1] == 'p' + && (fieldname[2] == '$' || fieldname[2] == '.')) + { +- const char *opname; +- +- opname = cplus_mangle_opname (fieldname + 3, 0); +- if (opname == NULL) +- { +- fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname); +- return DEBUG_TYPE_NULL; +- } +- mangled_name_len += strlen (opname); +- physname = (char *) xmalloc (mangled_name_len); +- strncpy (physname, fieldname, 3); +- strcpy (physname + 3, opname); ++ /* Opname selection is no longer supported by libiberty's demangler. */ ++ return DEBUG_TYPE_NULL; + } + else + { +diff -rup binutils.orig.3/include/demangle.h binutils-2.30/include/demangle.h +--- binutils.orig.3/include/demangle.h 2024-10-29 14:24:58.588809275 +0000 ++++ binutils-2.30/include/demangle.h 2024-10-29 14:25:27.754896740 +0000 +@@ -53,20 +53,13 @@ extern "C" { + */ + + #define DMGL_AUTO (1 << 8) +-#define DMGL_GNU (1 << 9) +-#define DMGL_LUCID (1 << 10) +-#define DMGL_ARM (1 << 11) +-#define DMGL_HP (1 << 12) /* For the HP aCC compiler; +- same as ARM except for +- template arguments, etc. */ +-#define DMGL_EDG (1 << 13) + #define DMGL_GNU_V3 (1 << 14) + #define DMGL_GNAT (1 << 15) + #define DMGL_DLANG (1 << 16) + #define DMGL_RUST (1 << 17) /* Rust wraps GNU_V3 style mangling. */ + + /* If none of these are set, use 'current_demangling_style' as the default. */ +-#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) ++#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) + + /* Disable a limit on the depth of recursion in mangled strings. + Note if this limit is disabled then stack exhaustion is possible when +@@ -92,11 +85,6 @@ extern enum demangling_styles + no_demangling = -1, + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, +- gnu_demangling = DMGL_GNU, +- lucid_demangling = DMGL_LUCID, +- arm_demangling = DMGL_ARM, +- hp_demangling = DMGL_HP, +- edg_demangling = DMGL_EDG, + gnu_v3_demangling = DMGL_GNU_V3, + java_demangling = DMGL_JAVA, + gnat_demangling = DMGL_GNAT, +@@ -108,11 +96,6 @@ extern enum demangling_styles + + #define NO_DEMANGLING_STYLE_STRING "none" + #define AUTO_DEMANGLING_STYLE_STRING "auto" +-#define GNU_DEMANGLING_STYLE_STRING "gnu" +-#define LUCID_DEMANGLING_STYLE_STRING "lucid" +-#define ARM_DEMANGLING_STYLE_STRING "arm" +-#define HP_DEMANGLING_STYLE_STRING "hp" +-#define EDG_DEMANGLING_STYLE_STRING "edg" + #define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3" + #define JAVA_DEMANGLING_STYLE_STRING "java" + #define GNAT_DEMANGLING_STYLE_STRING "gnat" +@@ -123,11 +106,6 @@ extern enum demangling_styles + + #define CURRENT_DEMANGLING_STYLE current_demangling_style + #define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +-#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +-#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +-#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +-#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +-#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) + #define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3) + #define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA) + #define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) +@@ -147,17 +125,8 @@ extern const struct demangler_engine + extern char * + cplus_demangle (const char *mangled, int options); + +-extern int +-cplus_demangle_opname (const char *opname, char *result, int options); +- +-extern const char * +-cplus_mangle_opname (const char *opname, int options); +- + /* Note: This sets global state. FIXME if you care about multi-threading. */ + +-extern void +-set_cplus_marker_for_demangling (int ch); +- + extern enum demangling_styles + cplus_demangle_set_style (enum demangling_styles style); + +diff -rup binutils.orig.3/libiberty/cplus-dem.c binutils-2.30/libiberty/cplus-dem.c +--- binutils.orig.3/libiberty/cplus-dem.c 2024-10-29 14:24:58.571809224 +0000 ++++ binutils-2.30/libiberty/cplus-dem.c 2024-10-29 14:25:33.816914919 +0000 +@@ -29,12 +29,6 @@ License along with libiberty; see the fi + not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +-/* This file exports two functions; cplus_mangle_opname and cplus_demangle. +- +- This file imports xmalloc and xrealloc, which are like malloc and +- realloc except that they generate a fatal error if there is no +- available memory. */ +- + /* This file lives in both GCC and libiberty. When making changes, please + try not to break either. */ + +@@ -44,9 +38,7 @@ Boston, MA 02110-1301, USA. */ + + #include "safe-ctype.h" + +-#include + #include +-#include + + #ifdef HAVE_STDLIB_H + #include +@@ -55,205 +47,14 @@ void * malloc (); + void * realloc (); + #endif + +-#ifdef HAVE_LIMITS_H +-#include +-#endif +-#ifndef INT_MAX +-# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */ +-#endif +- + #include + #undef CURRENT_DEMANGLING_STYLE +-#define CURRENT_DEMANGLING_STYLE work->options ++#define CURRENT_DEMANGLING_STYLE options + + #include "libiberty.h" + +-#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) +- +-/* A value at least one greater than the maximum number of characters +- that will be output when using the `%d' format with `printf'. */ +-#define INTBUF_SIZE 32 +- +-extern void fancy_abort (void) ATTRIBUTE_NORETURN; +- +-/* In order to allow a single demangler executable to demangle strings +- using various common values of CPLUS_MARKER, as well as any specific +- one set at compile time, we maintain a string containing all the +- commonly used ones, and check to see if the marker we are looking for +- is in that string. CPLUS_MARKER is usually '$' on systems where the +- assembler can deal with that. Where the assembler can't, it's usually +- '.' (but on many systems '.' is used for other things). We put the +- current defined CPLUS_MARKER first (which defaults to '$'), followed +- by the next most common value, followed by an explicit '$' in case +- the value of CPLUS_MARKER is not '$'. +- +- We could avoid this if we could just get g++ to tell us what the actual +- cplus marker character is as part of the debug information, perhaps by +- ensuring that it is the character that terminates the gcc_compiled +- marker symbol (FIXME). */ +- +-#if !defined (CPLUS_MARKER) +-#define CPLUS_MARKER '$' +-#endif +- + enum demangling_styles current_demangling_style = auto_demangling; + +-static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; +- +-static char char_str[2] = { '\000', '\000' }; +- +-void +-set_cplus_marker_for_demangling (int ch) +-{ +- cplus_markers[0] = ch; +-} +- +-typedef struct string /* Beware: these aren't required to be */ +-{ /* '\0' terminated. */ +- char *b; /* pointer to start of string */ +- char *p; /* pointer after last character */ +- char *e; /* pointer after end of allocated space */ +-} string; +- +-/* Stuff that is shared between sub-routines. +- Using a shared structure allows cplus_demangle to be reentrant. */ +- +-struct work_stuff +-{ +- int options; +- char **typevec; +- char **ktypevec; +- char **btypevec; +- int numk; +- int numb; +- int ksize; +- int bsize; +- int ntypes; +- int typevec_size; +- int constructor; +- int destructor; +- int static_type; /* A static member function */ +- int temp_start; /* index in demangled to start of template args */ +- int type_quals; /* The type qualifiers. */ +- int dllimported; /* Symbol imported from a PE DLL */ +- char **tmpl_argvec; /* Template function arguments. */ +- int ntmpl_args; /* The number of template function arguments. */ +- int forgetting_types; /* Nonzero if we are not remembering the types +- we see. */ +- string* previous_argument; /* The last function argument demangled. */ +- int nrepeats; /* The number of times to repeat the previous +- argument. */ +- int *proctypevec; /* Indices of currently processed remembered typevecs. */ +- int proctypevec_size; +- int nproctypes; +- unsigned int recursion_level; +-}; +- +-#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +-#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) +- +-static const struct optable +-{ +- const char *const in; +- const char *const out; +- const int flags; +-} optable[] = { +- {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ +- {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ +- {"new", " new", 0}, /* old (1.91, and 1.x) */ +- {"delete", " delete", 0}, /* old (1.91, and 1.x) */ +- {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ +- {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ +- {"as", "=", DMGL_ANSI}, /* ansi */ +- {"ne", "!=", DMGL_ANSI}, /* old, ansi */ +- {"eq", "==", DMGL_ANSI}, /* old, ansi */ +- {"ge", ">=", DMGL_ANSI}, /* old, ansi */ +- {"gt", ">", DMGL_ANSI}, /* old, ansi */ +- {"le", "<=", DMGL_ANSI}, /* old, ansi */ +- {"lt", "<", DMGL_ANSI}, /* old, ansi */ +- {"plus", "+", 0}, /* old */ +- {"pl", "+", DMGL_ANSI}, /* ansi */ +- {"apl", "+=", DMGL_ANSI}, /* ansi */ +- {"minus", "-", 0}, /* old */ +- {"mi", "-", DMGL_ANSI}, /* ansi */ +- {"ami", "-=", DMGL_ANSI}, /* ansi */ +- {"mult", "*", 0}, /* old */ +- {"ml", "*", DMGL_ANSI}, /* ansi */ +- {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ +- {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ +- {"convert", "+", 0}, /* old (unary +) */ +- {"negate", "-", 0}, /* old (unary -) */ +- {"trunc_mod", "%", 0}, /* old */ +- {"md", "%", DMGL_ANSI}, /* ansi */ +- {"amd", "%=", DMGL_ANSI}, /* ansi */ +- {"trunc_div", "/", 0}, /* old */ +- {"dv", "/", DMGL_ANSI}, /* ansi */ +- {"adv", "/=", DMGL_ANSI}, /* ansi */ +- {"truth_andif", "&&", 0}, /* old */ +- {"aa", "&&", DMGL_ANSI}, /* ansi */ +- {"truth_orif", "||", 0}, /* old */ +- {"oo", "||", DMGL_ANSI}, /* ansi */ +- {"truth_not", "!", 0}, /* old */ +- {"nt", "!", DMGL_ANSI}, /* ansi */ +- {"postincrement","++", 0}, /* old */ +- {"pp", "++", DMGL_ANSI}, /* ansi */ +- {"postdecrement","--", 0}, /* old */ +- {"mm", "--", DMGL_ANSI}, /* ansi */ +- {"bit_ior", "|", 0}, /* old */ +- {"or", "|", DMGL_ANSI}, /* ansi */ +- {"aor", "|=", DMGL_ANSI}, /* ansi */ +- {"bit_xor", "^", 0}, /* old */ +- {"er", "^", DMGL_ANSI}, /* ansi */ +- {"aer", "^=", DMGL_ANSI}, /* ansi */ +- {"bit_and", "&", 0}, /* old */ +- {"ad", "&", DMGL_ANSI}, /* ansi */ +- {"aad", "&=", DMGL_ANSI}, /* ansi */ +- {"bit_not", "~", 0}, /* old */ +- {"co", "~", DMGL_ANSI}, /* ansi */ +- {"call", "()", 0}, /* old */ +- {"cl", "()", DMGL_ANSI}, /* ansi */ +- {"alshift", "<<", 0}, /* old */ +- {"ls", "<<", DMGL_ANSI}, /* ansi */ +- {"als", "<<=", DMGL_ANSI}, /* ansi */ +- {"arshift", ">>", 0}, /* old */ +- {"rs", ">>", DMGL_ANSI}, /* ansi */ +- {"ars", ">>=", DMGL_ANSI}, /* ansi */ +- {"component", "->", 0}, /* old */ +- {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ +- {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ +- {"indirect", "*", 0}, /* old */ +- {"method_call", "->()", 0}, /* old */ +- {"addr", "&", 0}, /* old (unary &) */ +- {"array", "[]", 0}, /* old */ +- {"vc", "[]", DMGL_ANSI}, /* ansi */ +- {"compound", ", ", 0}, /* old */ +- {"cm", ", ", DMGL_ANSI}, /* ansi */ +- {"cond", "?:", 0}, /* old */ +- {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ +- {"max", ">?", 0}, /* old */ +- {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ +- {"min", "*", DMGL_ANSI}, /* ansi */ +- {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ +-}; +- +-/* These values are used to indicate the various type varieties. +- They are all non-zero so that they can be used as `success' +- values. */ +-typedef enum type_kind_t +-{ +- tk_none, +- tk_pointer, +- tk_reference, +- tk_rvalue_reference, +- tk_integral, +- tk_bool, +- tk_char, +- tk_real +-} type_kind_t; +- + const struct demangler_engine libiberty_demanglers[] = + { + { +@@ -269,39 +70,9 @@ const struct demangler_engine libiberty_ + } + , + { +- GNU_DEMANGLING_STYLE_STRING, +- gnu_demangling, +- "GNU (g++) style demangling" +- } +- , +- { +- LUCID_DEMANGLING_STYLE_STRING, +- lucid_demangling, +- "Lucid (lcc) style demangling" +- } +- , +- { +- ARM_DEMANGLING_STYLE_STRING, +- arm_demangling, +- "ARM style demangling" +- } +- , +- { +- HP_DEMANGLING_STYLE_STRING, +- hp_demangling, +- "HP (aCC) style demangling" +- } +- , +- { +- EDG_DEMANGLING_STYLE_STRING, +- edg_demangling, +- "EDG style demangling" +- } +- , +- { + GNU_V3_DEMANGLING_STYLE_STRING, + gnu_v3_demangling, +- "GNU (g++) V3 ABI-style demangling" ++ "GNU (g++) V3 (Itanium C++ ABI) style demangling" + } + , + { +@@ -333,474 +104,6 @@ const struct demangler_engine libiberty_ + } + }; + +-#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +-#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ +- string_append(str, " ");} +-#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) +- +-/* The scope separator appropriate for the language being demangled. */ +- +-#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") +- +-#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +-#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ +- +-/* Prototypes for local functions */ +- +-static void delete_work_stuff (struct work_stuff *); +- +-static void delete_non_B_K_work_stuff (struct work_stuff *); +- +-static char *mop_up (struct work_stuff *, string *, int); +- +-static void squangle_mop_up (struct work_stuff *); +- +-static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *); +- +-#if 0 +-static int +-demangle_method_args (struct work_stuff *, const char **, string *); +-#endif +- +-static char * +-internal_cplus_demangle (struct work_stuff *, const char *); +- +-static int +-demangle_template_template_parm (struct work_stuff *work, +- const char **, string *); +- +-static int +-demangle_template (struct work_stuff *work, const char **, string *, +- string *, int, int); +- +-static int +-arm_pt (struct work_stuff *, const char *, int, const char **, +- const char **); +- +-static int +-demangle_class_name (struct work_stuff *, const char **, string *); +- +-static int +-demangle_qualified (struct work_stuff *, const char **, string *, +- int, int); +- +-static int demangle_class (struct work_stuff *, const char **, string *); +- +-static int demangle_fund_type (struct work_stuff *, const char **, string *); +- +-static int demangle_signature (struct work_stuff *, const char **, string *); +- +-static int demangle_prefix (struct work_stuff *, const char **, string *); +- +-static int gnu_special (struct work_stuff *, const char **, string *); +- +-static int arm_special (const char **, string *); +- +-static void string_need (string *, int); +- +-static void string_delete (string *); +- +-static void +-string_init (string *); +- +-static void string_clear (string *); +- +-#if 0 +-static int string_empty (string *); +-#endif +- +-static void string_append (string *, const char *); +- +-static void string_appends (string *, string *); +- +-static void string_appendn (string *, const char *, int); +- +-static void string_prepend (string *, const char *); +- +-static void string_prependn (string *, const char *, int); +- +-static void string_append_template_idx (string *, int); +- +-static int get_count (const char **, int *); +- +-static int consume_count (const char **); +- +-static int consume_count_with_underscores (const char**); +- +-static int demangle_args (struct work_stuff *, const char **, string *); +- +-static int demangle_nested_args (struct work_stuff*, const char**, string*); +- +-static int do_type (struct work_stuff *, const char **, string *); +- +-static int do_arg (struct work_stuff *, const char **, string *); +- +-static int +-demangle_function_name (struct work_stuff *, const char **, string *, +- const char *); +- +-static int +-iterate_demangle_function (struct work_stuff *, +- const char **, string *, const char *); +- +-static void remember_type (struct work_stuff *, const char *, int); +- +-static void push_processed_type (struct work_stuff *, int); +- +-static void pop_processed_type (struct work_stuff *); +- +-static void remember_Btype (struct work_stuff *, const char *, int, int); +- +-static int register_Btype (struct work_stuff *); +- +-static void remember_Ktype (struct work_stuff *, const char *, int); +- +-static void forget_types (struct work_stuff *); +- +-static void forget_B_and_K_types (struct work_stuff *); +- +-static void string_prepends (string *, string *); +- +-static int +-demangle_template_value_parm (struct work_stuff*, const char**, +- string*, type_kind_t); +- +-static int +-do_hpacc_template_const_value (struct work_stuff *, const char **, string *); +- +-static int +-do_hpacc_template_literal (struct work_stuff *, const char **, string *); +- +-static int snarf_numeric_literal (const char **, string *); +- +-/* There is a TYPE_QUAL value for each type qualifier. They can be +- combined by bitwise-or to form the complete set of qualifiers for a +- type. */ +- +-#define TYPE_UNQUALIFIED 0x0 +-#define TYPE_QUAL_CONST 0x1 +-#define TYPE_QUAL_VOLATILE 0x2 +-#define TYPE_QUAL_RESTRICT 0x4 +- +-static int code_for_qualifier (int); +- +-static const char* qualifier_string (int); +- +-static const char* demangle_qualifier (int); +- +-static int demangle_expression (struct work_stuff *, const char **, string *, +- type_kind_t); +- +-static int +-demangle_integral_value (struct work_stuff *, const char **, string *); +- +-static int +-demangle_real_value (struct work_stuff *, const char **, string *); +- +-static void +-demangle_arm_hp_template (struct work_stuff *, const char **, int, string *); +- +-static void +-recursively_demangle (struct work_stuff *, const char **, string *, int); +- +-/* Translate count to integer, consuming tokens in the process. +- Conversion terminates on the first non-digit character. +- +- Trying to consume something that isn't a count results in no +- consumption of input and a return of -1. +- +- Overflow consumes the rest of the digits, and returns -1. */ +- +-static int +-consume_count (const char **type) +-{ +- int count = 0; +- +- if (! ISDIGIT ((unsigned char)**type)) +- return -1; +- +- while (ISDIGIT ((unsigned char)**type)) +- { +- const int digit = **type - '0'; +- /* Check for overflow. */ +- if (count > ((INT_MAX - digit) / 10)) +- { +- while (ISDIGIT ((unsigned char) **type)) +- (*type)++; +- return -1; +- } +- +- count *= 10; +- count += digit; +- (*type)++; +- } +- +- if (count < 0) +- count = -1; +- +- return (count); +-} +- +- +-/* Like consume_count, but for counts that are preceded and followed +- by '_' if they are greater than 10. Also, -1 is returned for +- failure, since 0 can be a valid value. */ +- +-static int +-consume_count_with_underscores (const char **mangled) +-{ +- int idx; +- +- if (**mangled == '_') +- { +- (*mangled)++; +- if (!ISDIGIT ((unsigned char)**mangled)) +- return -1; +- +- idx = consume_count (mangled); +- if (**mangled != '_') +- /* The trailing underscore was missing. */ +- return -1; +- +- (*mangled)++; +- } +- else +- { +- if (**mangled < '0' || **mangled > '9') +- return -1; +- +- idx = **mangled - '0'; +- (*mangled)++; +- } +- +- return idx; +-} +- +-/* C is the code for a type-qualifier. Return the TYPE_QUAL +- corresponding to this qualifier. */ +- +-static int +-code_for_qualifier (int c) +-{ +- switch (c) +- { +- case 'C': +- return TYPE_QUAL_CONST; +- +- case 'V': +- return TYPE_QUAL_VOLATILE; +- +- case 'u': +- return TYPE_QUAL_RESTRICT; +- +- default: +- break; +- } +- +- /* C was an invalid qualifier. */ +- abort (); +-} +- +-/* Return the string corresponding to the qualifiers given by +- TYPE_QUALS. */ +- +-static const char* +-qualifier_string (int type_quals) +-{ +- switch (type_quals) +- { +- case TYPE_UNQUALIFIED: +- return ""; +- +- case TYPE_QUAL_CONST: +- return "const"; +- +- case TYPE_QUAL_VOLATILE: +- return "volatile"; +- +- case TYPE_QUAL_RESTRICT: +- return "__restrict"; +- +- case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: +- return "const volatile"; +- +- case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: +- return "const __restrict"; +- +- case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: +- return "volatile __restrict"; +- +- case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: +- return "const volatile __restrict"; +- +- default: +- break; +- } +- +- /* TYPE_QUALS was an invalid qualifier set. */ +- abort (); +-} +- +-/* C is the code for a type-qualifier. Return the string +- corresponding to this qualifier. This function should only be +- called with a valid qualifier code. */ +- +-static const char* +-demangle_qualifier (int c) +-{ +- return qualifier_string (code_for_qualifier (c)); +-} +- +-int +-cplus_demangle_opname (const char *opname, char *result, int options) +-{ +- int len, len1, ret; +- string type; +- struct work_stuff work[1]; +- const char *tem; +- +- len = strlen(opname); +- result[0] = '\0'; +- ret = 0; +- memset ((char *) work, 0, sizeof (work)); +- work->options = options; +- +- if (opname[0] == '_' && opname[1] == '_' +- && opname[2] == 'o' && opname[3] == 'p') +- { +- /* ANSI. */ +- /* type conversion operator. */ +- tem = opname + 4; +- if (do_type (work, &tem, &type)) +- { +- strcat (result, "operator "); +- strncat (result, type.b, type.p - type.b); +- string_delete (&type); +- ret = 1; +- } +- } +- else if (opname[0] == '_' && opname[1] == '_' +- && ISLOWER((unsigned char)opname[2]) +- && ISLOWER((unsigned char)opname[3])) +- { +- if (opname[4] == '\0') +- { +- /* Operator. */ +- size_t i; +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- if (strlen (optable[i].in) == 2 +- && memcmp (optable[i].in, opname + 2, 2) == 0) +- { +- strcat (result, "operator"); +- strcat (result, optable[i].out); +- ret = 1; +- break; +- } +- } +- } +- else +- { +- if (opname[2] == 'a' && opname[5] == '\0') +- { +- /* Assignment. */ +- size_t i; +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- if (strlen (optable[i].in) == 3 +- && memcmp (optable[i].in, opname + 2, 3) == 0) +- { +- strcat (result, "operator"); +- strcat (result, optable[i].out); +- ret = 1; +- break; +- } +- } +- } +- } +- } +- else if (len >= 3 +- && opname[0] == 'o' +- && opname[1] == 'p' +- && strchr (cplus_markers, opname[2]) != NULL) +- { +- /* see if it's an assignment expression */ +- if (len >= 10 /* op$assign_ */ +- && memcmp (opname + 3, "assign_", 7) == 0) +- { +- size_t i; +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- len1 = len - 10; +- if ((int) strlen (optable[i].in) == len1 +- && memcmp (optable[i].in, opname + 10, len1) == 0) +- { +- strcat (result, "operator"); +- strcat (result, optable[i].out); +- strcat (result, "="); +- ret = 1; +- break; +- } +- } +- } +- else +- { +- size_t i; +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- len1 = len - 3; +- if ((int) strlen (optable[i].in) == len1 +- && memcmp (optable[i].in, opname + 3, len1) == 0) +- { +- strcat (result, "operator"); +- strcat (result, optable[i].out); +- ret = 1; +- break; +- } +- } +- } +- } +- else if (len >= 5 && memcmp (opname, "type", 4) == 0 +- && strchr (cplus_markers, opname[4]) != NULL) +- { +- /* type conversion operator */ +- tem = opname + 5; +- if (do_type (work, &tem, &type)) +- { +- strcat (result, "operator "); +- strncat (result, type.b, type.p - type.b); +- string_delete (&type); +- ret = 1; +- } +- } +- squangle_mop_up (work); +- return ret; +- +-} +- +-/* Takes operator name as e.g. "++" and returns mangled +- operator name (e.g. "postincrement_expr"), or NULL if not found. +- +- If OPTIONS & DMGL_ANSI == 1, return the ANSI name; +- if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ +- +-const char * +-cplus_mangle_opname (const char *opname, int options) +-{ +- size_t i; +- int len; +- +- len = strlen (opname); +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- if ((int) strlen (optable[i].out) == len +- && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) +- && memcmp (optable[i].out, opname, len) == 0) +- return optable[i].in; +- } +- return (0); +-} +- + /* Add a routine to set the demangling style to be sure it is valid and + allow for any demangler initialization that maybe necessary. */ + +@@ -841,22 +144,6 @@ cplus_demangle_name_to_style (const char + It is the caller's responsibility to free the string which + is returned. + +- The OPTIONS arg may contain one or more of the following bits: +- +- DMGL_ANSI ANSI qualifiers such as `const' and `void' are +- included. +- DMGL_PARAMS Function parameters are included. +- +- For example, +- +- cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" +- cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" +- cplus_demangle ("foo__1Ai", 0) => "A::foo" +- +- cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" +- cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" +- cplus_demangle ("foo__1Afe", 0) => "A::foo" +- + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + MANGLED. */ +@@ -865,20 +152,17 @@ char * + cplus_demangle (const char *mangled, int options) + { + char *ret; +- struct work_stuff work[1]; + + if (current_demangling_style == no_demangling) + return xstrdup (mangled); + +- memset ((char *) work, 0, sizeof (work)); +- work->options = options; +- if ((work->options & DMGL_STYLE_MASK) == 0) +- work->options |= (int) current_demangling_style & DMGL_STYLE_MASK; ++ if ((options & DMGL_STYLE_MASK) == 0) ++ options |= (int) current_demangling_style & DMGL_STYLE_MASK; + + /* The V3 ABI demangling is implemented elsewhere. */ + if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING) + { +- ret = cplus_demangle_v3 (mangled, work->options); ++ ret = cplus_demangle_v3 (mangled, options); + if (GNU_V3_DEMANGLING) + return ret; + +@@ -916,8 +200,6 @@ cplus_demangle (const char *mangled, int + return ret; + } + +- ret = internal_cplus_demangle (work, mangled); +- squangle_mop_up (work); + return (ret); + } + +@@ -1206,3861 +488,3 @@ ada_demangle (const char *mangled, int o + + return demangled; + } +- +-/* This function performs most of what cplus_demangle use to do, but +- to be able to demangle a name with a B, K or n code, we need to +- have a longer term memory of what types have been seen. The original +- now initializes and cleans up the squangle code info, while internal +- calls go directly to this routine to avoid resetting that info. */ +- +-static char * +-internal_cplus_demangle (struct work_stuff *work, const char *mangled) +-{ +- +- string decl; +- int success = 0; +- char *demangled = NULL; +- int s1, s2, s3, s4; +- s1 = work->constructor; +- s2 = work->destructor; +- s3 = work->static_type; +- s4 = work->type_quals; +- work->constructor = work->destructor = 0; +- work->type_quals = TYPE_UNQUALIFIED; +- work->dllimported = 0; +- +- if ((mangled != NULL) && (*mangled != '\0')) +- { +- string_init (&decl); +- +- /* First check to see if gnu style demangling is active and if the +- string to be demangled contains a CPLUS_MARKER. If so, attempt to +- recognize one of the gnu special forms rather than looking for a +- standard prefix. In particular, don't worry about whether there +- is a "__" string in the mangled string. Consider "_$_5__foo" for +- example. */ +- +- if ((AUTO_DEMANGLING || GNU_DEMANGLING)) +- { +- success = gnu_special (work, &mangled, &decl); +- if (!success) +- { +- delete_work_stuff (work); +- string_delete (&decl); +- } +- } +- if (!success) +- { +- success = demangle_prefix (work, &mangled, &decl); +- } +- if (success && (*mangled != '\0')) +- { +- success = demangle_signature (work, &mangled, &decl); +- } +- if (work->constructor == 2) +- { +- string_prepend (&decl, "global constructors keyed to "); +- work->constructor = 0; +- } +- else if (work->destructor == 2) +- { +- string_prepend (&decl, "global destructors keyed to "); +- work->destructor = 0; +- } +- else if (work->dllimported == 1) +- { +- string_prepend (&decl, "import stub for "); +- work->dllimported = 0; +- } +- demangled = mop_up (work, &decl, success); +- } +- work->constructor = s1; +- work->destructor = s2; +- work->static_type = s3; +- work->type_quals = s4; +- return demangled; +-} +- +- +-/* Clear out and squangling related storage */ +-static void +-squangle_mop_up (struct work_stuff *work) +-{ +- /* clean up the B and K type mangling types. */ +- forget_B_and_K_types (work); +- if (work -> btypevec != NULL) +- { +- free ((char *) work -> btypevec); +- work->btypevec = NULL; +- work->bsize = 0; +- work->numb = 0; +- } +- if (work -> ktypevec != NULL) +- { +- free ((char *) work -> ktypevec); +- work->ktypevec = NULL; +- work->ksize = 0; +- work->numk = 0; +- } +-} +- +- +-/* Copy the work state and storage. */ +- +-static void +-work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from) +-{ +- int i; +- +- delete_work_stuff (to); +- +- /* Shallow-copy scalars. */ +- memcpy (to, from, sizeof (*to)); +- +- /* Deep-copy dynamic storage. */ +- if (from->typevec_size) +- to->typevec = XNEWVEC (char *, from->typevec_size); +- +- for (i = 0; i < from->ntypes; i++) +- { +- int len = strlen (from->typevec[i]) + 1; +- +- to->typevec[i] = XNEWVEC (char, len); +- memcpy (to->typevec[i], from->typevec[i], len); +- } +- +- if (from->ksize) +- to->ktypevec = XNEWVEC (char *, from->ksize); +- +- for (i = 0; i < from->numk; i++) +- { +- int len; +- +- if (from->ktypevec[i] == NULL) +- { +- to->ktypevec[i] = NULL; +- continue; +- } +- +- len = strlen (from->ktypevec[i]) + 1; +- to->ktypevec[i] = XNEWVEC (char, len); +- memcpy (to->ktypevec[i], from->ktypevec[i], len); +- } +- +- if (from->bsize) +- to->btypevec = XNEWVEC (char *, from->bsize); +- +- for (i = 0; i < from->numb; i++) +- { +- int len; +- +- if (from->btypevec[i] == NULL) +- { +- to->btypevec[i] = NULL; +- continue; +- } +- +- len = strlen (from->btypevec[i]) + 1; +- to->btypevec[i] = XNEWVEC (char , len); +- memcpy (to->btypevec[i], from->btypevec[i], len); +- } +- +- if (from->proctypevec) +- to->proctypevec = +- XDUPVEC (int, from->proctypevec, from->proctypevec_size); +- +- if (from->ntmpl_args) +- to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args); +- +- for (i = 0; i < from->ntmpl_args; i++) +- { +- int len = strlen (from->tmpl_argvec[i]) + 1; +- +- to->tmpl_argvec[i] = XNEWVEC (char, len); +- memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len); +- } +- +- if (from->previous_argument) +- { +- to->previous_argument = XNEW (string); +- string_init (to->previous_argument); +- string_appends (to->previous_argument, from->previous_argument); +- } +-} +- +- +-/* Delete dynamic stuff in work_stuff that is not to be re-used. */ +- +-static void +-delete_non_B_K_work_stuff (struct work_stuff *work) +-{ +- /* Discard the remembered types, if any. */ +- +- forget_types (work); +- if (work->typevec != NULL) +- { +- free ((char *) work->typevec); +- work->typevec = NULL; +- work->typevec_size = 0; +- } +- if (work->proctypevec != NULL) +- { +- free (work->proctypevec); +- work->proctypevec = NULL; +- work->proctypevec_size = 0; +- } +- if (work->tmpl_argvec) +- { +- int i; +- +- for (i = 0; i < work->ntmpl_args; i++) +- free ((char*) work->tmpl_argvec[i]); +- +- free ((char*) work->tmpl_argvec); +- work->tmpl_argvec = NULL; +- work->ntmpl_args = 0; +- } +- if (work->previous_argument) +- { +- string_delete (work->previous_argument); +- free ((char*) work->previous_argument); +- work->previous_argument = NULL; +- } +-} +- +- +-/* Delete all dynamic storage in work_stuff. */ +-static void +-delete_work_stuff (struct work_stuff *work) +-{ +- delete_non_B_K_work_stuff (work); +- squangle_mop_up (work); +-} +- +- +-/* Clear out any mangled storage */ +- +-static char * +-mop_up (struct work_stuff *work, string *declp, int success) +-{ +- char *demangled = NULL; +- +- delete_non_B_K_work_stuff (work); +- +- /* If demangling was successful, ensure that the demangled string is null +- terminated and return it. Otherwise, free the demangling decl. */ +- +- if (!success) +- { +- string_delete (declp); +- } +- else +- { +- string_appendn (declp, "", 1); +- demangled = declp->b; +- } +- return (demangled); +-} +- +-/* +- +-LOCAL FUNCTION +- +- demangle_signature -- demangle the signature part of a mangled name +- +-SYNOPSIS +- +- static int +- demangle_signature (struct work_stuff *work, const char **mangled, +- string *declp); +- +-DESCRIPTION +- +- Consume and demangle the signature portion of the mangled name. +- +- DECLP is the string where demangled output is being built. At +- entry it contains the demangled root name from the mangled name +- prefix. I.E. either a demangled operator name or the root function +- name. In some special cases, it may contain nothing. +- +- *MANGLED points to the current unconsumed location in the mangled +- name. As tokens are consumed and demangling is performed, the +- pointer is updated to continuously point at the next token to +- be consumed. +- +- Demangling GNU style mangled names is nasty because there is no +- explicit token that marks the start of the outermost function +- argument list. */ +- +-static int +-demangle_signature (struct work_stuff *work, +- const char **mangled, string *declp) +-{ +- int success = 1; +- int func_done = 0; +- int expect_func = 0; +- int expect_return_type = 0; +- const char *oldmangled = NULL; +- string trawname; +- string tname; +- +- while (success && (**mangled != '\0')) +- { +- switch (**mangled) +- { +- case 'Q': +- oldmangled = *mangled; +- success = demangle_qualified (work, mangled, declp, 1, 0); +- if (success) +- remember_type (work, oldmangled, *mangled - oldmangled); +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- expect_func = 1; +- oldmangled = NULL; +- break; +- +- case 'K': +- oldmangled = *mangled; +- success = demangle_qualified (work, mangled, declp, 1, 0); +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- { +- expect_func = 1; +- } +- oldmangled = NULL; +- break; +- +- case 'S': +- /* Static member function */ +- if (oldmangled == NULL) +- { +- oldmangled = *mangled; +- } +- (*mangled)++; +- work -> static_type = 1; +- break; +- +- case 'C': +- case 'V': +- case 'u': +- work->type_quals |= code_for_qualifier (**mangled); +- +- /* a qualified member function */ +- if (oldmangled == NULL) +- oldmangled = *mangled; +- (*mangled)++; +- break; +- +- case 'L': +- /* Local class name follows after "Lnnn_" */ +- if (HP_DEMANGLING) +- { +- while (**mangled && (**mangled != '_')) +- (*mangled)++; +- if (!**mangled) +- success = 0; +- else +- (*mangled)++; +- } +- else +- success = 0; +- break; +- +- case '0': case '1': case '2': case '3': case '4': +- case '5': case '6': case '7': case '8': case '9': +- if (oldmangled == NULL) +- { +- oldmangled = *mangled; +- } +- work->temp_start = -1; /* uppermost call to demangle_class */ +- success = demangle_class (work, mangled, declp); +- if (success) +- { +- remember_type (work, oldmangled, *mangled - oldmangled); +- } +- if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) +- { +- /* EDG and others will have the "F", so we let the loop cycle +- if we are looking at one. */ +- if (**mangled != 'F') +- expect_func = 1; +- } +- oldmangled = NULL; +- break; +- +- case 'B': +- { +- string s; +- success = do_type (work, mangled, &s); +- if (success) +- { +- string_append (&s, SCOPE_STRING (work)); +- string_prepends (declp, &s); +- string_delete (&s); +- } +- oldmangled = NULL; +- expect_func = 1; +- } +- break; +- +- case 'F': +- /* Function */ +- /* ARM/HP style demangling includes a specific 'F' character after +- the class name. For GNU style, it is just implied. So we can +- safely just consume any 'F' at this point and be compatible +- with either style. */ +- +- oldmangled = NULL; +- func_done = 1; +- (*mangled)++; +- +- /* For lucid/ARM/HP style we have to forget any types we might +- have remembered up to this point, since they were not argument +- types. GNU style considers all types seen as available for +- back references. See comment in demangle_args() */ +- +- if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) +- { +- forget_types (work); +- } +- success = demangle_args (work, mangled, declp); +- /* After picking off the function args, we expect to either +- find the function return type (preceded by an '_') or the +- end of the string. */ +- if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') +- { +- ++(*mangled); +- /* At this level, we do not care about the return type. */ +- success = do_type (work, mangled, &tname); +- string_delete (&tname); +- } +- +- break; +- +- case 't': +- /* G++ Template */ +- string_init(&trawname); +- string_init(&tname); +- if (oldmangled == NULL) +- { +- oldmangled = *mangled; +- } +- success = demangle_template (work, mangled, &tname, +- &trawname, 1, 1); +- if (success) +- { +- remember_type (work, oldmangled, *mangled - oldmangled); +- } +- string_append (&tname, SCOPE_STRING (work)); +- +- string_prepends(declp, &tname); +- if (work -> destructor & 1) +- { +- string_prepend (&trawname, "~"); +- string_appends (declp, &trawname); +- work->destructor -= 1; +- } +- if ((work->constructor & 1) || (work->destructor & 1)) +- { +- string_appends (declp, &trawname); +- work->constructor -= 1; +- } +- string_delete(&trawname); +- string_delete(&tname); +- oldmangled = NULL; +- expect_func = 1; +- break; +- +- case '_': +- if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type) +- { +- /* Read the return type. */ +- string return_type; +- +- (*mangled)++; +- success = do_type (work, mangled, &return_type); +- APPEND_BLANK (&return_type); +- +- string_prepends (declp, &return_type); +- string_delete (&return_type); +- break; +- } +- else +- /* At the outermost level, we cannot have a return type specified, +- so if we run into another '_' at this point we are dealing with +- a mangled name that is either bogus, or has been mangled by +- some algorithm we don't know how to deal with. So just +- reject the entire demangling. */ +- /* However, "_nnn" is an expected suffix for alternate entry point +- numbered nnn for a function, with HP aCC, so skip over that +- without reporting failure. pai/1997-09-04 */ +- if (HP_DEMANGLING) +- { +- (*mangled)++; +- while (**mangled && ISDIGIT ((unsigned char)**mangled)) +- (*mangled)++; +- } +- else +- success = 0; +- break; +- +- case 'H': +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- { +- /* A G++ template function. Read the template arguments. */ +- success = demangle_template (work, mangled, declp, 0, 0, +- 0); +- if (!(work->constructor & 1)) +- expect_return_type = 1; +- if (!**mangled) +- success = 0; +- else +- (*mangled)++; +- break; +- } +- /* fall through */ +- +- default: +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- { +- /* Assume we have stumbled onto the first outermost function +- argument token, and start processing args. */ +- func_done = 1; +- success = demangle_args (work, mangled, declp); +- } +- else +- { +- /* Non-GNU demanglers use a specific token to mark the start +- of the outermost function argument tokens. Typically 'F', +- for ARM/HP-demangling, for example. So if we find something +- we are not prepared for, it must be an error. */ +- success = 0; +- } +- break; +- } +- /* +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- */ +- { +- if (success && expect_func) +- { +- func_done = 1; +- if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) +- { +- forget_types (work); +- } +- success = demangle_args (work, mangled, declp); +- /* Since template include the mangling of their return types, +- we must set expect_func to 0 so that we don't try do +- demangle more arguments the next time we get here. */ +- expect_func = 0; +- } +- } +- } +- if (success && !func_done) +- { +- if (AUTO_DEMANGLING || GNU_DEMANGLING) +- { +- /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and +- bar__3fooi is 'foo::bar(int)'. We get here when we find the +- first case, and need to ensure that the '(void)' gets added to +- the current declp. Note that with ARM/HP, the first case +- represents the name of a static data member 'foo::bar', +- which is in the current declp, so we leave it alone. */ +- success = demangle_args (work, mangled, declp); +- } +- } +- if (success && PRINT_ARG_TYPES) +- { +- if (work->static_type) +- string_append (declp, " static"); +- if (work->type_quals != TYPE_UNQUALIFIED) +- { +- APPEND_BLANK (declp); +- string_append (declp, qualifier_string (work->type_quals)); +- } +- } +- +- return (success); +-} +- +-#if 0 +- +-static int +-demangle_method_args (struct work_stuff *work, const char **mangled, +- string *declp) +-{ +- int success = 0; +- +- if (work -> static_type) +- { +- string_append (declp, *mangled + 1); +- *mangled += strlen (*mangled); +- success = 1; +- } +- else +- { +- success = demangle_args (work, mangled, declp); +- } +- return (success); +-} +- +-#endif +- +-static int +-demangle_template_template_parm (struct work_stuff *work, +- const char **mangled, string *tname) +-{ +- int i; +- int r; +- int need_comma = 0; +- int success = 1; +- string temp; +- +- string_append (tname, "template <"); +- /* get size of template parameter list */ +- if (get_count (mangled, &r)) +- { +- for (i = 0; i < r; i++) +- { +- if (need_comma) +- { +- string_append (tname, ", "); +- } +- +- /* Z for type parameters */ +- if (**mangled == 'Z') +- { +- (*mangled)++; +- string_append (tname, "class"); +- } +- /* z for template parameters */ +- else if (**mangled == 'z') +- { +- (*mangled)++; +- success = +- demangle_template_template_parm (work, mangled, tname); +- if (!success) +- { +- break; +- } +- } +- else +- { +- /* temp is initialized in do_type */ +- success = do_type (work, mangled, &temp); +- if (success) +- { +- string_appends (tname, &temp); +- } +- string_delete(&temp); +- if (!success) +- { +- break; +- } +- } +- need_comma = 1; +- } +- +- } +- if (tname->p[-1] == '>') +- string_append (tname, " "); +- string_append (tname, "> class"); +- return (success); +-} +- +-static int +-demangle_expression (struct work_stuff *work, const char **mangled, +- string *s, type_kind_t tk) +-{ +- int need_operator = 0; +- int success; +- +- success = 1; +- string_appendn (s, "(", 1); +- (*mangled)++; +- while (success && **mangled != 'W' && **mangled != '\0') +- { +- if (need_operator) +- { +- size_t i; +- size_t len; +- +- success = 0; +- +- len = strlen (*mangled); +- +- for (i = 0; i < ARRAY_SIZE (optable); ++i) +- { +- size_t l = strlen (optable[i].in); +- +- if (l <= len +- && memcmp (optable[i].in, *mangled, l) == 0) +- { +- string_appendn (s, " ", 1); +- string_append (s, optable[i].out); +- string_appendn (s, " ", 1); +- success = 1; +- (*mangled) += l; +- break; +- } +- } +- +- if (!success) +- break; +- } +- else +- need_operator = 1; +- +- success = demangle_template_value_parm (work, mangled, s, tk); +- } +- +- if (**mangled != 'W') +- success = 0; +- else +- { +- string_appendn (s, ")", 1); +- (*mangled)++; +- } +- +- return success; +-} +- +-static int +-demangle_integral_value (struct work_stuff *work, +- const char **mangled, string *s) +-{ +- int success; +- +- if (**mangled == 'E') +- success = demangle_expression (work, mangled, s, tk_integral); +- else if (**mangled == 'Q' || **mangled == 'K') +- success = demangle_qualified (work, mangled, s, 0, 1); +- else +- { +- int value; +- +- /* By default, we let the number decide whether we shall consume an +- underscore. */ +- int multidigit_without_leading_underscore = 0; +- int leave_following_underscore = 0; +- +- success = 0; +- +- if (**mangled == '_') +- { +- if (mangled[0][1] == 'm') +- { +- /* Since consume_count_with_underscores does not handle the +- `m'-prefix we must do it here, using consume_count and +- adjusting underscores: we have to consume the underscore +- matching the prepended one. */ +- multidigit_without_leading_underscore = 1; +- string_appendn (s, "-", 1); +- (*mangled) += 2; +- } +- else +- { +- /* Do not consume a following underscore; +- consume_count_with_underscores will consume what +- should be consumed. */ +- leave_following_underscore = 1; +- } +- } +- else +- { +- /* Negative numbers are indicated with a leading `m'. */ +- if (**mangled == 'm') +- { +- string_appendn (s, "-", 1); +- (*mangled)++; +- } +- /* Since consume_count_with_underscores does not handle +- multi-digit numbers that do not start with an underscore, +- and this number can be an integer template parameter, +- we have to call consume_count. */ +- multidigit_without_leading_underscore = 1; +- /* These multi-digit numbers never end on an underscore, +- so if there is one then don't eat it. */ +- leave_following_underscore = 1; +- } +- +- /* We must call consume_count if we expect to remove a trailing +- underscore, since consume_count_with_underscores expects +- the leading underscore (that we consumed) if it is to handle +- multi-digit numbers. */ +- if (multidigit_without_leading_underscore) +- value = consume_count (mangled); +- else +- value = consume_count_with_underscores (mangled); +- +- if (value != -1) +- { +- char buf[INTBUF_SIZE]; +- sprintf (buf, "%d", value); +- string_append (s, buf); +- +- /* Numbers not otherwise delimited, might have an underscore +- appended as a delimeter, which we should skip. +- +- ??? This used to always remove a following underscore, which +- is wrong. If other (arbitrary) cases are followed by an +- underscore, we need to do something more radical. */ +- +- if ((value > 9 || multidigit_without_leading_underscore) +- && ! leave_following_underscore +- && **mangled == '_') +- (*mangled)++; +- +- /* All is well. */ +- success = 1; +- } +- } +- +- return success; +-} +- +-/* Demangle the real value in MANGLED. */ +- +-static int +-demangle_real_value (struct work_stuff *work, +- const char **mangled, string *s) +-{ +- if (**mangled == 'E') +- return demangle_expression (work, mangled, s, tk_real); +- +- if (**mangled == 'm') +- { +- string_appendn (s, "-", 1); +- (*mangled)++; +- } +- while (ISDIGIT ((unsigned char)**mangled)) +- { +- string_appendn (s, *mangled, 1); +- (*mangled)++; +- } +- if (**mangled == '.') /* fraction */ +- { +- string_appendn (s, ".", 1); +- (*mangled)++; +- while (ISDIGIT ((unsigned char)**mangled)) +- { +- string_appendn (s, *mangled, 1); +- (*mangled)++; +- } +- } +- if (**mangled == 'e') /* exponent */ +- { +- string_appendn (s, "e", 1); +- (*mangled)++; +- while (ISDIGIT ((unsigned char)**mangled)) +- { +- string_appendn (s, *mangled, 1); +- (*mangled)++; +- } +- } +- +- return 1; +-} +- +-static int +-demangle_template_value_parm (struct work_stuff *work, const char **mangled, +- string *s, type_kind_t tk) +-{ +- int success = 1; +- +- if (**mangled == 'Y') +- { +- /* The next argument is a template parameter. */ +- int idx; +- +- (*mangled)++; +- idx = consume_count_with_underscores (mangled); +- if (idx == -1 +- || (work->tmpl_argvec && idx >= work->ntmpl_args) +- || consume_count_with_underscores (mangled) == -1) +- return -1; +- if (work->tmpl_argvec) +- string_append (s, work->tmpl_argvec[idx]); +- else +- string_append_template_idx (s, idx); +- } +- else if (tk == tk_integral) +- success = demangle_integral_value (work, mangled, s); +- else if (tk == tk_char) +- { +- char tmp[2]; +- int val; +- if (**mangled == 'm') +- { +- string_appendn (s, "-", 1); +- (*mangled)++; +- } +- string_appendn (s, "'", 1); +- val = consume_count(mangled); +- if (val <= 0) +- success = 0; +- else +- { +- tmp[0] = (char)val; +- tmp[1] = '\0'; +- string_appendn (s, &tmp[0], 1); +- string_appendn (s, "'", 1); +- } +- } +- else if (tk == tk_bool) +- { +- int val = consume_count (mangled); +- if (val == 0) +- string_appendn (s, "false", 5); +- else if (val == 1) +- string_appendn (s, "true", 4); +- else +- success = 0; +- } +- else if (tk == tk_real) +- success = demangle_real_value (work, mangled, s); +- else if (tk == tk_pointer || tk == tk_reference +- || tk == tk_rvalue_reference) +- { +- if (**mangled == 'Q') +- success = demangle_qualified (work, mangled, s, +- /*isfuncname=*/0, +- /*append=*/1); +- else +- { +- int symbol_len = consume_count (mangled); +- if (symbol_len == -1 +- || symbol_len > (long) strlen (*mangled)) +- return -1; +- if (symbol_len == 0) +- string_appendn (s, "0", 1); +- else +- { +- char *p = XNEWVEC (char, symbol_len + 1), *q; +- strncpy (p, *mangled, symbol_len); +- p [symbol_len] = '\0'; +- /* We use cplus_demangle here, rather than +- internal_cplus_demangle, because the name of the entity +- mangled here does not make use of any of the squangling +- or type-code information we have built up thus far; it is +- mangled independently. */ +- q = cplus_demangle (p, work->options); +- if (tk == tk_pointer) +- string_appendn (s, "&", 1); +- /* FIXME: Pointer-to-member constants should get a +- qualifying class name here. */ +- if (q) +- { +- string_append (s, q); +- free (q); +- } +- else +- string_append (s, p); +- free (p); +- } +- *mangled += symbol_len; +- } +- } +- +- return success; +-} +- +-/* Demangle the template name in MANGLED. The full name of the +- template (e.g., S) is placed in TNAME. The name without the +- template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is +- non-NULL. If IS_TYPE is nonzero, this template is a type template, +- not a function template. If both IS_TYPE and REMEMBER are nonzero, +- the template is remembered in the list of back-referenceable +- types. */ +- +-static int +-demangle_template (struct work_stuff *work, const char **mangled, +- string *tname, string *trawname, +- int is_type, int remember) +-{ +- int i; +- int r; +- int need_comma = 0; +- int success = 0; +- int is_java_array = 0; +- string temp; +- +- (*mangled)++; +- if (is_type) +- { +- /* get template name */ +- if (**mangled == 'z') +- { +- int idx; +- (*mangled)++; +- if (**mangled == '\0') +- return (0); +- (*mangled)++; +- +- idx = consume_count_with_underscores (mangled); +- if (idx == -1 +- || (work->tmpl_argvec && idx >= work->ntmpl_args) +- || consume_count_with_underscores (mangled) == -1) +- return (0); +- +- if (work->tmpl_argvec) +- { +- string_append (tname, work->tmpl_argvec[idx]); +- if (trawname) +- string_append (trawname, work->tmpl_argvec[idx]); +- } +- else +- { +- string_append_template_idx (tname, idx); +- if (trawname) +- string_append_template_idx (trawname, idx); +- } +- } +- else +- { +- if ((r = consume_count (mangled)) <= 0 +- || (int) strlen (*mangled) < r) +- { +- return (0); +- } +- is_java_array = (work -> options & DMGL_JAVA) +- && strncmp (*mangled, "JArray1Z", 8) == 0; +- if (! is_java_array) +- { +- string_appendn (tname, *mangled, r); +- } +- if (trawname) +- string_appendn (trawname, *mangled, r); +- *mangled += r; +- } +- } +- if (!is_java_array) +- string_append (tname, "<"); +- /* get size of template parameter list */ +- if (!get_count (mangled, &r)) +- { +- return (0); +- } +- if (!is_type) +- { +- /* Create an array for saving the template argument values. */ +- work->tmpl_argvec = XNEWVEC (char *, r); +- work->ntmpl_args = r; +- for (i = 0; i < r; i++) +- work->tmpl_argvec[i] = 0; +- } +- for (i = 0; i < r; i++) +- { +- if (need_comma) +- { +- string_append (tname, ", "); +- } +- /* Z for type parameters */ +- if (**mangled == 'Z') +- { +- (*mangled)++; +- /* temp is initialized in do_type */ +- success = do_type (work, mangled, &temp); +- if (success) +- { +- string_appends (tname, &temp); +- +- if (!is_type) +- { +- /* Save the template argument. */ +- int len = temp.p - temp.b; +- work->tmpl_argvec[i] = XNEWVEC (char, len + 1); +- memcpy (work->tmpl_argvec[i], temp.b, len); +- work->tmpl_argvec[i][len] = '\0'; +- } +- } +- string_delete(&temp); +- if (!success) +- { +- break; +- } +- } +- /* z for template parameters */ +- else if (**mangled == 'z') +- { +- int r2; +- (*mangled)++; +- success = demangle_template_template_parm (work, mangled, tname); +- +- if (success +- && (r2 = consume_count (mangled)) > 0 +- && (int) strlen (*mangled) >= r2) +- { +- string_append (tname, " "); +- string_appendn (tname, *mangled, r2); +- if (!is_type) +- { +- /* Save the template argument. */ +- int len = r2; +- work->tmpl_argvec[i] = XNEWVEC (char, len + 1); +- memcpy (work->tmpl_argvec[i], *mangled, len); +- work->tmpl_argvec[i][len] = '\0'; +- } +- *mangled += r2; +- } +- if (!success) +- { +- break; +- } +- } +- else +- { +- string param; +- string* s; +- +- /* otherwise, value parameter */ +- +- /* temp is initialized in do_type */ +- success = do_type (work, mangled, &temp); +- string_delete(&temp); +- if (!success) +- break; +- +- if (!is_type) +- { +- s = ¶m; +- string_init (s); +- } +- else +- s = tname; +- +- success = demangle_template_value_parm (work, mangled, s, +- (type_kind_t) success); +- +- if (!success) +- { +- if (!is_type) +- string_delete (s); +- success = 0; +- break; +- } +- +- if (!is_type) +- { +- int len = s->p - s->b; +- work->tmpl_argvec[i] = XNEWVEC (char, len + 1); +- memcpy (work->tmpl_argvec[i], s->b, len); +- work->tmpl_argvec[i][len] = '\0'; +- +- string_appends (tname, s); +- string_delete (s); +- } +- } +- need_comma = 1; +- } +- if (is_java_array) +- { +- string_append (tname, "[]"); +- } +- else +- { +- if (tname->p[-1] == '>') +- string_append (tname, " "); +- string_append (tname, ">"); +- } +- +- if (is_type && remember) +- { +- const int bindex = register_Btype (work); +- remember_Btype (work, tname->b, LEN_STRING (tname), bindex); +- } +- +- /* +- if (work -> static_type) +- { +- string_append (declp, *mangled + 1); +- *mangled += strlen (*mangled); +- success = 1; +- } +- else +- { +- success = demangle_args (work, mangled, declp); +- } +- } +- */ +- return (success); +-} +- +-static int +-arm_pt (struct work_stuff *work, const char *mangled, +- int n, const char **anchor, const char **args) +-{ +- /* Check if ARM template with "__pt__" in it ("parameterized type") */ +- /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ +- if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__"))) +- { +- int len; +- *args = *anchor + 6; +- len = consume_count (args); +- if (len == -1) +- return 0; +- if (*args + len == mangled + n && **args == '_') +- { +- ++*args; +- return 1; +- } +- } +- if (AUTO_DEMANGLING || EDG_DEMANGLING) +- { +- if ((*anchor = strstr (mangled, "__tm__")) +- || (*anchor = strstr (mangled, "__ps__")) +- || (*anchor = strstr (mangled, "__pt__"))) +- { +- int len; +- *args = *anchor + 6; +- len = consume_count (args); +- if (len == -1) +- return 0; +- if (*args + len == mangled + n && **args == '_') +- { +- ++*args; +- return 1; +- } +- } +- else if ((*anchor = strstr (mangled, "__S"))) +- { +- int len; +- *args = *anchor + 3; +- len = consume_count (args); +- if (len == -1) +- return 0; +- if (*args + len == mangled + n && **args == '_') +- { +- ++*args; +- return 1; +- } +- } +- } +- +- return 0; +-} +- +-static void +-demangle_arm_hp_template (struct work_stuff *work, const char **mangled, +- int n, string *declp) +-{ +- const char *p; +- const char *args; +- const char *e = *mangled + n; +- string arg; +- +- /* Check for HP aCC template spec: classXt1t2 where t1, t2 are +- template args */ +- if (HP_DEMANGLING && ((*mangled)[n] == 'X')) +- { +- char *start_spec_args = NULL; +- int hold_options; +- +- /* First check for and omit template specialization pseudo-arguments, +- such as in "Spec<#1,#1.*>" */ +- start_spec_args = strchr (*mangled, '<'); +- if (start_spec_args && (start_spec_args - *mangled < n)) +- string_appendn (declp, *mangled, start_spec_args - *mangled); +- else +- string_appendn (declp, *mangled, n); +- (*mangled) += n + 1; +- string_init (&arg); +- if (work->temp_start == -1) /* non-recursive call */ +- work->temp_start = declp->p - declp->b; +- +- /* We want to unconditionally demangle parameter types in +- template parameters. */ +- hold_options = work->options; +- work->options |= DMGL_PARAMS; +- +- string_append (declp, "<"); +- while (1) +- { +- string_delete (&arg); +- switch (**mangled) +- { +- case 'T': +- /* 'T' signals a type parameter */ +- (*mangled)++; +- if (!do_type (work, mangled, &arg)) +- goto hpacc_template_args_done; +- break; +- +- case 'U': +- case 'S': +- /* 'U' or 'S' signals an integral value */ +- if (!do_hpacc_template_const_value (work, mangled, &arg)) +- goto hpacc_template_args_done; +- break; +- +- case 'A': +- /* 'A' signals a named constant expression (literal) */ +- if (!do_hpacc_template_literal (work, mangled, &arg)) +- goto hpacc_template_args_done; +- break; +- +- default: +- /* Today, 1997-09-03, we have only the above types +- of template parameters */ +- /* FIXME: maybe this should fail and return null */ +- goto hpacc_template_args_done; +- } +- string_appends (declp, &arg); +- /* Check if we're at the end of template args. +- 0 if at end of static member of template class, +- _ if done with template args for a function */ +- if ((**mangled == '\000') || (**mangled == '_')) +- break; +- else +- string_append (declp, ","); +- } +- hpacc_template_args_done: +- string_append (declp, ">"); +- string_delete (&arg); +- if (**mangled == '_') +- (*mangled)++; +- work->options = hold_options; +- return; +- } +- /* ARM template? (Also handles HP cfront extensions) */ +- else if (arm_pt (work, *mangled, n, &p, &args)) +- { +- int hold_options; +- string type_str; +- +- string_init (&arg); +- string_appendn (declp, *mangled, p - *mangled); +- if (work->temp_start == -1) /* non-recursive call */ +- work->temp_start = declp->p - declp->b; +- +- /* We want to unconditionally demangle parameter types in +- template parameters. */ +- hold_options = work->options; +- work->options |= DMGL_PARAMS; +- +- string_append (declp, "<"); +- /* should do error checking here */ +- while (args < e) { +- string_delete (&arg); +- +- /* Check for type or literal here */ +- switch (*args) +- { +- /* HP cfront extensions to ARM for template args */ +- /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ +- /* FIXME: We handle only numeric literals for HP cfront */ +- case 'X': +- /* A typed constant value follows */ +- args++; +- if (!do_type (work, &args, &type_str)) +- goto cfront_template_args_done; +- string_append (&arg, "("); +- string_appends (&arg, &type_str); +- string_delete (&type_str); +- string_append (&arg, ")"); +- if (*args != 'L') +- goto cfront_template_args_done; +- args++; +- /* Now snarf a literal value following 'L' */ +- if (!snarf_numeric_literal (&args, &arg)) +- goto cfront_template_args_done; +- break; +- +- case 'L': +- /* Snarf a literal following 'L' */ +- args++; +- if (!snarf_numeric_literal (&args, &arg)) +- goto cfront_template_args_done; +- break; +- default: +- /* Not handling other HP cfront stuff */ +- { +- const char* old_args = args; +- if (!do_type (work, &args, &arg)) +- goto cfront_template_args_done; +- +- /* Fail if we didn't make any progress: prevent infinite loop. */ +- if (args == old_args) +- { +- work->options = hold_options; +- return; +- } +- } +- } +- string_appends (declp, &arg); +- string_append (declp, ","); +- } +- cfront_template_args_done: +- string_delete (&arg); +- if (args >= e) +- --declp->p; /* remove extra comma */ +- string_append (declp, ">"); +- work->options = hold_options; +- } +- else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 +- && (*mangled)[9] == 'N' +- && (*mangled)[8] == (*mangled)[10] +- && strchr (cplus_markers, (*mangled)[8])) +- { +- /* A member of the anonymous namespace. */ +- string_append (declp, "{anonymous}"); +- } +- else +- { +- if (work->temp_start == -1) /* non-recursive call only */ +- work->temp_start = 0; /* disable in recursive calls */ +- string_appendn (declp, *mangled, n); +- } +- *mangled += n; +-} +- +-/* Extract a class name, possibly a template with arguments, from the +- mangled string; qualifiers, local class indicators, etc. have +- already been dealt with */ +- +-static int +-demangle_class_name (struct work_stuff *work, const char **mangled, +- string *declp) +-{ +- int n; +- int success = 0; +- +- n = consume_count (mangled); +- if (n == -1) +- return 0; +- if ((int) strlen (*mangled) >= n) +- { +- demangle_arm_hp_template (work, mangled, n, declp); +- success = 1; +- } +- +- return (success); +-} +- +-/* +- +-LOCAL FUNCTION +- +- demangle_class -- demangle a mangled class sequence +- +-SYNOPSIS +- +- static int +- demangle_class (struct work_stuff *work, const char **mangled, +- strint *declp) +- +-DESCRIPTION +- +- DECLP points to the buffer into which demangling is being done. +- +- *MANGLED points to the current token to be demangled. On input, +- it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) +- On exit, it points to the next token after the mangled class on +- success, or the first unconsumed token on failure. +- +- If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then +- we are demangling a constructor or destructor. In this case +- we prepend "class::class" or "class::~class" to DECLP. +- +- Otherwise, we prepend "class::" to the current DECLP. +- +- Reset the constructor/destructor flags once they have been +- "consumed". This allows demangle_class to be called later during +- the same demangling, to do normal class demangling. +- +- Returns 1 if demangling is successful, 0 otherwise. +- +-*/ +- +-static int +-demangle_class (struct work_stuff *work, const char **mangled, string *declp) +-{ +- int success = 0; +- int btype; +- string class_name; +- char *save_class_name_end = 0; +- +- string_init (&class_name); +- btype = register_Btype (work); +- if (demangle_class_name (work, mangled, &class_name)) +- { +- save_class_name_end = class_name.p; +- if ((work->constructor & 1) || (work->destructor & 1)) +- { +- /* adjust so we don't include template args */ +- if (work->temp_start && (work->temp_start != -1)) +- { +- class_name.p = class_name.b + work->temp_start; +- } +- string_prepends (declp, &class_name); +- if (work -> destructor & 1) +- { +- string_prepend (declp, "~"); +- work -> destructor -= 1; +- } +- else +- { +- work -> constructor -= 1; +- } +- } +- class_name.p = save_class_name_end; +- remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); +- remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); +- string_prepend (declp, SCOPE_STRING (work)); +- string_prepends (declp, &class_name); +- success = 1; +- } +- string_delete (&class_name); +- return (success); +-} +- +- +-/* Called when there's a "__" in the mangled name, with `scan' pointing to +- the rightmost guess. +- +- Find the correct "__"-sequence where the function name ends and the +- signature starts, which is ambiguous with GNU mangling. +- Call demangle_signature here, so we can make sure we found the right +- one; *mangled will be consumed so caller will not make further calls to +- demangle_signature. */ +- +-static int +-iterate_demangle_function (struct work_stuff *work, const char **mangled, +- string *declp, const char *scan) +-{ +- const char *mangle_init = *mangled; +- int success = 0; +- string decl_init; +- struct work_stuff work_init; +- +- if (*(scan + 2) == '\0') +- return 0; +- +- /* Do not iterate for some demangling modes, or if there's only one +- "__"-sequence. This is the normal case. */ +- if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING +- || strstr (scan + 2, "__") == NULL) +- return demangle_function_name (work, mangled, declp, scan); +- +- /* Save state so we can restart if the guess at the correct "__" was +- wrong. */ +- string_init (&decl_init); +- string_appends (&decl_init, declp); +- memset (&work_init, 0, sizeof work_init); +- work_stuff_copy_to_from (&work_init, work); +- +- /* Iterate over occurrences of __, allowing names and types to have a +- "__" sequence in them. We must start with the first (not the last) +- occurrence, since "__" most often occur between independent mangled +- parts, hence starting at the last occurence inside a signature +- might get us a "successful" demangling of the signature. */ +- +- while (scan[2]) +- { +- if (demangle_function_name (work, mangled, declp, scan)) +- { +- success = demangle_signature (work, mangled, declp); +- if (success) +- break; +- } +- +- /* Reset demangle state for the next round. */ +- *mangled = mangle_init; +- string_clear (declp); +- string_appends (declp, &decl_init); +- work_stuff_copy_to_from (work, &work_init); +- +- /* Leave this underscore-sequence. */ +- scan += 2; +- +- /* Scan for the next "__" sequence. */ +- while (*scan && (scan[0] != '_' || scan[1] != '_')) +- scan++; +- +- /* Move to last "__" in this sequence. */ +- while (*scan && *scan == '_') +- scan++; +- scan -= 2; +- } +- +- /* Delete saved state. */ +- delete_work_stuff (&work_init); +- string_delete (&decl_init); +- +- return success; +-} +- +-/* +- +-LOCAL FUNCTION +- +- demangle_prefix -- consume the mangled name prefix and find signature +- +-SYNOPSIS +- +- static int +- demangle_prefix (struct work_stuff *work, const char **mangled, +- string *declp); +- +-DESCRIPTION +- +- Consume and demangle the prefix of the mangled name. +- While processing the function name root, arrange to call +- demangle_signature if the root is ambiguous. +- +- DECLP points to the string buffer into which demangled output is +- placed. On entry, the buffer is empty. On exit it contains +- the root function name, the demangled operator name, or in some +- special cases either nothing or the completely demangled result. +- +- MANGLED points to the current pointer into the mangled name. As each +- token of the mangled name is consumed, it is updated. Upon entry +- the current mangled name pointer points to the first character of +- the mangled name. Upon exit, it should point to the first character +- of the signature if demangling was successful, or to the first +- unconsumed character if demangling of the prefix was unsuccessful. +- +- Returns 1 on success, 0 otherwise. +- */ +- +-static int +-demangle_prefix (struct work_stuff *work, const char **mangled, +- string *declp) +-{ +- int success = 1; +- const char *scan; +- int i; +- +- if (strlen(*mangled) > 6 +- && (strncmp(*mangled, "_imp__", 6) == 0 +- || strncmp(*mangled, "__imp_", 6) == 0)) +- { +- /* it's a symbol imported from a PE dynamic library. Check for both +- new style prefix _imp__ and legacy __imp_ used by older versions +- of dlltool. */ +- (*mangled) += 6; +- work->dllimported = 1; +- } +- else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) +- { +- char *marker = strchr (cplus_markers, (*mangled)[8]); +- if (marker != NULL && *marker == (*mangled)[10]) +- { +- if ((*mangled)[9] == 'D') +- { +- /* it's a GNU global destructor to be executed at program exit */ +- (*mangled) += 11; +- work->destructor = 2; +- if (gnu_special (work, mangled, declp)) +- return success; +- } +- else if ((*mangled)[9] == 'I') +- { +- /* it's a GNU global constructor to be executed at program init */ +- (*mangled) += 11; +- work->constructor = 2; +- if (gnu_special (work, mangled, declp)) +- return success; +- } +- } +- } +- else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) +- { +- /* it's a ARM global destructor to be executed at program exit */ +- (*mangled) += 7; +- work->destructor = 2; +- } +- else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) +- { +- /* it's a ARM global constructor to be executed at program initial */ +- (*mangled) += 7; +- work->constructor = 2; +- } +- +- /* This block of code is a reduction in strength time optimization +- of: +- scan = strstr (*mangled, "__"); */ +- +- { +- scan = *mangled; +- +- do { +- scan = strchr (scan, '_'); +- } while (scan != NULL && *++scan != '_'); +- +- if (scan != NULL) --scan; +- } +- +- if (scan != NULL) +- { +- /* We found a sequence of two or more '_', ensure that we start at +- the last pair in the sequence. */ +- i = strspn (scan, "_"); +- if (i > 2) +- { +- scan += (i - 2); +- } +- } +- +- if (scan == NULL) +- { +- success = 0; +- } +- else if (work -> static_type) +- { +- if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't')) +- { +- success = 0; +- } +- } +- else if ((scan == *mangled) +- && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q') +- || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) +- { +- /* The ARM says nothing about the mangling of local variables. +- But cfront mangles local variables by prepending __ +- to them. As an extension to ARM demangling we handle this case. */ +- if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) +- && ISDIGIT ((unsigned char)scan[2])) +- { +- *mangled = scan + 2; +- consume_count (mangled); +- string_append (declp, *mangled); +- *mangled += strlen (*mangled); +- success = 1; +- } +- else +- { +- /* A GNU style constructor starts with __[0-9Qt]. But cfront uses +- names like __Q2_3foo3bar for nested type names. So don't accept +- this style of constructor for cfront demangling. A GNU +- style member-template constructor starts with 'H'. */ +- if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) +- work -> constructor += 1; +- *mangled = scan + 2; +- } +- } +- else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') +- { +- /* Cfront-style parameterized type. Handled later as a signature. */ +- success = 1; +- +- /* ARM template? */ +- demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); +- } +- else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') +- || (scan[2] == 'p' && scan[3] == 's') +- || (scan[2] == 'p' && scan[3] == 't'))) +- { +- /* EDG-style parameterized type. Handled later as a signature. */ +- success = 1; +- +- /* EDG template? */ +- demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); +- } +- else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2]) +- && (scan[2] != 't')) +- { +- /* Mangled name starts with "__". Skip over any leading '_' characters, +- then find the next "__" that separates the prefix from the signature. +- */ +- if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) +- || (arm_special (mangled, declp) == 0)) +- { +- while (*scan == '_') +- { +- scan++; +- } +- if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) +- { +- /* No separator (I.E. "__not_mangled"), or empty signature +- (I.E. "__not_mangled_either__") */ +- success = 0; +- } +- else +- return iterate_demangle_function (work, mangled, declp, scan); +- } +- } +- else if (*(scan + 2) != '\0') +- { +- /* Mangled name does not start with "__" but does have one somewhere +- in there with non empty stuff after it. Looks like a global +- function name. Iterate over all "__":s until the right +- one is found. */ +- return iterate_demangle_function (work, mangled, declp, scan); +- } +- else +- { +- /* Doesn't look like a mangled name */ +- success = 0; +- } +- +- if (!success && (work->constructor == 2 || work->destructor == 2)) +- { +- string_append (declp, *mangled); +- *mangled += strlen (*mangled); +- success = 1; +- } +- return (success); +-} +- +-/* +- +-LOCAL FUNCTION +- +- gnu_special -- special handling of gnu mangled strings +- +-SYNOPSIS +- +- static int +- gnu_special (struct work_stuff *work, const char **mangled, +- string *declp); +- +- +-DESCRIPTION +- +- Process some special GNU style mangling forms that don't fit +- the normal pattern. For example: +- +- _$_3foo (destructor for class foo) +- _vt$foo (foo virtual table) +- _vt$foo$bar (foo::bar virtual table) +- __vt_foo (foo virtual table, new style with thunks) +- _3foo$varname (static data member) +- _Q22rs2tu$vw (static data member) +- __t6vector1Zii (constructor with template) +- __thunk_4__$_7ostream (virtual function thunk) +- */ +- +-static int +-gnu_special (struct work_stuff *work, const char **mangled, string *declp) +-{ +- int n; +- int success = 1; +- const char *p; +- +- if ((*mangled)[0] == '_' && (*mangled)[1] != '\0' +- && strchr (cplus_markers, (*mangled)[1]) != NULL +- && (*mangled)[2] == '_') +- { +- /* Found a GNU style destructor, get past "__" */ +- (*mangled) += 3; +- work -> destructor += 1; +- } +- else if ((*mangled)[0] == '_' +- && (((*mangled)[1] == '_' +- && (*mangled)[2] == 'v' +- && (*mangled)[3] == 't' +- && (*mangled)[4] == '_') +- || ((*mangled)[1] == 'v' +- && (*mangled)[2] == 't' && (*mangled)[3] != '\0' +- && strchr (cplus_markers, (*mangled)[3]) != NULL))) +- { +- /* Found a GNU style virtual table, get past "_vt" +- and create the decl. Note that we consume the entire mangled +- input string, which means that demangle_signature has no work +- to do. */ +- if ((*mangled)[2] == 'v') +- (*mangled) += 5; /* New style, with thunks: "__vt_" */ +- else +- (*mangled) += 4; /* Old style, no thunks: "_vt" */ +- while (**mangled != '\0') +- { +- switch (**mangled) +- { +- case 'Q': +- case 'K': +- success = demangle_qualified (work, mangled, declp, 0, 1); +- break; +- case 't': +- success = demangle_template (work, mangled, declp, 0, 1, +- 1); +- break; +- default: +- if (ISDIGIT((unsigned char)*mangled[0])) +- { +- n = consume_count(mangled); +- /* We may be seeing a too-large size, or else a +- "." indicating a static local symbol. In +- any case, declare victory and move on; *don't* try +- to use n to allocate. */ +- if (n > (int) strlen (*mangled)) +- { +- success = 1; +- break; +- } +- else if (n == -1) +- { +- success = 0; +- break; +- } +- } +- else +- { +- n = strcspn (*mangled, cplus_markers); +- } +- string_appendn (declp, *mangled, n); +- (*mangled) += n; +- } +- +- p = strpbrk (*mangled, cplus_markers); +- if (success && ((p == NULL) || (p == *mangled))) +- { +- if (p != NULL) +- { +- string_append (declp, SCOPE_STRING (work)); +- (*mangled)++; +- } +- } +- else +- { +- success = 0; +- break; +- } +- } +- if (success) +- string_append (declp, " virtual table"); +- } +- else if ((*mangled)[0] == '_' +- && (strchr("0123456789Qt", (*mangled)[1]) != NULL) +- && (p = strpbrk (*mangled, cplus_markers)) != NULL) +- { +- /* static data member, "_3foo$varname" for example */ +- (*mangled)++; +- switch (**mangled) +- { +- case 'Q': +- case 'K': +- success = demangle_qualified (work, mangled, declp, 0, 1); +- break; +- case 't': +- success = demangle_template (work, mangled, declp, 0, 1, 1); +- break; +- default: +- n = consume_count (mangled); +- if (n < 0 || n > (long) strlen (*mangled)) +- { +- success = 0; +- break; +- } +- +- if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 +- && (*mangled)[9] == 'N' +- && (*mangled)[8] == (*mangled)[10] +- && strchr (cplus_markers, (*mangled)[8])) +- { +- /* A member of the anonymous namespace. There's information +- about what identifier or filename it was keyed to, but +- it's just there to make the mangled name unique; we just +- step over it. */ +- string_append (declp, "{anonymous}"); +- (*mangled) += n; +- +- /* Now p points to the marker before the N, so we need to +- update it to the first marker after what we consumed. */ +- p = strpbrk (*mangled, cplus_markers); +- break; +- } +- +- string_appendn (declp, *mangled, n); +- (*mangled) += n; +- } +- if (success && (p == *mangled)) +- { +- /* Consumed everything up to the cplus_marker, append the +- variable name. */ +- (*mangled)++; +- string_append (declp, SCOPE_STRING (work)); +- n = strlen (*mangled); +- string_appendn (declp, *mangled, n); +- (*mangled) += n; +- } +- else +- { +- success = 0; +- } +- } +- else if (strncmp (*mangled, "__thunk_", 8) == 0) +- { +- int delta; +- +- (*mangled) += 8; +- delta = consume_count (mangled); +- if (delta == -1) +- success = 0; +- else if (**mangled != '_') +- success = 0; +- else +- { +- char *method = internal_cplus_demangle (work, ++*mangled); +- +- if (method) +- { +- char buf[50]; +- sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); +- string_append (declp, buf); +- string_append (declp, method); +- free (method); +- n = strlen (*mangled); +- (*mangled) += n; +- } +- else +- { +- success = 0; +- } +- } +- } +- else if (strncmp (*mangled, "__t", 3) == 0 +- && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) +- { +- p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; +- (*mangled) += 4; +- switch (**mangled) +- { +- case 'Q': +- case 'K': +- success = demangle_qualified (work, mangled, declp, 0, 1); +- break; +- case 't': +- success = demangle_template (work, mangled, declp, 0, 1, 1); +- break; +- default: +- success = do_type (work, mangled, declp); +- break; +- } +- if (success && **mangled != '\0') +- success = 0; +- if (success) +- string_append (declp, p); +- } +- else +- { +- success = 0; +- } +- return (success); +-} +- +-static void +-recursively_demangle(struct work_stuff *work, const char **mangled, +- string *result, int namelength) +-{ +- char * recurse = (char *)NULL; +- char * recurse_dem = (char *)NULL; +- +- recurse = XNEWVEC (char, namelength + 1); +- memcpy (recurse, *mangled, namelength); +- recurse[namelength] = '\000'; +- +- recurse_dem = cplus_demangle (recurse, work->options); +- +- if (recurse_dem) +- { +- string_append (result, recurse_dem); +- free (recurse_dem); +- } +- else +- { +- string_appendn (result, *mangled, namelength); +- } +- free (recurse); +- *mangled += namelength; +-} +- +-/* +- +-LOCAL FUNCTION +- +- arm_special -- special handling of ARM/lucid mangled strings +- +-SYNOPSIS +- +- static int +- arm_special (const char **mangled, +- string *declp); +- +- +-DESCRIPTION +- +- Process some special ARM style mangling forms that don't fit +- the normal pattern. For example: +- +- __vtbl__3foo (foo virtual table) +- __vtbl__3foo__3bar (bar::foo virtual table) +- +- */ +- +-static int +-arm_special (const char **mangled, string *declp) +-{ +- int n; +- int success = 1; +- const char *scan; +- +- if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) +- { +- /* Found a ARM style virtual table, get past ARM_VTABLE_STRING +- and create the decl. Note that we consume the entire mangled +- input string, which means that demangle_signature has no work +- to do. */ +- scan = *mangled + ARM_VTABLE_STRLEN; +- while (*scan != '\0') /* first check it can be demangled */ +- { +- n = consume_count (&scan); +- if (n == -1) +- { +- return (0); /* no good */ +- } +- scan += n; +- if (scan[0] == '_' && scan[1] == '_') +- { +- scan += 2; +- } +- } +- (*mangled) += ARM_VTABLE_STRLEN; +- while (**mangled != '\0') +- { +- n = consume_count (mangled); +- if (n == -1 +- || n > (long) strlen (*mangled)) +- return 0; +- string_prependn (declp, *mangled, n); +- (*mangled) += n; +- if ((*mangled)[0] == '_' && (*mangled)[1] == '_') +- { +- string_prepend (declp, "::"); +- (*mangled) += 2; +- } +- } +- string_append (declp, " virtual table"); +- } +- else +- { +- success = 0; +- } +- return (success); +-} +- +-/* +- +-LOCAL FUNCTION +- +- demangle_qualified -- demangle 'Q' qualified name strings +- +-SYNOPSIS +- +- static int +- demangle_qualified (struct work_stuff *, const char *mangled, +- string *result, int isfuncname, int append); +- +-DESCRIPTION +- +- Demangle a qualified name, such as "Q25Outer5Inner" which is +- the mangled form of "Outer::Inner". The demangled output is +- prepended or appended to the result string according to the +- state of the append flag. +- +- If isfuncname is nonzero, then the qualified name we are building +- is going to be used as a member function name, so if it is a +- constructor or destructor function, append an appropriate +- constructor or destructor name. I.E. for the above example, +- the result for use as a constructor is "Outer::Inner::Inner" +- and the result for use as a destructor is "Outer::Inner::~Inner". +- +-BUGS +- +- Numeric conversion is ASCII dependent (FIXME). +- +- */ +- +-static int +-demangle_qualified (struct work_stuff *work, const char **mangled, +- string *result, int isfuncname, int append) +-{ +- int qualifiers = 0; +- int success = 1; +- char num[2]; +- string temp; +- string last_name; +- int bindex = register_Btype (work); +- +- /* We only make use of ISFUNCNAME if the entity is a constructor or +- destructor. */ +- isfuncname = (isfuncname +- && ((work->constructor & 1) || (work->destructor & 1))); +- +- string_init (&temp); +- string_init (&last_name); +- +- if ((*mangled)[0] == 'K') +- { +- /* Squangling qualified name reuse */ +- int idx; +- (*mangled)++; +- idx = consume_count_with_underscores (mangled); +- if (idx == -1 || idx >= work -> numk) +- success = 0; +- else +- string_append (&temp, work -> ktypevec[idx]); +- } +- else +- switch ((*mangled)[1]) +- { +- case '_': +- /* GNU mangled name with more than 9 classes. The count is preceded +- by an underscore (to distinguish it from the <= 9 case) and followed +- by an underscore. */ +- (*mangled)++; +- qualifiers = consume_count_with_underscores (mangled); +- if (qualifiers == -1) +- success = 0; +- break; +- +- case '1': +- case '2': +- case '3': +- case '4': +- case '5': +- case '6': +- case '7': +- case '8': +- case '9': +- /* The count is in a single digit. */ +- num[0] = (*mangled)[1]; +- num[1] = '\0'; +- qualifiers = atoi (num); +- +- /* If there is an underscore after the digit, skip it. This is +- said to be for ARM-qualified names, but the ARM makes no +- mention of such an underscore. Perhaps cfront uses one. */ +- if ((*mangled)[2] == '_') +- { +- (*mangled)++; +- } +- (*mangled) += 2; +- break; +- +- case '0': +- default: +- success = 0; +- } +- +- if (!success) +- return success; +- +- /* Pick off the names and collect them in the temp buffer in the order +- in which they are found, separated by '::'. */ +- +- while (qualifiers-- > 0) +- { +- int remember_K = 1; +- string_clear (&last_name); +- +- if (*mangled[0] == '_') +- (*mangled)++; +- +- if (*mangled[0] == 't') +- { +- /* Here we always append to TEMP since we will want to use +- the template name without the template parameters as a +- constructor or destructor name. The appropriate +- (parameter-less) value is returned by demangle_template +- in LAST_NAME. We do not remember the template type here, +- in order to match the G++ mangling algorithm. */ +- success = demangle_template(work, mangled, &temp, +- &last_name, 1, 0); +- if (!success) +- break; +- } +- else if (*mangled[0] == 'K') +- { +- int idx; +- (*mangled)++; +- idx = consume_count_with_underscores (mangled); +- if (idx == -1 || idx >= work->numk) +- success = 0; +- else +- string_append (&temp, work->ktypevec[idx]); +- remember_K = 0; +- +- if (!success) break; +- } +- else +- { +- if (EDG_DEMANGLING) +- { +- int namelength; +- /* Now recursively demangle the qualifier +- * This is necessary to deal with templates in +- * mangling styles like EDG */ +- namelength = consume_count (mangled); +- if (namelength == -1) +- { +- success = 0; +- break; +- } +- recursively_demangle(work, mangled, &temp, namelength); +- } +- else +- { +- string_delete (&last_name); +- success = do_type (work, mangled, &last_name); +- if (!success) +- break; +- string_appends (&temp, &last_name); +- } +- } +- +- if (remember_K) +- remember_Ktype (work, temp.b, LEN_STRING (&temp)); +- +- if (qualifiers > 0) +- string_append (&temp, SCOPE_STRING (work)); +- } +- +- remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); +- +- /* If we are using the result as a function name, we need to append +- the appropriate '::' separated constructor or destructor name. +- We do this here because this is the most convenient place, where +- we already have a pointer to the name and the length of the name. */ +- +- if (isfuncname) +- { +- string_append (&temp, SCOPE_STRING (work)); +- if (work -> destructor & 1) +- string_append (&temp, "~"); +- string_appends (&temp, &last_name); +- } +- +- /* Now either prepend the temp buffer to the result, or append it, +- depending upon the state of the append flag. */ +- +- if (append) +- string_appends (result, &temp); +- else +- { +- if (!STRING_EMPTY (result)) +- string_append (&temp, SCOPE_STRING (work)); +- string_prepends (result, &temp); +- } +- +- string_delete (&last_name); +- string_delete (&temp); +- return (success); +-} +- +-/* +- +-LOCAL FUNCTION +- +- get_count -- convert an ascii count to integer, consuming tokens +- +-SYNOPSIS +- +- static int +- get_count (const char **type, int *count) +- +-DESCRIPTION +- +- Assume that *type points at a count in a mangled name; set +- *count to its value, and set *type to the next character after +- the count. There are some weird rules in effect here. +- +- If *type does not point at a string of digits, return zero. +- +- If *type points at a string of digits followed by an +- underscore, set *count to their value as an integer, advance +- *type to point *after the underscore, and return 1. +- +- If *type points at a string of digits not followed by an +- underscore, consume only the first digit. Set *count to its +- value as an integer, leave *type pointing after that digit, +- and return 1. +- +- The excuse for this odd behavior: in the ARM and HP demangling +- styles, a type can be followed by a repeat count of the form +- `Nxy', where: +- +- `x' is a single digit specifying how many additional copies +- of the type to append to the argument list, and +- +- `y' is one or more digits, specifying the zero-based index of +- the first repeated argument in the list. Yes, as you're +- unmangling the name you can figure this out yourself, but +- it's there anyway. +- +- So, for example, in `bar__3fooFPiN51', the first argument is a +- pointer to an integer (`Pi'), and then the next five arguments +- are the same (`N5'), and the first repeat is the function's +- second argument (`1'). +-*/ +- +-static int +-get_count (const char **type, int *count) +-{ +- const char *p; +- int n; +- +- if (!ISDIGIT ((unsigned char)**type)) +- return (0); +- else +- { +- *count = **type - '0'; +- (*type)++; +- if (ISDIGIT ((unsigned char)**type)) +- { +- p = *type; +- n = *count; +- do +- { +- n *= 10; +- n += *p - '0'; +- p++; +- } +- while (ISDIGIT ((unsigned char)*p)); +- if (*p == '_') +- { +- *type = p + 1; +- *count = n; +- } +- } +- } +- return (1); +-} +- +-/* RESULT will be initialised here; it will be freed on failure. The +- value returned is really a type_kind_t. */ +- +-static int +-do_type (struct work_stuff *work, const char **mangled, string *result) +-{ +- int n; +- int i; +- int is_proctypevec; +- int done; +- int success; +- string decl; +- const char *remembered_type; +- int type_quals; +- type_kind_t tk = tk_none; +- +- string_init (&decl); +- string_init (result); +- +- done = 0; +- success = 1; +- is_proctypevec = 0; +- while (success && !done) +- { +- int member; +- switch (**mangled) +- { +- +- /* A pointer type */ +- case 'P': +- case 'p': +- (*mangled)++; +- if (! (work -> options & DMGL_JAVA)) +- string_prepend (&decl, "*"); +- if (tk == tk_none) +- tk = tk_pointer; +- break; +- +- /* A reference type */ +- case 'R': +- (*mangled)++; +- string_prepend (&decl, "&"); +- if (tk == tk_none) +- tk = tk_reference; +- break; +- +- /* An rvalue reference type */ +- case 'O': +- (*mangled)++; +- string_prepend (&decl, "&&"); +- if (tk == tk_none) +- tk = tk_rvalue_reference; +- break; +- +- /* An array */ +- case 'A': +- { +- ++(*mangled); +- if (!STRING_EMPTY (&decl) +- && (decl.b[0] == '*' || decl.b[0] == '&')) +- { +- string_prepend (&decl, "("); +- string_append (&decl, ")"); +- } +- string_append (&decl, "["); +- if (**mangled != '_') +- success = demangle_template_value_parm (work, mangled, &decl, +- tk_integral); +- if (**mangled == '_') +- ++(*mangled); +- string_append (&decl, "]"); +- break; +- } +- +- /* A back reference to a previously seen type */ +- case 'T': +- (*mangled)++; +- if (!get_count (mangled, &n) || n < 0 || n >= work -> ntypes) +- { +- success = 0; +- } +- else +- for (i = 0; i < work->nproctypes; i++) +- if (work -> proctypevec [i] == n) +- success = 0; +- +- if (success) +- { +- is_proctypevec = 1; +- push_processed_type (work, n); +- remembered_type = work->typevec[n]; +- mangled = &remembered_type; +- } +- break; +- +- /* A function */ +- case 'F': +- (*mangled)++; +- if (!STRING_EMPTY (&decl) +- && (decl.b[0] == '*' || decl.b[0] == '&')) +- { +- string_prepend (&decl, "("); +- string_append (&decl, ")"); +- } +- /* After picking off the function args, we expect to either find the +- function return type (preceded by an '_') or the end of the +- string. */ +- if (!demangle_nested_args (work, mangled, &decl) +- || (**mangled != '_' && **mangled != '\0')) +- { +- success = 0; +- break; +- } +- if (success && (**mangled == '_')) +- (*mangled)++; +- break; +- +- case 'M': +- { +- type_quals = TYPE_UNQUALIFIED; +- +- member = **mangled == 'M'; +- (*mangled)++; +- +- string_append (&decl, ")"); +- +- /* We don't need to prepend `::' for a qualified name; +- demangle_qualified will do that for us. */ +- if (**mangled != 'Q') +- string_prepend (&decl, SCOPE_STRING (work)); +- +- if (ISDIGIT ((unsigned char)**mangled)) +- { +- n = consume_count (mangled); +- if (n == -1 +- || (int) strlen (*mangled) < n) +- { +- success = 0; +- break; +- } +- string_prependn (&decl, *mangled, n); +- *mangled += n; +- } +- else if (**mangled == 'X' || **mangled == 'Y') +- { +- string temp; +- do_type (work, mangled, &temp); +- string_prepends (&decl, &temp); +- string_delete (&temp); +- } +- else if (**mangled == 't') +- { +- string temp; +- string_init (&temp); +- success = demangle_template (work, mangled, &temp, +- NULL, 1, 1); +- if (success) +- { +- string_prependn (&decl, temp.b, temp.p - temp.b); +- string_delete (&temp); +- } +- else +- { +- string_delete (&temp); +- break; +- } +- } +- else if (**mangled == 'Q') +- { +- success = demangle_qualified (work, mangled, &decl, +- /*isfuncnam=*/0, +- /*append=*/0); +- if (!success) +- break; +- } +- else +- { +- success = 0; +- break; +- } +- +- string_prepend (&decl, "("); +- if (member) +- { +- switch (**mangled) +- { +- case 'C': +- case 'V': +- case 'u': +- type_quals |= code_for_qualifier (**mangled); +- (*mangled)++; +- break; +- +- default: +- break; +- } +- +- if (*(*mangled) != 'F') +- { +- success = 0; +- break; +- } +- (*mangled)++; +- } +- if ((member && !demangle_nested_args (work, mangled, &decl)) +- || **mangled != '_') +- { +- success = 0; +- break; +- } +- (*mangled)++; +- if (! PRINT_ANSI_QUALIFIERS) +- { +- break; +- } +- if (type_quals != TYPE_UNQUALIFIED) +- { +- APPEND_BLANK (&decl); +- string_append (&decl, qualifier_string (type_quals)); +- } +- break; +- } +- case 'G': +- (*mangled)++; +- break; +- +- case 'C': +- case 'V': +- case 'u': +- if (PRINT_ANSI_QUALIFIERS) +- { +- if (!STRING_EMPTY (&decl)) +- string_prepend (&decl, " "); +- +- string_prepend (&decl, demangle_qualifier (**mangled)); +- } +- (*mangled)++; +- break; +- /* +- } +- */ +- +- /* fall through */ +- default: +- done = 1; +- break; +- } +- } +- +- if (success) switch (**mangled) +- { +- /* A qualified name, such as "Outer::Inner". */ +- case 'Q': +- case 'K': +- { +- success = demangle_qualified (work, mangled, result, 0, 1); +- break; +- } +- +- /* A back reference to a previously seen squangled type */ +- case 'B': +- (*mangled)++; +- if (!get_count (mangled, &n) || n < 0 || n >= work -> numb) +- success = 0; +- else +- string_append (result, work->btypevec[n]); +- break; +- +- case 'X': +- case 'Y': +- /* A template parm. We substitute the corresponding argument. */ +- { +- int idx; +- +- (*mangled)++; +- idx = consume_count_with_underscores (mangled); +- +- if (idx == -1 +- || (work->tmpl_argvec && idx >= work->ntmpl_args) +- || consume_count_with_underscores (mangled) == -1) +- { +- success = 0; +- break; +- } +- +- if (work->tmpl_argvec) +- string_append (result, work->tmpl_argvec[idx]); +- else +- string_append_template_idx (result, idx); +- +- success = 1; +- } +- break; +- +- default: +- success = demangle_fund_type (work, mangled, result); +- if (tk == tk_none) +- tk = (type_kind_t) success; +- break; +- } +- +- if (success) +- { +- if (!STRING_EMPTY (&decl)) +- { +- string_append (result, " "); +- string_appends (result, &decl); +- } +- } +- else +- string_delete (result); +- string_delete (&decl); +- +- if (is_proctypevec) +- pop_processed_type (work); +- +- if (success) +- /* Assume an integral type, if we're not sure. */ +- return (int) ((tk == tk_none) ? tk_integral : tk); +- else +- return 0; +-} +- +-/* Given a pointer to a type string that represents a fundamental type +- argument (int, long, unsigned int, etc) in TYPE, a pointer to the +- string in which the demangled output is being built in RESULT, and +- the WORK structure, decode the types and add them to the result. +- +- For example: +- +- "Ci" => "const int" +- "Sl" => "signed long" +- "CUs" => "const unsigned short" +- +- The value returned is really a type_kind_t. */ +- +-static int +-demangle_fund_type (struct work_stuff *work, +- const char **mangled, string *result) +-{ +- int done = 0; +- int success = 1; +- char buf[INTBUF_SIZE + 5 /* 'int%u_t' */]; +- unsigned int dec = 0; +- type_kind_t tk = tk_integral; +- +- /* First pick off any type qualifiers. There can be more than one. */ +- +- while (!done) +- { +- switch (**mangled) +- { +- case 'C': +- case 'V': +- case 'u': +- if (PRINT_ANSI_QUALIFIERS) +- { +- if (!STRING_EMPTY (result)) +- string_prepend (result, " "); +- string_prepend (result, demangle_qualifier (**mangled)); +- } +- (*mangled)++; +- break; +- case 'U': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "unsigned"); +- break; +- case 'S': /* signed char only */ +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "signed"); +- break; +- case 'J': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "__complex"); +- break; +- default: +- done = 1; +- break; +- } +- } +- +- /* Now pick off the fundamental type. There can be only one. */ +- +- switch (**mangled) +- { +- case '\0': +- case '_': +- break; +- case 'v': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "void"); +- break; +- case 'x': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "long long"); +- break; +- case 'l': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "long"); +- break; +- case 'i': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "int"); +- break; +- case 's': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "short"); +- break; +- case 'b': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "bool"); +- tk = tk_bool; +- break; +- case 'c': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "char"); +- tk = tk_char; +- break; +- case 'w': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "wchar_t"); +- tk = tk_char; +- break; +- case 'r': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "long double"); +- tk = tk_real; +- break; +- case 'd': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "double"); +- tk = tk_real; +- break; +- case 'f': +- (*mangled)++; +- APPEND_BLANK (result); +- string_append (result, "float"); +- tk = tk_real; +- break; +- case 'G': +- (*mangled)++; +- if (!ISDIGIT ((unsigned char)**mangled)) +- { +- success = 0; +- break; +- } +- /* fall through */ +- case 'I': +- (*mangled)++; +- if (**mangled == '_') +- { +- int i; +- (*mangled)++; +- for (i = 0; +- i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_'; +- (*mangled)++, i++) +- buf[i] = **mangled; +- if (**mangled != '_') +- { +- success = 0; +- break; +- } +- buf[i] = '\0'; +- (*mangled)++; +- } +- else +- { +- strncpy (buf, *mangled, 2); +- buf[2] = '\0'; +- *mangled += min (strlen (*mangled), 2); +- } +- sscanf (buf, "%x", &dec); +- sprintf (buf, "int%u_t", dec); +- APPEND_BLANK (result); +- string_append (result, buf); +- break; +- +- /* fall through */ +- /* An explicit type, such as "6mytype" or "7integer" */ +- case '0': +- case '1': +- case '2': +- case '3': +- case '4': +- case '5': +- case '6': +- case '7': +- case '8': +- case '9': +- { +- int bindex = register_Btype (work); +- string btype; +- string_init (&btype); +- if (demangle_class_name (work, mangled, &btype)) { +- remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); +- APPEND_BLANK (result); +- string_appends (result, &btype); +- } +- else +- success = 0; +- string_delete (&btype); +- break; +- } +- case 't': +- { +- string btype; +- string_init (&btype); +- success = demangle_template (work, mangled, &btype, 0, 1, 1); +- string_appends (result, &btype); +- string_delete (&btype); +- break; +- } +- default: +- success = 0; +- break; +- } +- +- return success ? ((int) tk) : 0; +-} +- +- +-/* Handle a template's value parameter for HP aCC (extension from ARM) +- **mangled points to 'S' or 'U' */ +- +-static int +-do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED, +- const char **mangled, string *result) +-{ +- int unsigned_const; +- +- if (**mangled != 'U' && **mangled != 'S') +- return 0; +- +- unsigned_const = (**mangled == 'U'); +- +- (*mangled)++; +- +- switch (**mangled) +- { +- case 'N': +- string_append (result, "-"); +- /* fall through */ +- case 'P': +- (*mangled)++; +- break; +- case 'M': +- /* special case for -2^31 */ +- string_append (result, "-2147483648"); +- (*mangled)++; +- return 1; +- default: +- return 0; +- } +- +- /* We have to be looking at an integer now */ +- if (!(ISDIGIT ((unsigned char)**mangled))) +- return 0; +- +- /* We only deal with integral values for template +- parameters -- so it's OK to look only for digits */ +- while (ISDIGIT ((unsigned char)**mangled)) +- { +- char_str[0] = **mangled; +- string_append (result, char_str); +- (*mangled)++; +- } +- +- if (unsigned_const) +- string_append (result, "U"); +- +- /* FIXME? Some day we may have 64-bit (or larger :-) ) constants +- with L or LL suffixes. pai/1997-09-03 */ +- +- return 1; /* success */ +-} +- +-/* Handle a template's literal parameter for HP aCC (extension from ARM) +- **mangled is pointing to the 'A' */ +- +-static int +-do_hpacc_template_literal (struct work_stuff *work, const char **mangled, +- string *result) +-{ +- int literal_len = 0; +- char * recurse; +- char * recurse_dem; +- +- if (**mangled != 'A') +- return 0; +- +- (*mangled)++; +- +- literal_len = consume_count (mangled); +- +- if (literal_len <= 0 +- || literal_len > (long) strlen (*mangled)) +- return 0; +- +- /* Literal parameters are names of arrays, functions, etc. and the +- canonical representation uses the address operator */ +- string_append (result, "&"); +- +- /* Now recursively demangle the literal name */ +- recurse = XNEWVEC (char, literal_len + 1); +- memcpy (recurse, *mangled, literal_len); +- recurse[literal_len] = '\000'; +- +- recurse_dem = cplus_demangle (recurse, work->options); +- +- if (recurse_dem) +- { +- string_append (result, recurse_dem); +- free (recurse_dem); +- } +- else +- { +- string_appendn (result, *mangled, literal_len); +- } +- (*mangled) += literal_len; +- free (recurse); +- +- return 1; +-} +- +-static int +-snarf_numeric_literal (const char **args, string *arg) +-{ +- if (**args == '-') +- { +- char_str[0] = '-'; +- string_append (arg, char_str); +- (*args)++; +- } +- else if (**args == '+') +- (*args)++; +- +- if (!ISDIGIT ((unsigned char)**args)) +- return 0; +- +- while (ISDIGIT ((unsigned char)**args)) +- { +- char_str[0] = **args; +- string_append (arg, char_str); +- (*args)++; +- } +- +- return 1; +-} +- +-/* Demangle the next argument, given by MANGLED into RESULT, which +- *should be an uninitialized* string. It will be initialized here, +- and free'd should anything go wrong. */ +- +-static int +-do_arg (struct work_stuff *work, const char **mangled, string *result) +-{ +- /* Remember where we started so that we can record the type, for +- non-squangling type remembering. */ +- const char *start = *mangled; +- +- string_init (result); +- +- if (work->nrepeats > 0) +- { +- --work->nrepeats; +- +- if (work->previous_argument == 0) +- return 0; +- +- /* We want to reissue the previous type in this argument list. */ +- string_appends (result, work->previous_argument); +- return 1; +- } +- +- if (**mangled == 'n') +- { +- /* A squangling-style repeat. */ +- (*mangled)++; +- work->nrepeats = consume_count(mangled); +- +- if (work->nrepeats <= 0) +- /* This was not a repeat count after all. */ +- return 0; +- +- if (work->nrepeats > 9) +- { +- if (**mangled != '_') +- /* The repeat count should be followed by an '_' in this +- case. */ +- return 0; +- else +- (*mangled)++; +- } +- +- /* Now, the repeat is all set up. */ +- return do_arg (work, mangled, result); +- } +- +- /* Save the result in WORK->previous_argument so that we can find it +- if it's repeated. Note that saving START is not good enough: we +- do not want to add additional types to the back-referenceable +- type vector when processing a repeated type. */ +- if (work->previous_argument) +- string_delete (work->previous_argument); +- else +- work->previous_argument = XNEW (string); +- +- if (!do_type (work, mangled, work->previous_argument)) +- return 0; +- +- string_appends (result, work->previous_argument); +- +- remember_type (work, start, *mangled - start); +- return 1; +-} +- +-static void +-push_processed_type (struct work_stuff *work, int typevec_index) +-{ +- if (work->nproctypes >= work->proctypevec_size) +- { +- if (!work->proctypevec_size) +- { +- work->proctypevec_size = 4; +- work->proctypevec = XNEWVEC (int, work->proctypevec_size); +- } +- else +- { +- if (work->proctypevec_size < 16) +- /* Double when small. */ +- work->proctypevec_size *= 2; +- else +- { +- /* Grow slower when large. */ +- if (work->proctypevec_size > (INT_MAX / 3) * 2) +- xmalloc_failed (INT_MAX); +- work->proctypevec_size = (work->proctypevec_size * 3 / 2); +- } +- work->proctypevec +- = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size); +- } +- } +- work->proctypevec [work->nproctypes++] = typevec_index; +-} +- +-static void +-pop_processed_type (struct work_stuff *work) +-{ +- work->nproctypes--; +-} +- +-static void +-remember_type (struct work_stuff *work, const char *start, int len) +-{ +- char *tem; +- +- if (work->forgetting_types) +- return; +- +- if (work -> ntypes >= work -> typevec_size) +- { +- if (work -> typevec_size == 0) +- { +- work -> typevec_size = 3; +- work -> typevec = XNEWVEC (char *, work->typevec_size); +- } +- else +- { +- if (work -> typevec_size > INT_MAX / 2) +- xmalloc_failed (INT_MAX); +- work -> typevec_size *= 2; +- work -> typevec +- = XRESIZEVEC (char *, work->typevec, work->typevec_size); +- } +- } +- tem = XNEWVEC (char, len + 1); +- memcpy (tem, start, len); +- tem[len] = '\0'; +- work -> typevec[work -> ntypes++] = tem; +-} +- +- +-/* Remember a K type class qualifier. */ +-static void +-remember_Ktype (struct work_stuff *work, const char *start, int len) +-{ +- char *tem; +- +- if (work -> numk >= work -> ksize) +- { +- if (work -> ksize == 0) +- { +- work -> ksize = 5; +- work -> ktypevec = XNEWVEC (char *, work->ksize); +- } +- else +- { +- if (work -> ksize > INT_MAX / 2) +- xmalloc_failed (INT_MAX); +- work -> ksize *= 2; +- work -> ktypevec +- = XRESIZEVEC (char *, work->ktypevec, work->ksize); +- } +- } +- tem = XNEWVEC (char, len + 1); +- memcpy (tem, start, len); +- tem[len] = '\0'; +- work -> ktypevec[work -> numk++] = tem; +-} +- +-/* Register a B code, and get an index for it. B codes are registered +- as they are seen, rather than as they are completed, so map > +- registers map > as B0, and temp as B1 */ +- +-static int +-register_Btype (struct work_stuff *work) +-{ +- int ret; +- +- if (work -> numb >= work -> bsize) +- { +- if (work -> bsize == 0) +- { +- work -> bsize = 5; +- work -> btypevec = XNEWVEC (char *, work->bsize); +- } +- else +- { +- if (work -> bsize > INT_MAX / 2) +- xmalloc_failed (INT_MAX); +- work -> bsize *= 2; +- work -> btypevec +- = XRESIZEVEC (char *, work->btypevec, work->bsize); +- } +- } +- ret = work -> numb++; +- work -> btypevec[ret] = NULL; +- return(ret); +-} +- +-/* Store a value into a previously registered B code type. */ +- +-static void +-remember_Btype (struct work_stuff *work, const char *start, +- int len, int index) +-{ +- char *tem; +- +- tem = XNEWVEC (char, len + 1); +- if (len > 0) +- memcpy (tem, start, len); +- tem[len] = '\0'; +- work -> btypevec[index] = tem; +-} +- +-/* Lose all the info related to B and K type codes. */ +- +-static void +-forget_B_and_K_types (struct work_stuff *work) +-{ +- int i; +- +- while (work -> numk > 0) +- { +- i = --(work -> numk); +- if (work -> ktypevec[i] != NULL) +- { +- free (work -> ktypevec[i]); +- work -> ktypevec[i] = NULL; +- } +- } +- +- while (work -> numb > 0) +- { +- i = --(work -> numb); +- if (work -> btypevec[i] != NULL) +- { +- free (work -> btypevec[i]); +- work -> btypevec[i] = NULL; +- } +- } +-} +- +-/* Forget the remembered types, but not the type vector itself. */ +- +-static void +-forget_types (struct work_stuff *work) +-{ +- int i; +- +- while (work -> ntypes > 0) +- { +- i = --(work -> ntypes); +- if (work -> typevec[i] != NULL) +- { +- free (work -> typevec[i]); +- work -> typevec[i] = NULL; +- } +- } +-} +- +-/* Process the argument list part of the signature, after any class spec +- has been consumed, as well as the first 'F' character (if any). For +- example: +- +- "__als__3fooRT0" => process "RT0" +- "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" +- +- DECLP must be already initialised, usually non-empty. It won't be freed +- on failure. +- +- Note that g++ differs significantly from ARM and lucid style mangling +- with regards to references to previously seen types. For example, given +- the source fragment: +- +- class foo { +- public: +- foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); +- }; +- +- foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } +- void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } +- +- g++ produces the names: +- +- __3fooiRT0iT2iT2 +- foo__FiR3fooiT1iT1 +- +- while lcc (and presumably other ARM style compilers as well) produces: +- +- foo__FiR3fooT1T2T1T2 +- __ct__3fooFiR3fooT1T2T1T2 +- +- Note that g++ bases its type numbers starting at zero and counts all +- previously seen types, while lucid/ARM bases its type numbers starting +- at one and only considers types after it has seen the 'F' character +- indicating the start of the function args. For lucid/ARM style, we +- account for this difference by discarding any previously seen types when +- we see the 'F' character, and subtracting one from the type number +- reference. +- +- */ +- +-static int +-demangle_args (struct work_stuff *work, const char **mangled, +- string *declp) +-{ +- string arg; +- int need_comma = 0; +- int r; +- int t; +- const char *tem; +- char temptype; +- +- if (PRINT_ARG_TYPES) +- { +- string_append (declp, "("); +- if (**mangled == '\0') +- { +- string_append (declp, "void"); +- } +- } +- +- while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') +- || work->nrepeats > 0) +- { +- if ((**mangled == 'N') || (**mangled == 'T')) +- { +- temptype = *(*mangled)++; +- +- if (temptype == 'N') +- { +- if (!get_count (mangled, &r)) +- { +- return (0); +- } +- } +- else +- { +- r = 1; +- } +- if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) +- { +- /* If we have 10 or more types we might have more than a 1 digit +- index so we'll have to consume the whole count here. This +- will lose if the next thing is a type name preceded by a +- count but it's impossible to demangle that case properly +- anyway. Eg if we already have 12 types is T12Pc "(..., type1, +- Pc, ...)" or "(..., type12, char *, ...)" */ +- if ((t = consume_count(mangled)) <= 0) +- { +- return (0); +- } +- } +- else +- { +- if (!get_count (mangled, &t)) +- { +- return (0); +- } +- } +- if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) +- { +- t--; +- } +- /* Validate the type index. Protect against illegal indices from +- malformed type strings. */ +- if ((t < 0) || (t >= work -> ntypes)) +- { +- return (0); +- } +- while (work->nrepeats > 0 || --r >= 0) +- { +- tem = work -> typevec[t]; +- if (need_comma && PRINT_ARG_TYPES) +- { +- string_append (declp, ", "); +- } +- push_processed_type (work, t); +- if (!do_arg (work, &tem, &arg)) +- { +- pop_processed_type (work); +- return (0); +- } +- pop_processed_type (work); +- if (PRINT_ARG_TYPES) +- { +- string_appends (declp, &arg); +- } +- string_delete (&arg); +- need_comma = 1; +- } +- } +- else +- { +- if (need_comma && PRINT_ARG_TYPES) +- string_append (declp, ", "); +- if (!do_arg (work, mangled, &arg)) +- return (0); +- if (PRINT_ARG_TYPES) +- string_appends (declp, &arg); +- string_delete (&arg); +- need_comma = 1; +- } +- } +- +- if (**mangled == 'e') +- { +- (*mangled)++; +- if (PRINT_ARG_TYPES) +- { +- if (need_comma) +- { +- string_append (declp, ","); +- } +- string_append (declp, "..."); +- } +- } +- +- if (PRINT_ARG_TYPES) +- { +- string_append (declp, ")"); +- } +- return (1); +-} +- +-/* Like demangle_args, but for demangling the argument lists of function +- and method pointers or references, not top-level declarations. */ +- +-static int +-demangle_nested_args (struct work_stuff *work, const char **mangled, +- string *declp) +-{ +- string* saved_previous_argument; +- int result; +- int saved_nrepeats; +- +- if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) +- { +- if (work->recursion_level > DEMANGLE_RECURSION_LIMIT) +- /* FIXME: There ought to be a way to report +- that the recursion limit has been reached. */ +- return 0; +- +- work->recursion_level ++; +- } +- +- /* The G++ name-mangling algorithm does not remember types on nested +- argument lists, unless -fsquangling is used, and in that case the +- type vector updated by remember_type is not used. So, we turn +- off remembering of types here. */ +- ++work->forgetting_types; +- +- /* For the repeat codes used with -fsquangling, we must keep track of +- the last argument. */ +- saved_previous_argument = work->previous_argument; +- saved_nrepeats = work->nrepeats; +- work->previous_argument = 0; +- work->nrepeats = 0; +- +- /* Actually demangle the arguments. */ +- result = demangle_args (work, mangled, declp); +- +- /* Restore the previous_argument field. */ +- if (work->previous_argument) +- { +- string_delete (work->previous_argument); +- free ((char *) work->previous_argument); +- } +- work->previous_argument = saved_previous_argument; +- --work->forgetting_types; +- work->nrepeats = saved_nrepeats; +- +- if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) +- --work->recursion_level; +- +- return result; +-} +- +-/* Returns 1 if a valid function name was found or 0 otherwise. */ +- +-static int +-demangle_function_name (struct work_stuff *work, const char **mangled, +- string *declp, const char *scan) +-{ +- size_t i; +- string type; +- const char *tem; +- +- string_appendn (declp, (*mangled), scan - (*mangled)); +- string_need (declp, 1); +- *(declp -> p) = '\0'; +- +- /* Consume the function name, including the "__" separating the name +- from the signature. We are guaranteed that SCAN points to the +- separator. */ +- +- (*mangled) = scan + 2; +- /* We may be looking at an instantiation of a template function: +- foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a +- following _F marks the start of the function arguments. Handle +- the template arguments first. */ +- +- if (HP_DEMANGLING && (**mangled == 'X')) +- { +- demangle_arm_hp_template (work, mangled, 0, declp); +- /* This leaves MANGLED pointing to the 'F' marking func args */ +- } +- +- if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) +- { +- +- /* See if we have an ARM style constructor or destructor operator. +- If so, then just record it, clear the decl, and return. +- We can't build the actual constructor/destructor decl until later, +- when we recover the class name from the signature. */ +- +- if (strcmp (declp -> b, "__ct") == 0) +- { +- work -> constructor += 1; +- string_clear (declp); +- return 1; +- } +- else if (strcmp (declp -> b, "__dt") == 0) +- { +- work -> destructor += 1; +- string_clear (declp); +- return 1; +- } +- } +- +- if (declp->p - declp->b >= 3 +- && declp->b[0] == 'o' +- && declp->b[1] == 'p' +- && strchr (cplus_markers, declp->b[2]) != NULL) +- { +- /* see if it's an assignment expression */ +- if (declp->p - declp->b >= 10 /* op$assign_ */ +- && memcmp (declp->b + 3, "assign_", 7) == 0) +- { +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- int len = declp->p - declp->b - 10; +- if ((int) strlen (optable[i].in) == len +- && memcmp (optable[i].in, declp->b + 10, len) == 0) +- { +- string_clear (declp); +- string_append (declp, "operator"); +- string_append (declp, optable[i].out); +- string_append (declp, "="); +- break; +- } +- } +- } +- else +- { +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- int len = declp->p - declp->b - 3; +- if ((int) strlen (optable[i].in) == len +- && memcmp (optable[i].in, declp->b + 3, len) == 0) +- { +- string_clear (declp); +- string_append (declp, "operator"); +- string_append (declp, optable[i].out); +- break; +- } +- } +- } +- } +- else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 +- && strchr (cplus_markers, declp->b[4]) != NULL) +- { +- /* type conversion operator */ +- tem = declp->b + 5; +- if (do_type (work, &tem, &type)) +- { +- string_clear (declp); +- string_append (declp, "operator "); +- string_appends (declp, &type); +- string_delete (&type); +- } +- } +- else if (declp->b[0] == '_' && declp->b[1] == '_' +- && declp->b[2] == 'o' && declp->b[3] == 'p') +- { +- /* ANSI. */ +- /* type conversion operator. */ +- tem = declp->b + 4; +- if (do_type (work, &tem, &type)) +- { +- string_clear (declp); +- string_append (declp, "operator "); +- string_appends (declp, &type); +- string_delete (&type); +- } +- } +- else if (declp->b[0] == '_' && declp->b[1] == '_' +- && ISLOWER((unsigned char)declp->b[2]) +- && ISLOWER((unsigned char)declp->b[3])) +- { +- if (declp->b[4] == '\0') +- { +- /* Operator. */ +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- if (strlen (optable[i].in) == 2 +- && memcmp (optable[i].in, declp->b + 2, 2) == 0) +- { +- string_clear (declp); +- string_append (declp, "operator"); +- string_append (declp, optable[i].out); +- break; +- } +- } +- } +- else +- { +- if (declp->b[2] == 'a' && declp->b[5] == '\0') +- { +- /* Assignment. */ +- for (i = 0; i < ARRAY_SIZE (optable); i++) +- { +- if (strlen (optable[i].in) == 3 +- && memcmp (optable[i].in, declp->b + 2, 3) == 0) +- { +- string_clear (declp); +- string_append (declp, "operator"); +- string_append (declp, optable[i].out); +- break; +- } +- } +- } +- } +- } +- +- /* If a function name was obtained but it's not valid, we were not +- successful. */ +- if (LEN_STRING (declp) == 1 && declp->b[0] == '.') +- return 0; +- else +- return 1; +-} +- +-/* a mini string-handling package */ +- +-static void +-string_need (string *s, int n) +-{ +- int tem; +- +- if (s->b == NULL) +- { +- if (n < 32) +- { +- n = 32; +- } +- s->p = s->b = XNEWVEC (char, n); +- s->e = s->b + n; +- } +- else if (s->e - s->p < n) +- { +- tem = s->p - s->b; +- if (n > INT_MAX / 2 - tem) +- xmalloc_failed (INT_MAX); +- n += tem; +- n *= 2; +- s->b = XRESIZEVEC (char, s->b, n); +- s->p = s->b + tem; +- s->e = s->b + n; +- } +-} +- +-static void +-string_delete (string *s) +-{ +- if (s->b != NULL) +- { +- free (s->b); +- s->b = s->e = s->p = NULL; +- } +-} +- +-static void +-string_init (string *s) +-{ +- s->b = s->p = s->e = NULL; +-} +- +-static void +-string_clear (string *s) +-{ +- s->p = s->b; +-} +- +-#if 0 +- +-static int +-string_empty (string *s) +-{ +- return (s->b == s->p); +-} +- +-#endif +- +-static void +-string_append (string *p, const char *s) +-{ +- int n; +- if (s == NULL || *s == '\0') +- return; +- n = strlen (s); +- string_need (p, n); +- memcpy (p->p, s, n); +- p->p += n; +-} +- +-static void +-string_appends (string *p, string *s) +-{ +- int n; +- +- if (s->b != s->p) +- { +- n = s->p - s->b; +- string_need (p, n); +- memcpy (p->p, s->b, n); +- p->p += n; +- } +-} +- +-static void +-string_appendn (string *p, const char *s, int n) +-{ +- if (n != 0) +- { +- string_need (p, n); +- memcpy (p->p, s, n); +- p->p += n; +- } +-} +- +-static void +-string_prepend (string *p, const char *s) +-{ +- if (s != NULL && *s != '\0') +- { +- string_prependn (p, s, strlen (s)); +- } +-} +- +-static void +-string_prepends (string *p, string *s) +-{ +- if (s->b != s->p) +- { +- string_prependn (p, s->b, s->p - s->b); +- } +-} +- +-static void +-string_prependn (string *p, const char *s, int n) +-{ +- char *q; +- +- if (n != 0) +- { +- string_need (p, n); +- for (q = p->p - 1; q >= p->b; q--) +- { +- q[n] = q[0]; +- } +- memcpy (p->b, s, n); +- p->p += n; +- } +-} +- +-static void +-string_append_template_idx (string *s, int idx) +-{ +- char buf[INTBUF_SIZE + 1 /* 'T' */]; +- sprintf(buf, "T%d", idx); +- string_append (s, buf); +-} diff --git a/SOURCES/binutils-CVE-2018-12699-part5-PR28694.patch b/SOURCES/binutils-CVE-2018-12699-part5-PR28694.patch new file mode 100644 index 0000000..3effc60 --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part5-PR28694.patch @@ -0,0 +1,232 @@ +diff -rup binutils.orig.4/binutils/stabs.c binutils-2.30/binutils/stabs.c +--- binutils.orig.4/binutils/stabs.c 2024-10-29 14:31:49.044040165 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-10-29 14:35:01.106616133 +0000 +@@ -202,7 +202,7 @@ static debug_type stab_find_type (void * + static bfd_boolean stab_record_type + (void *, struct stab_handle *, const int *, debug_type); + static debug_type stab_xcoff_builtin_type +- (void *, struct stab_handle *, int); ++ (void *, struct stab_handle *, unsigned int); + static debug_type stab_find_tagged_type + (void *, struct stab_handle *, const char *, int, enum debug_type_kind); + static debug_type *stab_demangle_argtypes +@@ -3538,166 +3538,168 @@ stab_record_type (void *dhandle ATTRIBUT + + static debug_type + stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info, +- int typenum) ++ unsigned int typenum) + { + debug_type rettype; + const char *name; + +- if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT) ++ typenum = -typenum - 1; ++ if (typenum >= XCOFF_TYPE_COUNT) + { +- fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum); ++ fprintf (stderr, _("Unrecognized XCOFF type %d\n"), -typenum - 1); + return DEBUG_TYPE_NULL; + } +- if (info->xcoff_types[-typenum] != NULL) +- return info->xcoff_types[-typenum]; + +- switch (-typenum) ++ if (info->xcoff_types[typenum] != NULL) ++ return info->xcoff_types[typenum]; ++ ++ switch (typenum) + { +- case 1: ++ case 0: + /* The size of this and all the other types are fixed, defined + by the debugging format. */ + name = "int"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 2: ++ case 1: + name = "char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 3: ++ case 2: + name = "short"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 4: ++ case 3: + name = "long"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 5: ++ case 4: + name = "unsigned char"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; +- case 6: ++ case 5: + name = "signed char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 7: ++ case 6: + name = "unsigned short"; + rettype = debug_make_int_type (dhandle, 2, TRUE); + break; +- case 8: ++ case 7: + name = "unsigned int"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 9: ++ case 8: + name = "unsigned"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 10: ++ case 9: + name = "unsigned long"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; +- case 11: ++ case 10: + name = "void"; + rettype = debug_make_void_type (dhandle); + break; +- case 12: ++ case 11: + /* IEEE single precision (32 bit). */ + name = "float"; + rettype = debug_make_float_type (dhandle, 4); + break; +- case 13: ++ case 12: + /* IEEE double precision (64 bit). */ + name = "double"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 14: ++ case 13: + /* This is an IEEE double on the RS/6000, and different machines + with different sizes for "long double" should use different + negative type numbers. See stabs.texinfo. */ + name = "long double"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 15: ++ case 14: + name = "integer"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 16: ++ case 15: + name = "boolean"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 17: ++ case 16: + name = "short real"; + rettype = debug_make_float_type (dhandle, 4); + break; +- case 18: ++ case 17: + name = "real"; + rettype = debug_make_float_type (dhandle, 8); + break; +- case 19: ++ case 18: + /* FIXME */ + name = "stringptr"; + rettype = NULL; + break; +- case 20: ++ case 19: + /* FIXME */ + name = "character"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; +- case 21: ++ case 20: + name = "logical*1"; + rettype = debug_make_bool_type (dhandle, 1); + break; +- case 22: ++ case 21: + name = "logical*2"; + rettype = debug_make_bool_type (dhandle, 2); + break; +- case 23: ++ case 22: + name = "logical*4"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 24: ++ case 23: + name = "logical"; + rettype = debug_make_bool_type (dhandle, 4); + break; +- case 25: ++ case 24: + /* Complex type consisting of two IEEE single precision values. */ + name = "complex"; + rettype = debug_make_complex_type (dhandle, 8); + break; +- case 26: ++ case 25: + /* Complex type consisting of two IEEE double precision values. */ + name = "double complex"; + rettype = debug_make_complex_type (dhandle, 16); + break; +- case 27: ++ case 26: + name = "integer*1"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; +- case 28: ++ case 27: + name = "integer*2"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 29: ++ case 28: + name = "integer*4"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; +- case 30: ++ case 29: + /* FIXME */ + name = "wchar"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; +- case 31: ++ case 30: + name = "long long"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; +- case 32: ++ case 31: + name = "unsigned long long"; + rettype = debug_make_int_type (dhandle, 8, TRUE); + break; +- case 33: ++ case 32: + name = "logical*8"; + rettype = debug_make_bool_type (dhandle, 8); + break; +- case 34: ++ case 33: + name = "integer*8"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; +@@ -3706,9 +3708,7 @@ stab_xcoff_builtin_type (void *dhandle, + } + + rettype = debug_name_type (dhandle, name, rettype); +- +- info->xcoff_types[-typenum] = rettype; +- ++ info->xcoff_types[typenum] = rettype; + return rettype; + } + diff --git a/SOURCES/binutils-CVE-2018-12699-part6-PR28862.patch b/SOURCES/binutils-CVE-2018-12699-part6-PR28862.patch new file mode 100644 index 0000000..1f49770 --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part6-PR28862.patch @@ -0,0 +1,33 @@ +# Commit 481153777e278b71e694fd2db6b897f7a9e3dcb8 fixing PR 28862 +# +# From: Alan Modra +# +# I have no info on the format of a "SUNPRO C++ Namespace" stab, so am +# relying on the previous code being correct in parsing these stabs. +# Just don't allow NULs anywhere in the stab. +# +# PR 28862 +# * stabs.c (parse_stab_string): Don't overrun buffer when parsing +# 'Y' stab. +--- binutils.orig/binutils/stabs.c 2024-11-06 17:39:57.460250962 +0000 ++++ binutils-2.30/binutils/stabs.c 2024-11-06 17:41:32.293848603 +0000 +@@ -1138,15 +1138,13 @@ parse_stab_string (void *dhandle, struct + case 'Y': + /* SUNPro C++ Namespace =Yn0. */ + /* Skip the namespace mapping, as it is not used now. */ +- if (*(++p) == 'n' && *(++p) == '0') ++ if (*p++ != 0 && *p++ == 'n' && *p++ == '0') + { + /* =Yn0name; */ +- while (*p != ';') ++ while (*p && *p != ';') + ++p; +- ++p; +- /* There is a potential resource leak here, but it is not important. */ +- /* coverity[leaked_storage: FALSE] */ +- return TRUE; ++ if (*p) ++ return TRUE; + } + /* TODO SUNPro C++ support: + Support default arguments after F,P parameters diff --git a/SOURCES/binutils-CVE-2018-12699-part7-PR28718.patch b/SOURCES/binutils-CVE-2018-12699-part7-PR28718.patch new file mode 100644 index 0000000..0c1f735 --- /dev/null +++ b/SOURCES/binutils-CVE-2018-12699-part7-PR28718.patch @@ -0,0 +1,158 @@ +# This is a merge of four commits to fix a stack overflow bug: +# +# From af4004d1da135610ab931e04a3ba2c9124defbd7 Mon Sep 17 00:00:00 2001 +# From: Nick Clifton +# Date: Thu, 6 Jan 2022 16:37:26 +0000 +# Subject: [PATCH] Fix a stack exhaustion bug parsing malicious STABS format +# debug information. +# +# PR 28718 +# * debug.c (debug_write_type): Allow for malicious recursion via +# indirect debug types. +# +# From 0e9f1c04b9572920c7f940203a67d5af3f6c19f6 Mon Sep 17 00:00:00 2001 +# From: Pavel Mayorov +# Date: Fri, 7 Jan 2022 12:34:37 +0000 +# Subject: [PATCH] Revert previous delta to debug.c. Replace with patch to +# reject indirect types that point to indirect types. +# +# PR 28718 +# * dwarf.c: Revert previous delta. +# (debug_get_real_type): Reject indirect types that point to +# indirect types. +# (debug_get_type_name, debug_get_type_size, debug_write_type): +# Likewise. +# +# From 55a75aae9d971d3d0f49884e3954ac4794559542 Mon Sep 17 00:00:00 2001 +# From: Alan Modra +# Date: Tue, 9 May 2023 17:11:46 +0930 +# Subject: [PATCH] stack overflow in debug_write_type +# +# Another fuzzer attack. This one was a "set" with elements using an +# indirect type pointing back at the set. The existing recursion check +# only prevented simple recursion. +# +# * debug.c (struct debug_type_s): Add mark. +# (debug_write_type): Set mark and check before recursing into +# indirect types. +# +# From 6109320673fe30163b5d00d9e3a7f4e77befb22a Mon Sep 17 00:00:00 2001 +# From: Alan Modra +# Date: Wed, 10 May 2023 23:05:00 +0930 +# Subject: [PATCH] Re: stack overflow in debug_write_type +# +# Apparently u.kindirect->slot can point at a NULL. +# +# * debug.c (debug_write_type): Don't segfault on NULL indirect. + +--- binutils.orig/binutils/debug.c 2024-11-06 17:39:57.452250912 +0000 ++++ binutils-2.30/binutils/debug.c 2024-11-06 17:44:37.951018606 +0000 +@@ -2483,8 +2483,22 @@ debug_write_type (struct debug_handle *i + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) + return (*fns->empty_type) (fhandle); +- return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, +- name); ++ /* PR 28718: Allow for malicious recursion. */ ++ { ++ static int recursion_depth = 0; ++ bfd_boolean result; ++ ++ if (recursion_depth > 256) ++ { ++ debug_error (_("debug_write_type: too many levels of nested indirection")); ++ return FALSE; ++ } ++ ++ recursion_depth; ++ result = debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, ++ name); ++ -- recursion_depth; ++ return result; ++ } + case DEBUG_KIND_VOID: + return (*fns->void_type) (fhandle); + case DEBUG_KIND_INT: +--- binutils.orig/binutils/debug.c 2024-11-07 12:05:27.049161875 +0000 ++++ binutils-2.30/binutils/debug.c 2024-11-07 12:25:03.616783102 +0000 +@@ -102,6 +102,8 @@ struct debug_type_s + enum debug_type_kind kind; + /* Size of type (0 if not known). */ + unsigned int size; ++ /* Used by debug_write to stop DEBUG_KIND_INDIRECT infinite recursion. */ ++ unsigned int mark; + /* Type which is a pointer to this type. */ + debug_type pointer; + /* Tagged union with additional information about the type. */ +@@ -2065,7 +2067,9 @@ debug_get_real_type (void *handle, debug + /* The default case is just here to avoid warnings. */ + default: + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_real_type (handle, *type->u.kindirect->slot, &rl); + return type; + case DEBUG_KIND_NAMED: +@@ -2095,7 +2099,9 @@ debug_get_type_name (void *handle, debug + { + if (type->kind == DEBUG_KIND_INDIRECT) + { +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_type_name (handle, *type->u.kindirect->slot); + return type->u.kindirect->tag; + } +@@ -2124,7 +2130,9 @@ debug_get_type_size (void *handle, debug + default: + return 0; + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot != NULL) ++ /* A valid non-self-referencing indirect type. */ ++ if (*type->u.kindirect->slot != NULL ++ && *type->u.kindirect->slot != type) + return debug_get_type_size (handle, *type->u.kindirect->slot); + return 0; + case DEBUG_KIND_NAMED: +@@ -2419,6 +2427,9 @@ debug_write_type (struct debug_handle *i + int is; + const char *tag = NULL; + ++ /* Mark the type so that we don't define a type in terms of itself. */ ++ type->mark = info->mark; ++ + /* If we have a name for this type, just output it. We only output + typedef names after they have been defined. We output type tags + whenever we are not actually defining them. */ +@@ -2481,24 +2492,12 @@ debug_write_type (struct debug_handle *i + debug_error (_("debug_write_type: illegal type encountered")); + return FALSE; + case DEBUG_KIND_INDIRECT: +- if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) ++ /* Prevent infinite recursion. */ ++ if (*type->u.kindirect->slot != DEBUG_TYPE_NULL ++ && (*type->u.kindirect->slot)->mark == info->mark) + return (*fns->empty_type) (fhandle); +- /* PR 28718: Allow for malicious recursion. */ +- { +- static int recursion_depth = 0; +- bfd_boolean result; +- +- if (recursion_depth > 256) +- { +- debug_error (_("debug_write_type: too many levels of nested indirection")); +- return FALSE; +- } +- ++ recursion_depth; +- result = debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, +- name); +- -- recursion_depth; +- return result; +- } ++ return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, ++ name); + case DEBUG_KIND_VOID: + return (*fns->void_type) (fhandle); + case DEBUG_KIND_INT: diff --git a/SPECS/binutils.spec b/SPECS/binutils.spec index f2ef9e1..a3f3731 100644 --- a/SPECS/binutils.spec +++ b/SPECS/binutils.spec @@ -43,7 +43,7 @@ Summary: A GNU collection of binary utilities Name: binutils%{?name_cross}%{?_with_debug:-debug} Version: 2.30 -Release: 123%{?dist} +Release: 125%{?dist} License: GPLv3+ URL: https://sourceware.org/binutils @@ -638,6 +638,35 @@ Patch103: binutils-memory-access-when-parsing-an-elf-file.patch # Purpose: Add support for DWARF-5 offset tables. # Lifetime: 2.40 Patch104: binutils-DW_FORM_strx.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch105: binutils-CVE-2018-12699-part1-PR22955.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch106: binutils-CVE-2018-12699-part2-PR87861.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch107: binutils-CVE-2018-12699-part3-PR22957.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch108: binutils-CVE-2018-12699-part4-PR16615.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch109: binutils-CVE-2018-12699-part5-PR28694.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch110: binutils-CVE-2018-12699-part6-PR28862.patch + +# Purpose: Fixes an illegal memory access parsing corrupt A.OUT files. +# Lifetime: 2.35 +Patch111: binutils-CVE-2018-12699-part7-PR28718.patch + #---------------------------------------------------------------------------- Provides: bundled(libiberty) @@ -879,6 +908,13 @@ using libelf instead of BFD. %patch102 -p1 %patch103 -p1 %patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 # We cannot run autotools as there is an exact requirement of autoconf-2.59. # FIXME - this is no longer true. Maybe try reinstating autotool use ? @@ -1328,6 +1364,12 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Wed Nov 06 2024 Nick Clifton - 2.30-125 +- Fix illegal memory accesses when parsing corrupt a.out format files. (RHEL-64927) + +* Tue Oct 29 2024 Nick Clifton - 2.30-124 +- Fix illegal memory accesses when parsing corrupt a.out format files. (RHEL-64927) + * Tue Jul 25 2023 Nick Clifton - 2.30-123 - Extend support for DWARF-5 offset tables as generated by Clang++. (#2222697)