1 /* Demangler for the Rust programming language
2 Copyright (C) 2016-2024 Free Software Foundation, Inc.
3 Written by David Tolnay (dtolnay@gmail.com).
4 Rewritten by Eduard-Mihai Burtescu (eddyb@lyken.rs) for v0 support.
6 This file is part of the libiberty library.
7 Libiberty is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 In addition to the permissions in the GNU Library General Public
13 License, the Free Software Foundation gives you unlimited permission
14 to link the compiled version of this file into combinations with other
15 programs, and to distribute those combinations without any restriction
16 coming from the use of this file. (The Library Public License
17 restrictions do apply in other respects; for example, they cover
18 modification of the file, and distribution when not linked into a
21 Libiberty is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 Library General Public License for more details.
26 You should have received a copy of the GNU Library General Public
27 License along with libiberty; see the file COPYING.LIB.
28 If not, see <http://www.gnu.org/licenses/>. */
35 #include "safe-ctype.h"
38 #include <sys/types.h>
46 extern size_t strlen(const char *s
);
47 extern int strncmp(const char *s1
, const char *s2
, size_t n
);
48 extern void *memset(void *s
, int c
, size_t n
);
52 #include "libiberty.h"
59 void *callback_opaque
;
60 demangle_callbackref callback
;
62 /* Position of the next character to read from the symbol. */
65 /* Non-zero if any error occurred. */
68 /* Non-zero if nothing should be printed. */
69 int skipping_printing
;
71 /* Non-zero if printing should be verbose (e.g. include hashes). */
74 /* Rust mangling version, with legacy mangling being -1. */
77 /* Recursion depth. */
78 unsigned int recursion
;
79 /* Maximum number of times demangle_path may be called recursively. */
80 #define RUST_MAX_RECURSION_COUNT 1024
81 #define RUST_NO_RECURSION_LIMIT ((unsigned int) -1)
83 uint64_t bound_lifetime_depth
;
86 /* Parsing functions. */
89 peek (const struct rust_demangler
*rdm
)
91 if (rdm
->next
< rdm
->sym_len
)
92 return rdm
->sym
[rdm
->next
];
97 eat (struct rust_demangler
*rdm
, char c
)
109 next (struct rust_demangler
*rdm
)
120 parse_integer_62 (struct rust_demangler
*rdm
)
129 while (!eat (rdm
, '_') && !rdm
->errored
)
135 else if (ISLOWER (c
))
137 else if (ISUPPER (c
))
138 x
+= 10 + 26 + (c
- 'A');
149 parse_opt_integer_62 (struct rust_demangler
*rdm
, char tag
)
153 return 1 + parse_integer_62 (rdm
);
157 parse_disambiguator (struct rust_demangler
*rdm
)
159 return parse_opt_integer_62 (rdm
, 's');
163 parse_hex_nibbles (struct rust_demangler
*rdm
, uint64_t *value
)
171 while (!eat (rdm
, '_'))
178 else if (c
>= 'a' && c
<= 'f')
179 *value
|= 10 + (c
- 'a');
191 struct rust_mangled_ident
193 /* ASCII part of the identifier. */
197 /* Punycode insertion codes for Unicode codepoints, if any. */
198 const char *punycode
;
202 static struct rust_mangled_ident
203 parse_ident (struct rust_demangler
*rdm
)
208 struct rust_mangled_ident ident
;
212 ident
.punycode
= NULL
;
213 ident
.punycode_len
= 0;
215 if (rdm
->version
!= -1)
216 is_punycode
= eat (rdm
, 'u');
227 while (ISDIGIT (peek (rdm
)))
228 len
= len
* 10 + (next (rdm
) - '0');
230 /* Skip past the optional `_` separator (v0). */
231 if (rdm
->version
!= -1)
236 /* Check for overflows. */
237 if ((start
> rdm
->next
) || (rdm
->next
> rdm
->sym_len
))
243 ident
.ascii
= rdm
->sym
+ start
;
244 ident
.ascii_len
= len
;
248 ident
.punycode_len
= 0;
249 while (ident
.ascii_len
> 0)
253 /* The last '_' is a separator between ascii & punycode. */
254 if (ident
.ascii
[ident
.ascii_len
] == '_')
257 ident
.punycode_len
++;
259 if (!ident
.punycode_len
)
264 ident
.punycode
= ident
.ascii
+ (len
- ident
.punycode_len
);
267 if (ident
.ascii_len
== 0)
273 /* Printing functions. */
276 print_str (struct rust_demangler
*rdm
, const char *data
, size_t len
)
278 if (!rdm
->errored
&& !rdm
->skipping_printing
)
279 rdm
->callback (data
, len
, rdm
->callback_opaque
);
282 #define PRINT(s) print_str (rdm, s, strlen (s))
285 print_uint64 (struct rust_demangler
*rdm
, uint64_t x
)
288 snprintf (s
, 21, "%" PRIu64
, x
);
293 print_uint64_hex (struct rust_demangler
*rdm
, uint64_t x
)
296 snprintf (s
, 17, "%" PRIx64
, x
);
300 /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
302 decode_lower_hex_nibble (char nibble
)
304 if ('0' <= nibble
&& nibble
<= '9')
306 if ('a' <= nibble
&& nibble
<= 'f')
307 return 0xa + (nibble
- 'a');
311 /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
313 decode_legacy_escape (const char *e
, size_t len
, size_t *out_len
)
316 size_t escape_len
= 0;
317 int lo_nibble
= -1, hi_nibble
= -1;
319 if (len
< 3 || e
[0] != '$')
335 if (e
[0] == 'S' && e
[1] == 'P')
337 else if (e
[0] == 'B' && e
[1] == 'P')
339 else if (e
[0] == 'R' && e
[1] == 'F')
341 else if (e
[0] == 'L' && e
[1] == 'T')
343 else if (e
[0] == 'G' && e
[1] == 'T')
345 else if (e
[0] == 'L' && e
[1] == 'P')
347 else if (e
[0] == 'R' && e
[1] == 'P')
349 else if (e
[0] == 'u' && len
> 3)
353 hi_nibble
= decode_lower_hex_nibble (e
[1]);
356 lo_nibble
= decode_lower_hex_nibble (e
[2]);
360 /* Only allow non-control ASCII characters. */
363 c
= (hi_nibble
<< 4) | lo_nibble
;
369 if (!c
|| len
<= escape_len
|| e
[escape_len
] != '$')
372 *out_len
= 2 + escape_len
;
377 print_ident (struct rust_demangler
*rdm
, struct rust_mangled_ident ident
)
381 size_t len
, cap
, punycode_pos
, j
;
382 /* Punycode parameters and state. */
384 size_t base
, t_min
, t_max
, skew
, damp
, bias
, i
;
385 size_t delta
, w
, k
, t
;
387 if (rdm
->errored
|| rdm
->skipping_printing
)
390 if (rdm
->version
== -1)
392 /* Ignore leading underscores preceding escape sequences.
393 The mangler inserts an underscore to make sure the
394 identifier begins with a XID_Start character. */
395 if (ident
.ascii_len
>= 2 && ident
.ascii
[0] == '_'
396 && ident
.ascii
[1] == '$')
402 while (ident
.ascii_len
> 0)
404 /* Handle legacy escape sequences ("$...$", ".." or "."). */
405 if (ident
.ascii
[0] == '$')
408 = decode_legacy_escape (ident
.ascii
, ident
.ascii_len
, &len
);
410 print_str (rdm
, &unescaped
, 1);
413 /* Unexpected escape sequence, print the rest verbatim. */
414 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
418 else if (ident
.ascii
[0] == '.')
420 if (ident
.ascii_len
>= 2 && ident
.ascii
[1] == '.')
422 /* ".." becomes "::" */
434 /* Print everything before the next escape sequence, at once. */
435 for (len
= 0; len
< ident
.ascii_len
; len
++)
436 if (ident
.ascii
[len
] == '$' || ident
.ascii
[len
] == '.')
439 print_str (rdm
, ident
.ascii
, len
);
443 ident
.ascii_len
-= len
;
451 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
457 while (cap
< ident
.ascii_len
)
460 /* Check for overflows. */
461 if ((cap
* 4) / 4 != cap
)
468 /* Store the output codepoints as groups of 4 UTF-8 bytes. */
469 out
= (uint8_t *)malloc (cap
* 4);
476 /* Populate initial output from ASCII fragment. */
477 for (len
= 0; len
< ident
.ascii_len
; len
++)
483 p
[3] = ident
.ascii
[len
];
486 /* Punycode parameters and initial state. */
497 while (punycode_pos
< ident
.punycode_len
)
499 /* Read one delta value. */
506 t
= k
< bias
? 0 : (k
- bias
);
512 if (punycode_pos
>= ident
.punycode_len
)
514 d
= ident
.punycode
[punycode_pos
++];
518 else if (ISDIGIT (d
))
531 /* Compute the new insert position and character. */
537 /* Ensure enough space is available. */
541 /* Check for overflows. */
542 if ((cap
* 4) / 4 != cap
|| cap
< len
)
548 p
= (uint8_t *)realloc (out
, cap
* 4);
556 /* Move the characters after the insert position. */
558 memmove (p
+ 4, p
, (len
- i
- 1) * 4);
560 /* Insert the new character, as UTF-8 bytes. */
561 p
[0] = c
>= 0x10000 ? 0xf0 | (c
>> 18) : 0;
562 p
[1] = c
>= 0x800 ? (c
< 0x10000 ? 0xe0 : 0x80) | ((c
>> 12) & 0x3f) : 0;
563 p
[2] = (c
< 0x800 ? 0xc0 : 0x80) | ((c
>> 6) & 0x3f);
564 p
[3] = 0x80 | (c
& 0x3f);
566 /* If there are no more deltas, decoding is complete. */
567 if (punycode_pos
== ident
.punycode_len
)
572 /* Perform bias adaptation. */
576 delta
+= delta
/ len
;
578 while (delta
> ((base
- t_min
) * t_max
) / 2)
580 delta
/= base
- t_min
;
583 bias
= k
+ ((base
- t_min
+ 1) * delta
) / (delta
+ skew
);
586 /* Remove all the 0 bytes to leave behind an UTF-8 string. */
587 for (i
= 0, j
= 0; i
< len
* 4; i
++)
591 print_str (rdm
, (const char *)out
, j
);
597 /* Print the lifetime according to the previously decoded index.
598 An index of `0` always refers to `'_`, but starting with `1`,
599 indices refer to late-bound lifetimes introduced by a binder. */
601 print_lifetime_from_index (struct rust_demangler
*rdm
, uint64_t lt
)
613 depth
= rdm
->bound_lifetime_depth
- lt
;
614 /* Try to print lifetimes alphabetically first. */
618 print_str (rdm
, &c
, 1);
622 /* Use `'_123` after running out of letters. */
624 print_uint64 (rdm
, depth
);
628 /* Demangling functions. */
630 static void demangle_binder (struct rust_demangler
*rdm
);
631 static void demangle_path (struct rust_demangler
*rdm
, int in_value
);
632 static void demangle_generic_arg (struct rust_demangler
*rdm
);
633 static void demangle_type (struct rust_demangler
*rdm
);
634 static int demangle_path_maybe_open_generics (struct rust_demangler
*rdm
);
635 static void demangle_dyn_trait (struct rust_demangler
*rdm
);
636 static void demangle_const (struct rust_demangler
*rdm
);
637 static void demangle_const_uint (struct rust_demangler
*rdm
);
638 static void demangle_const_int (struct rust_demangler
*rdm
);
639 static void demangle_const_bool (struct rust_demangler
*rdm
);
640 static void demangle_const_char (struct rust_demangler
*rdm
);
642 /* Optionally enter a binder ('G') for late-bound lifetimes,
643 printing e.g. `for<'a, 'b> `, and make those lifetimes visible
644 to the caller (via depth level, which the caller should reset). */
646 demangle_binder (struct rust_demangler
*rdm
)
648 uint64_t i
, bound_lifetimes
;
653 bound_lifetimes
= parse_opt_integer_62 (rdm
, 'G');
654 if (bound_lifetimes
> 0)
657 for (i
= 0; i
< bound_lifetimes
; i
++)
661 rdm
->bound_lifetime_depth
++;
662 print_lifetime_from_index (rdm
, 1);
669 demangle_path (struct rust_demangler
*rdm
, int in_value
)
672 int was_skipping_printing
;
673 size_t i
, backref
, old_next
;
675 struct rust_mangled_ident name
;
680 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
683 if (rdm
->recursion
> RUST_MAX_RECURSION_COUNT
)
684 /* FIXME: There ought to be a way to report
685 that the recursion limit has been reached. */
689 switch (tag
= next (rdm
))
692 dis
= parse_disambiguator (rdm
);
693 name
= parse_ident (rdm
);
695 print_ident (rdm
, name
);
699 print_uint64_hex (rdm
, dis
);
705 if (!ISLOWER (ns
) && !ISUPPER (ns
))
708 demangle_path (rdm
, in_value
);
710 dis
= parse_disambiguator (rdm
);
711 name
= parse_ident (rdm
);
715 /* Special namespaces, like closures and shims. */
726 print_str (rdm
, &ns
, 1);
728 if (name
.ascii
|| name
.punycode
)
731 print_ident (rdm
, name
);
734 print_uint64 (rdm
, dis
);
739 /* Implementation-specific/unspecified namespaces. */
741 if (name
.ascii
|| name
.punycode
)
744 print_ident (rdm
, name
);
750 /* Ignore the `impl`'s own path.*/
751 parse_disambiguator (rdm
);
752 was_skipping_printing
= rdm
->skipping_printing
;
753 rdm
->skipping_printing
= 1;
754 demangle_path (rdm
, in_value
);
755 rdm
->skipping_printing
= was_skipping_printing
;
763 demangle_path (rdm
, 0);
768 demangle_path (rdm
, in_value
);
772 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
776 demangle_generic_arg (rdm
);
781 backref
= parse_integer_62 (rdm
);
782 if (!rdm
->skipping_printing
)
784 old_next
= rdm
->next
;
786 demangle_path (rdm
, in_value
);
787 rdm
->next
= old_next
;
798 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
803 demangle_generic_arg (struct rust_demangler
*rdm
)
808 lt
= parse_integer_62 (rdm
);
809 print_lifetime_from_index (rdm
, lt
);
811 else if (eat (rdm
, 'K'))
812 demangle_const (rdm
);
818 basic_type (char tag
)
871 demangle_type (struct rust_demangler
*rdm
)
874 size_t i
, old_next
, backref
;
875 uint64_t lt
, old_bound_lifetime_depth
;
877 struct rust_mangled_ident abi
;
884 basic
= basic_type (tag
);
891 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
894 if (rdm
->recursion
> RUST_MAX_RECURSION_COUNT
)
895 /* FIXME: There ought to be a way to report
896 that the recursion limit has been reached. */
911 lt
= parse_integer_62 (rdm
);
914 print_lifetime_from_index (rdm
, lt
);
938 demangle_const (rdm
);
944 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
955 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
956 demangle_binder (rdm
);
970 abi
= parse_ident (rdm
);
971 if (!abi
.ascii
|| abi
.punycode
)
980 /* If the ABI had any `-`, they were replaced with `_`,
981 so the parts between `_` have to be re-joined with `-`. */
982 for (i
= 0; i
< abi
.ascii_len
; i
++)
984 if (abi
.ascii
[i
] == '_')
986 print_str (rdm
, abi
.ascii
, i
);
989 abi
.ascii_len
-= i
+ 1;
993 print_str (rdm
, abi
.ascii
, abi
.ascii_len
);
999 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1003 demangle_type (rdm
);
1009 /* Skip printing the return type if it's 'u', i.e. `()`. */
1014 demangle_type (rdm
);
1017 /* Restore `bound_lifetime_depth` to outside the binder. */
1019 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
1024 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
1025 demangle_binder (rdm
);
1027 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1031 demangle_dyn_trait (rdm
);
1034 /* Restore `bound_lifetime_depth` to outside the binder. */
1035 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
1037 if (!eat (rdm
, 'L'))
1042 lt
= parse_integer_62 (rdm
);
1046 print_lifetime_from_index (rdm
, lt
);
1050 backref
= parse_integer_62 (rdm
);
1051 if (!rdm
->skipping_printing
)
1053 old_next
= rdm
->next
;
1054 rdm
->next
= backref
;
1055 demangle_type (rdm
);
1056 rdm
->next
= old_next
;
1060 /* Go back to the tag, so `demangle_path` also sees it. */
1062 demangle_path (rdm
, 0);
1065 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
1069 /* A trait in a trait object may have some "existential projections"
1070 (i.e. associated type bindings) after it, which should be printed
1071 in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1072 To this end, this method will keep the `<...>` of an 'I' path
1073 open, by omitting the `>`, and return `Ok(true)` in that case. */
1075 demangle_path_maybe_open_generics (struct rust_demangler
*rdm
)
1078 size_t i
, old_next
, backref
;
1085 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
1088 if (rdm
->recursion
> RUST_MAX_RECURSION_COUNT
)
1090 /* FIXME: There ought to be a way to report
1091 that the recursion limit has been reached. */
1099 backref
= parse_integer_62 (rdm
);
1100 if (!rdm
->skipping_printing
)
1102 old_next
= rdm
->next
;
1103 rdm
->next
= backref
;
1104 open
= demangle_path_maybe_open_generics (rdm
);
1105 rdm
->next
= old_next
;
1108 else if (eat (rdm
, 'I'))
1110 demangle_path (rdm
, 0);
1113 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1117 demangle_generic_arg (rdm
);
1121 demangle_path (rdm
, 0);
1124 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
1131 demangle_dyn_trait (struct rust_demangler
*rdm
)
1134 struct rust_mangled_ident name
;
1139 open
= demangle_path_maybe_open_generics (rdm
);
1141 while (eat (rdm
, 'p'))
1149 name
= parse_ident (rdm
);
1150 print_ident (rdm
, name
);
1152 demangle_type (rdm
);
1160 demangle_const (struct rust_demangler
*rdm
)
1163 size_t old_next
, backref
;
1168 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
1171 if (rdm
->recursion
> RUST_MAX_RECURSION_COUNT
)
1172 /* FIXME: There ought to be a way to report
1173 that the recursion limit has been reached. */
1179 backref
= parse_integer_62 (rdm
);
1180 if (!rdm
->skipping_printing
)
1182 old_next
= rdm
->next
;
1183 rdm
->next
= backref
;
1184 demangle_const (rdm
);
1185 rdm
->next
= old_next
;
1190 ty_tag
= next (rdm
);
1198 /* Unsigned integer types. */
1205 demangle_const_uint (rdm
);
1208 /* Signed integer types. */
1215 demangle_const_int (rdm
);
1220 demangle_const_bool (rdm
);
1225 demangle_const_char (rdm
);
1232 if (!rdm
->errored
&& rdm
->verbose
)
1235 PRINT (basic_type (ty_tag
));
1242 if (rdm
->recursion
!= RUST_NO_RECURSION_LIMIT
)
1247 demangle_const_uint (struct rust_demangler
*rdm
)
1255 hex_len
= parse_hex_nibbles (rdm
, &value
);
1259 /* Print anything that doesn't fit in `uint64_t` verbatim. */
1261 print_str (rdm
, rdm
->sym
+ (rdm
->next
- hex_len
), hex_len
);
1263 else if (hex_len
> 0)
1264 print_uint64 (rdm
, value
);
1270 demangle_const_int (struct rust_demangler
*rdm
)
1274 demangle_const_uint (rdm
);
1278 demangle_const_bool (struct rust_demangler
*rdm
)
1282 if (parse_hex_nibbles (rdm
, &value
) != 1)
1290 else if (value
== 1)
1297 demangle_const_char (struct rust_demangler
*rdm
)
1302 hex_len
= parse_hex_nibbles (rdm
, &value
);
1304 if (hex_len
== 0 || hex_len
> 8)
1310 /* Match Rust's character "debug" output as best as we can. */
1314 else if (value
== '\r')
1316 else if (value
== '\n')
1318 else if (value
> ' ' && value
< '~')
1320 /* Rust also considers many non-ASCII codepoints to be printable, but
1321 that logic is not easily ported to C. */
1323 print_str (rdm
, &c
, 1);
1328 print_uint64_hex (rdm
, value
);
1334 /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
1335 The hex digits must contain at least 5 distinct digits. */
1337 is_legacy_prefixed_hash (struct rust_mangled_ident ident
)
1343 if (ident
.ascii_len
!= 17 || ident
.ascii
[0] != 'h')
1347 for (i
= 0; i
< 16; i
++)
1349 nibble
= decode_lower_hex_nibble (ident
.ascii
[1 + i
]);
1352 seen
|= (uint16_t)1 << nibble
;
1355 /* Count how many distinct digits were seen. */
1368 rust_demangle_callback (const char *mangled
, int options
,
1369 demangle_callbackref callback
, void *opaque
)
1372 struct rust_demangler rdm
;
1373 struct rust_mangled_ident ident
;
1378 rdm
.callback_opaque
= opaque
;
1379 rdm
.callback
= callback
;
1383 rdm
.skipping_printing
= 0;
1384 rdm
.verbose
= (options
& DMGL_VERBOSE
) != 0;
1386 rdm
.recursion
= (options
& DMGL_NO_RECURSE_LIMIT
) ? RUST_NO_RECURSION_LIMIT
: 0;
1387 rdm
.bound_lifetime_depth
= 0;
1389 /* Rust symbols always start with _R (v0) or _ZN (legacy). */
1390 if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'R')
1392 else if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'Z' && rdm
.sym
[2] == 'N')
1400 /* Paths (v0) always start with uppercase characters. */
1401 if (rdm
.version
!= -1 && !ISUPPER (rdm
.sym
[0]))
1404 /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
1405 for (p
= rdm
.sym
; *p
; p
++)
1407 /* Rust v0 symbols can have '.' suffixes, ignore those. */
1408 if (rdm
.version
== 0 && *p
== '.')
1413 if (*p
== '_' || ISALNUM (*p
))
1416 /* Legacy Rust symbols can also contain [.:$] characters.
1417 Or @ in the .suffix (which will be skipped, see below). */
1418 if (rdm
.version
== -1 && (*p
== '$' || *p
== '.' || *p
== ':'
1425 /* Legacy Rust symbols need to be handled separately. */
1426 if (rdm
.version
== -1)
1428 /* Legacy Rust symbols always end with E. But can be followed by a
1429 .suffix (which we want to ignore). */
1431 while (rdm
.sym_len
> 0 &&
1432 !(dot_suffix
&& rdm
.sym
[rdm
.sym_len
- 1] == 'E'))
1434 dot_suffix
= rdm
.sym
[rdm
.sym_len
- 1] == '.';
1438 if (!(rdm
.sym_len
> 0 && rdm
.sym
[rdm
.sym_len
- 1] == 'E'))
1442 /* Legacy Rust symbols also always end with a path segment
1443 that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
1444 This early check, before any parse_ident calls, should
1445 quickly filter out most C++ symbols unrelated to Rust. */
1446 if (!(rdm
.sym_len
> 19
1447 && !memcmp (&rdm
.sym
[rdm
.sym_len
- 19], "17h", 3)))
1452 ident
= parse_ident (&rdm
);
1453 if (rdm
.errored
|| !ident
.ascii
)
1456 while (rdm
.next
< rdm
.sym_len
);
1458 /* The last path segment should be the hash. */
1459 if (!is_legacy_prefixed_hash (ident
))
1462 /* Reset the state for a second pass, to print the symbol. */
1464 if (!rdm
.verbose
&& rdm
.sym_len
> 19)
1466 /* Hide the last segment, containing the hash, if not verbose. */
1473 print_str (&rdm
, "::", 2);
1475 ident
= parse_ident (&rdm
);
1476 print_ident (&rdm
, ident
);
1478 while (rdm
.next
< rdm
.sym_len
);
1482 demangle_path (&rdm
, 1);
1484 /* Skip instantiating crate. */
1485 if (!rdm
.errored
&& rdm
.next
< rdm
.sym_len
)
1487 rdm
.skipping_printing
= 1;
1488 demangle_path (&rdm
, 0);
1491 /* It's an error to not reach the end. */
1492 rdm
.errored
|= rdm
.next
!= rdm
.sym_len
;
1495 return !rdm
.errored
;
1498 /* Growable string buffers. */
1508 str_buf_reserve (struct str_buf
*buf
, size_t extra
)
1510 size_t available
, min_new_cap
, new_cap
;
1513 /* Allocation failed before. */
1517 available
= buf
->cap
- buf
->len
;
1519 if (extra
<= available
)
1522 min_new_cap
= buf
->cap
+ (extra
- available
);
1524 /* Check for overflows. */
1525 if (min_new_cap
< buf
->cap
)
1536 /* Double capacity until sufficiently large. */
1537 while (new_cap
< min_new_cap
)
1541 /* Check for overflows. */
1542 if (new_cap
< buf
->cap
)
1549 new_ptr
= (char *)realloc (buf
->ptr
, new_cap
);
1550 if (new_ptr
== NULL
)
1566 str_buf_append (struct str_buf
*buf
, const char *data
, size_t len
)
1568 str_buf_reserve (buf
, len
);
1572 memcpy (buf
->ptr
+ buf
->len
, data
, len
);
1577 str_buf_demangle_callback (const char *data
, size_t len
, void *opaque
)
1579 str_buf_append ((struct str_buf
*)opaque
, data
, len
);
1583 rust_demangle (const char *mangled
, int options
)
1593 success
= rust_demangle_callback (mangled
, options
,
1594 str_buf_demangle_callback
, &out
);
1602 str_buf_append (&out
, "\0", 1);