1 /* Demangler for the Rust programming language
2 Copyright (C) 2016-2021 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/>. */
31 #if 0 /* in valgrind */
35 #endif /* ! in valgrind */
37 #if 0 /* in valgrind */
38 #include "safe-ctype.h"
39 #endif /* ! in valgrind */
41 #if 0 /* in valgrind */
43 #include <sys/types.h>
47 #endif /* ! in valgrind */
49 #if 0 /* in valgrind */
53 extern size_t strlen(const char *s
);
54 extern int strncmp(const char *s1
, const char *s2
, size_t n
);
55 extern void *memset(void *s
, int c
, size_t n
);
57 #endif /* ! in valgrind */
59 #if 0 /* in valgrind */
61 #include "libiberty.h"
62 #endif /* ! in valgrind */
64 #include "vg_libciface.h"
68 #include "safe-ctype.h"
70 typedef UChar
uint8_t;
72 typedef UShort
uint16_t;
73 typedef Short
int16_t;
74 typedef UInt
uint32_t;
76 typedef ULong
uint64_t;
86 void *callback_opaque
;
87 demangle_callbackref callback
;
89 /* Position of the next character to read from the symbol. */
92 /* Non-zero if any error occurred. */
95 /* Non-zero if nothing should be printed. */
96 int skipping_printing
;
98 /* Non-zero if printing should be verbose (e.g. include hashes). */
101 /* Rust mangling version, with legacy mangling being -1. */
104 uint64_t bound_lifetime_depth
;
107 /* Parsing functions. */
110 peek (const struct rust_demangler
*rdm
)
112 if (rdm
->next
< rdm
->sym_len
)
113 return rdm
->sym
[rdm
->next
];
118 eat (struct rust_demangler
*rdm
, char c
)
130 next (struct rust_demangler
*rdm
)
141 parse_integer_62 (struct rust_demangler
*rdm
)
150 while (!eat (rdm
, '_'))
156 else if (ISLOWER (c
))
158 else if (ISUPPER (c
))
159 x
+= 10 + 26 + (c
- 'A');
170 parse_opt_integer_62 (struct rust_demangler
*rdm
, char tag
)
174 return 1 + parse_integer_62 (rdm
);
178 parse_disambiguator (struct rust_demangler
*rdm
)
180 return parse_opt_integer_62 (rdm
, 's');
184 parse_hex_nibbles (struct rust_demangler
*rdm
, uint64_t *value
)
192 while (!eat (rdm
, '_'))
199 else if (c
>= 'a' && c
<= 'f')
200 *value
|= 10 + (c
- 'a');
212 struct rust_mangled_ident
214 /* ASCII part of the identifier. */
218 /* Punycode insertion codes for Unicode codepoints, if any. */
219 const char *punycode
;
223 static struct rust_mangled_ident
224 parse_ident (struct rust_demangler
*rdm
)
229 struct rust_mangled_ident ident
;
233 ident
.punycode
= NULL
;
234 ident
.punycode_len
= 0;
236 if (rdm
->version
!= -1)
237 is_punycode
= eat (rdm
, 'u');
248 while (ISDIGIT (peek (rdm
)))
249 len
= len
* 10 + (next (rdm
) - '0');
251 /* Skip past the optional `_` separator (v0). */
252 if (rdm
->version
!= -1)
257 /* Check for overflows. */
258 if ((start
> rdm
->next
) || (rdm
->next
> rdm
->sym_len
))
264 ident
.ascii
= rdm
->sym
+ start
;
265 ident
.ascii_len
= len
;
269 ident
.punycode_len
= 0;
270 while (ident
.ascii_len
> 0)
274 /* The last '_' is a separator between ascii & punycode. */
275 if (ident
.ascii
[ident
.ascii_len
] == '_')
278 ident
.punycode_len
++;
280 if (!ident
.punycode_len
)
285 ident
.punycode
= ident
.ascii
+ (len
- ident
.punycode_len
);
288 if (ident
.ascii_len
== 0)
294 /* Printing functions. */
297 print_str (struct rust_demangler
*rdm
, const char *data
, size_t len
)
299 if (!rdm
->errored
&& !rdm
->skipping_printing
)
300 rdm
->callback (data
, len
, rdm
->callback_opaque
);
303 #define PRINT(s) print_str (rdm, s, strlen (s))
306 print_uint64 (struct rust_demangler
*rdm
, uint64_t x
)
309 snprintf (s
, 21, "%" PRIu64
, x
);
314 print_uint64_hex (struct rust_demangler
*rdm
, uint64_t x
)
317 snprintf (s
, 17, "%" PRIx64
, x
);
321 /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
323 decode_lower_hex_nibble (char nibble
)
325 if ('0' <= nibble
&& nibble
<= '9')
327 if ('a' <= nibble
&& nibble
<= 'f')
328 return 0xa + (nibble
- 'a');
332 /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
334 decode_legacy_escape (const char *e
, size_t len
, size_t *out_len
)
337 size_t escape_len
= 0;
338 int lo_nibble
= -1, hi_nibble
= -1;
340 if (len
< 3 || e
[0] != '$')
356 if (e
[0] == 'S' && e
[1] == 'P')
358 else if (e
[0] == 'B' && e
[1] == 'P')
360 else if (e
[0] == 'R' && e
[1] == 'F')
362 else if (e
[0] == 'L' && e
[1] == 'T')
364 else if (e
[0] == 'G' && e
[1] == 'T')
366 else if (e
[0] == 'L' && e
[1] == 'P')
368 else if (e
[0] == 'R' && e
[1] == 'P')
370 else if (e
[0] == 'u' && len
> 3)
374 hi_nibble
= decode_lower_hex_nibble (e
[1]);
377 lo_nibble
= decode_lower_hex_nibble (e
[2]);
381 /* Only allow non-control ASCII characters. */
384 c
= (hi_nibble
<< 4) | lo_nibble
;
390 if (!c
|| len
<= escape_len
|| e
[escape_len
] != '$')
393 *out_len
= 2 + escape_len
;
398 print_ident (struct rust_demangler
*rdm
, struct rust_mangled_ident ident
)
402 size_t len
, cap
, punycode_pos
, j
;
403 /* Punycode parameters and state. */
405 size_t base
, t_min
, t_max
, skew
, damp
, bias
, i
;
406 size_t delta
, w
, k
, t
;
408 if (rdm
->errored
|| rdm
->skipping_printing
)
411 if (rdm
->version
== -1)
413 /* Ignore leading underscores preceding escape sequences.
414 The mangler inserts an underscore to make sure the
415 identifier begins with a XID_Start character. */
416 if (ident
.ascii_len
>= 2 && ident
.ascii
[0] == '_'
417 && ident
.ascii
[1] == '$')
423 while (ident
.ascii_len
> 0)
425 /* Handle legacy escape sequences ("$...$", ".." or "."). */
426 if (ident
.ascii
[0] == '$')
429 = decode_legacy_escape (ident
.ascii
, ident
.ascii_len
, &len
);
431 print_str (rdm
, &unescaped
, 1);
434 /* Unexpected escape sequence, print the rest verbatim. */
435 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
439 else if (ident
.ascii
[0] == '.')
441 if (ident
.ascii_len
>= 2 && ident
.ascii
[1] == '.')
443 /* ".." becomes "::" */
455 /* Print everything before the next escape sequence, at once. */
456 for (len
= 0; len
< ident
.ascii_len
; len
++)
457 if (ident
.ascii
[len
] == '$' || ident
.ascii
[len
] == '.')
460 print_str (rdm
, ident
.ascii
, len
);
464 ident
.ascii_len
-= len
;
472 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
478 while (cap
< ident
.ascii_len
)
481 /* Check for overflows. */
482 if ((cap
* 4) / 4 != cap
)
489 /* Store the output codepoints as groups of 4 UTF-8 bytes. */
490 out
= (uint8_t *)xmalloc (cap
* 4);
497 /* Populate initial output from ASCII fragment. */
498 for (len
= 0; len
< ident
.ascii_len
; len
++)
504 p
[3] = ident
.ascii
[len
];
507 /* Punycode parameters and initial state. */
518 while (punycode_pos
< ident
.punycode_len
)
520 /* Read one delta value. */
527 t
= k
< bias
? 0 : (k
- bias
);
533 if (punycode_pos
>= ident
.punycode_len
)
535 d
= ident
.punycode
[punycode_pos
++];
539 else if (ISDIGIT (d
))
552 /* Compute the new insert position and character. */
558 /* Ensure enough space is available. */
562 /* Check for overflows. */
563 if ((cap
* 4) / 4 != cap
|| cap
< len
)
569 p
= (uint8_t *)xrealloc (out
, cap
* 4);
577 /* Move the characters after the insert position. */
579 memmove (p
+ 4, p
, (len
- i
- 1) * 4);
581 /* Insert the new character, as UTF-8 bytes. */
582 p
[0] = c
>= 0x10000 ? 0xf0 | (c
>> 18) : 0;
583 p
[1] = c
>= 0x800 ? (c
< 0x10000 ? 0xe0 : 0x80) | ((c
>> 12) & 0x3f) : 0;
584 p
[2] = (c
< 0x800 ? 0xc0 : 0x80) | ((c
>> 6) & 0x3f);
585 p
[3] = 0x80 | (c
& 0x3f);
587 /* If there are no more deltas, decoding is complete. */
588 if (punycode_pos
== ident
.punycode_len
)
593 /* Perform bias adaptation. */
597 delta
+= delta
/ len
;
599 while (delta
> ((base
- t_min
) * t_max
) / 2)
601 delta
/= base
- t_min
;
604 bias
= k
+ ((base
- t_min
+ 1) * delta
) / (delta
+ skew
);
607 /* Remove all the 0 bytes to leave behind an UTF-8 string. */
608 for (i
= 0, j
= 0; i
< len
* 4; i
++)
612 print_str (rdm
, (const char *)out
, j
);
618 /* Print the lifetime according to the previously decoded index.
619 An index of `0` always refers to `'_`, but starting with `1`,
620 indices refer to late-bound lifetimes introduced by a binder. */
622 print_lifetime_from_index (struct rust_demangler
*rdm
, uint64_t lt
)
634 depth
= rdm
->bound_lifetime_depth
- lt
;
635 /* Try to print lifetimes alphabetically first. */
639 print_str (rdm
, &c
, 1);
643 /* Use `'_123` after running out of letters. */
645 print_uint64 (rdm
, depth
);
649 /* Demangling functions. */
651 static void demangle_binder (struct rust_demangler
*rdm
);
652 static void demangle_path (struct rust_demangler
*rdm
, int in_value
);
653 static void demangle_generic_arg (struct rust_demangler
*rdm
);
654 static void demangle_type (struct rust_demangler
*rdm
);
655 static int demangle_path_maybe_open_generics (struct rust_demangler
*rdm
);
656 static void demangle_dyn_trait (struct rust_demangler
*rdm
);
657 static void demangle_const (struct rust_demangler
*rdm
);
658 static void demangle_const_uint (struct rust_demangler
*rdm
);
659 static void demangle_const_int (struct rust_demangler
*rdm
);
660 static void demangle_const_bool (struct rust_demangler
*rdm
);
661 static void demangle_const_char (struct rust_demangler
*rdm
);
663 /* Optionally enter a binder ('G') for late-bound lifetimes,
664 printing e.g. `for<'a, 'b> `, and make those lifetimes visible
665 to the caller (via depth level, which the caller should reset). */
667 demangle_binder (struct rust_demangler
*rdm
)
669 uint64_t i
, bound_lifetimes
;
674 bound_lifetimes
= parse_opt_integer_62 (rdm
, 'G');
675 if (bound_lifetimes
> 0)
678 for (i
= 0; i
< bound_lifetimes
; i
++)
682 rdm
->bound_lifetime_depth
++;
683 print_lifetime_from_index (rdm
, 1);
690 demangle_path (struct rust_demangler
*rdm
, int in_value
)
693 int was_skipping_printing
;
694 size_t i
, backref
, old_next
;
696 struct rust_mangled_ident name
;
701 switch (tag
= next (rdm
))
704 dis
= parse_disambiguator (rdm
);
705 name
= parse_ident (rdm
);
707 print_ident (rdm
, name
);
711 print_uint64_hex (rdm
, dis
);
717 if (!ISLOWER (ns
) && !ISUPPER (ns
))
723 demangle_path (rdm
, in_value
);
725 dis
= parse_disambiguator (rdm
);
726 name
= parse_ident (rdm
);
730 /* Special namespaces, like closures and shims. */
741 print_str (rdm
, &ns
, 1);
743 if (name
.ascii
|| name
.punycode
)
746 print_ident (rdm
, name
);
749 print_uint64 (rdm
, dis
);
754 /* Implementation-specific/unspecified namespaces. */
756 if (name
.ascii
|| name
.punycode
)
759 print_ident (rdm
, name
);
765 /* Ignore the `impl`'s own path.*/
766 parse_disambiguator (rdm
);
767 was_skipping_printing
= rdm
->skipping_printing
;
768 rdm
->skipping_printing
= 1;
769 demangle_path (rdm
, in_value
);
770 rdm
->skipping_printing
= was_skipping_printing
;
778 demangle_path (rdm
, 0);
783 demangle_path (rdm
, in_value
);
787 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
791 demangle_generic_arg (rdm
);
796 backref
= parse_integer_62 (rdm
);
797 if (!rdm
->skipping_printing
)
799 old_next
= rdm
->next
;
801 demangle_path (rdm
, in_value
);
802 rdm
->next
= old_next
;
812 demangle_generic_arg (struct rust_demangler
*rdm
)
817 lt
= parse_integer_62 (rdm
);
818 print_lifetime_from_index (rdm
, lt
);
820 else if (eat (rdm
, 'K'))
821 demangle_const (rdm
);
827 basic_type (char tag
)
880 demangle_type (struct rust_demangler
*rdm
)
883 size_t i
, old_next
, backref
;
884 uint64_t lt
, old_bound_lifetime_depth
;
886 struct rust_mangled_ident abi
;
893 basic
= basic_type (tag
);
907 lt
= parse_integer_62 (rdm
);
910 print_lifetime_from_index (rdm
, lt
);
934 demangle_const (rdm
);
940 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
951 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
952 demangle_binder (rdm
);
966 abi
= parse_ident (rdm
);
967 if (!abi
.ascii
|| abi
.punycode
)
976 /* If the ABI had any `-`, they were replaced with `_`,
977 so the parts between `_` have to be re-joined with `-`. */
978 for (i
= 0; i
< abi
.ascii_len
; i
++)
980 if (abi
.ascii
[i
] == '_')
982 print_str (rdm
, abi
.ascii
, i
);
985 abi
.ascii_len
-= i
+ 1;
989 print_str (rdm
, abi
.ascii
, abi
.ascii_len
);
995 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1005 /* Skip printing the return type if it's 'u', i.e. `()`. */
1010 demangle_type (rdm
);
1013 /* Restore `bound_lifetime_depth` to outside the binder. */
1015 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
1020 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
1021 demangle_binder (rdm
);
1023 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1027 demangle_dyn_trait (rdm
);
1030 /* Restore `bound_lifetime_depth` to outside the binder. */
1031 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
1033 if (!eat (rdm
, 'L'))
1038 lt
= parse_integer_62 (rdm
);
1042 print_lifetime_from_index (rdm
, lt
);
1046 backref
= parse_integer_62 (rdm
);
1047 if (!rdm
->skipping_printing
)
1049 old_next
= rdm
->next
;
1050 rdm
->next
= backref
;
1051 demangle_type (rdm
);
1052 rdm
->next
= old_next
;
1056 /* Go back to the tag, so `demangle_path` also sees it. */
1058 demangle_path (rdm
, 0);
1062 /* A trait in a trait object may have some "existential projections"
1063 (i.e. associated type bindings) after it, which should be printed
1064 in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1065 To this end, this method will keep the `<...>` of an 'I' path
1066 open, by omitting the `>`, and return `Ok(true)` in that case. */
1068 demangle_path_maybe_open_generics (struct rust_demangler
*rdm
)
1071 size_t i
, old_next
, backref
;
1080 backref
= parse_integer_62 (rdm
);
1081 if (!rdm
->skipping_printing
)
1083 old_next
= rdm
->next
;
1084 rdm
->next
= backref
;
1085 open
= demangle_path_maybe_open_generics (rdm
);
1086 rdm
->next
= old_next
;
1089 else if (eat (rdm
, 'I'))
1091 demangle_path (rdm
, 0);
1094 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1098 demangle_generic_arg (rdm
);
1102 demangle_path (rdm
, 0);
1107 demangle_dyn_trait (struct rust_demangler
*rdm
)
1110 struct rust_mangled_ident name
;
1115 open
= demangle_path_maybe_open_generics (rdm
);
1117 while (eat (rdm
, 'p'))
1125 name
= parse_ident (rdm
);
1126 print_ident (rdm
, name
);
1128 demangle_type (rdm
);
1136 demangle_const (struct rust_demangler
*rdm
)
1139 size_t old_next
, backref
;
1146 backref
= parse_integer_62 (rdm
);
1147 if (!rdm
->skipping_printing
)
1149 old_next
= rdm
->next
;
1150 rdm
->next
= backref
;
1151 demangle_const (rdm
);
1152 rdm
->next
= old_next
;
1157 ty_tag
= next (rdm
);
1165 /* Unsigned integer types. */
1172 demangle_const_uint (rdm
);
1175 /* Signed integer types. */
1182 demangle_const_int (rdm
);
1187 demangle_const_bool (rdm
);
1192 demangle_const_char (rdm
);
1206 PRINT (basic_type (ty_tag
));
1211 demangle_const_uint (struct rust_demangler
*rdm
)
1219 hex_len
= parse_hex_nibbles (rdm
, &value
);
1223 /* Print anything that doesn't fit in `uint64_t` verbatim. */
1225 print_str (rdm
, rdm
->sym
+ (rdm
->next
- hex_len
), hex_len
);
1227 else if (hex_len
> 0)
1228 print_uint64 (rdm
, value
);
1234 demangle_const_int (struct rust_demangler
*rdm
)
1238 demangle_const_uint (rdm
);
1242 demangle_const_bool (struct rust_demangler
*rdm
)
1246 if (parse_hex_nibbles (rdm
, &value
) != 1)
1254 else if (value
== 1)
1261 demangle_const_char (struct rust_demangler
*rdm
)
1266 hex_len
= parse_hex_nibbles (rdm
, &value
);
1268 if (hex_len
== 0 || hex_len
> 8)
1274 /* Match Rust's character "debug" output as best as we can. */
1278 else if (value
== '\r')
1280 else if (value
== '\n')
1282 else if (value
> ' ' && value
< '~')
1283 /* Rust also considers many non-ASCII codepoints to be printable, but
1284 that logic is not easily ported to C. */
1285 print_str (rdm
, (char *) &value
, 1);
1289 print_uint64_hex (rdm
, value
);
1295 /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
1296 The hex digits must contain at least 5 distinct digits. */
1298 is_legacy_prefixed_hash (struct rust_mangled_ident ident
)
1304 if (ident
.ascii_len
!= 17 || ident
.ascii
[0] != 'h')
1308 for (i
= 0; i
< 16; i
++)
1310 nibble
= decode_lower_hex_nibble (ident
.ascii
[1 + i
]);
1313 seen
|= (uint16_t)1 << nibble
;
1316 /* Count how many distinct digits were seen. */
1329 rust_demangle_callback (const char *mangled
, int options
,
1330 demangle_callbackref callback
, void *opaque
)
1333 struct rust_demangler rdm
;
1334 struct rust_mangled_ident ident
;
1339 rdm
.callback_opaque
= opaque
;
1340 rdm
.callback
= callback
;
1344 rdm
.skipping_printing
= 0;
1345 rdm
.verbose
= (options
& DMGL_VERBOSE
) != 0;
1347 rdm
.bound_lifetime_depth
= 0;
1349 /* Rust symbols always start with _R (v0) or _ZN (legacy). */
1350 if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'R')
1352 else if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'Z' && rdm
.sym
[2] == 'N')
1360 /* Paths (v0) always start with uppercase characters. */
1361 if (rdm
.version
!= -1 && !ISUPPER (rdm
.sym
[0]))
1364 /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
1365 for (p
= rdm
.sym
; *p
; p
++)
1369 if (*p
== '_' || ISALNUM (*p
))
1372 /* Legacy Rust symbols can also contain [.:$] characters. */
1373 if (rdm
.version
== -1 && (*p
== '$' || *p
== '.' || *p
== ':'))
1379 /* Legacy Rust symbols need to be handled separately. */
1380 if (rdm
.version
== -1)
1382 /* Legacy Rust symbols always end with E. */
1383 if (!(rdm
.sym_len
> 0 && rdm
.sym
[rdm
.sym_len
- 1] == 'E'))
1387 /* Legacy Rust symbols also always end with a path segment
1388 that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
1389 This early check, before any parse_ident calls, should
1390 quickly filter out most C++ symbols unrelated to Rust. */
1391 if (!(rdm
.sym_len
> 19
1392 && !memcmp (&rdm
.sym
[rdm
.sym_len
- 19], "17h", 3)))
1397 ident
= parse_ident (&rdm
);
1398 if (rdm
.errored
|| !ident
.ascii
)
1401 while (rdm
.next
< rdm
.sym_len
);
1403 /* The last path segment should be the hash. */
1404 if (!is_legacy_prefixed_hash (ident
))
1407 /* Reset the state for a second pass, to print the symbol. */
1409 if (!rdm
.verbose
&& rdm
.sym_len
> 19)
1411 /* Hide the last segment, containing the hash, if not verbose. */
1418 print_str (&rdm
, "::", 2);
1420 ident
= parse_ident (&rdm
);
1421 print_ident (&rdm
, ident
);
1423 while (rdm
.next
< rdm
.sym_len
);
1427 demangle_path (&rdm
, 1);
1429 /* Skip instantiating crate. */
1430 if (!rdm
.errored
&& rdm
.next
< rdm
.sym_len
)
1432 rdm
.skipping_printing
= 1;
1433 demangle_path (&rdm
, 0);
1436 /* It's an error to not reach the end. */
1437 rdm
.errored
|= rdm
.next
!= rdm
.sym_len
;
1440 return !rdm
.errored
;
1443 /* Growable string buffers. */
1453 str_buf_reserve (struct str_buf
*buf
, size_t extra
)
1455 size_t available
, min_new_cap
, new_cap
;
1458 /* Allocation failed before. */
1462 available
= buf
->cap
- buf
->len
;
1464 if (extra
<= available
)
1467 min_new_cap
= buf
->cap
+ (extra
- available
);
1469 /* Check for overflows. */
1470 if (min_new_cap
< buf
->cap
)
1481 /* Double capacity until sufficiently large. */
1482 while (new_cap
< min_new_cap
)
1486 /* Check for overflows. */
1487 if (new_cap
< buf
->cap
)
1494 new_ptr
= (char *)xrealloc (buf
->ptr
, new_cap
);
1495 if (new_ptr
== NULL
)
1511 str_buf_append (struct str_buf
*buf
, const char *data
, size_t len
)
1513 str_buf_reserve (buf
, len
);
1517 memcpy (buf
->ptr
+ buf
->len
, data
, len
);
1522 str_buf_demangle_callback (const char *data
, size_t len
, void *opaque
)
1524 str_buf_append ((struct str_buf
*)opaque
, data
, len
);
1528 rust_demangle (const char *mangled
, int options
)
1538 success
= rust_demangle_callback (mangled
, options
,
1539 str_buf_demangle_callback
, &out
);
1547 str_buf_append (&out
, "\0", 1);