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/>. */
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 uint64_t bound_lifetime_depth
;
80 /* Parsing functions. */
83 peek (const struct rust_demangler
*rdm
)
85 if (rdm
->next
< rdm
->sym_len
)
86 return rdm
->sym
[rdm
->next
];
91 eat (struct rust_demangler
*rdm
, char c
)
103 next (struct rust_demangler
*rdm
)
114 parse_integer_62 (struct rust_demangler
*rdm
)
123 while (!eat (rdm
, '_'))
129 else if (ISLOWER (c
))
131 else if (ISUPPER (c
))
132 x
+= 10 + 26 + (c
- 'A');
143 parse_opt_integer_62 (struct rust_demangler
*rdm
, char tag
)
147 return 1 + parse_integer_62 (rdm
);
151 parse_disambiguator (struct rust_demangler
*rdm
)
153 return parse_opt_integer_62 (rdm
, 's');
157 parse_hex_nibbles (struct rust_demangler
*rdm
, uint64_t *value
)
165 while (!eat (rdm
, '_'))
172 else if (c
>= 'a' && c
<= 'f')
173 *value
|= 10 + (c
- 'a');
185 struct rust_mangled_ident
187 /* ASCII part of the identifier. */
191 /* Punycode insertion codes for Unicode codepoints, if any. */
192 const char *punycode
;
196 static struct rust_mangled_ident
197 parse_ident (struct rust_demangler
*rdm
)
202 struct rust_mangled_ident ident
;
206 ident
.punycode
= NULL
;
207 ident
.punycode_len
= 0;
209 if (rdm
->version
!= -1)
210 is_punycode
= eat (rdm
, 'u');
221 while (ISDIGIT (peek (rdm
)))
222 len
= len
* 10 + (next (rdm
) - '0');
224 /* Skip past the optional `_` separator (v0). */
225 if (rdm
->version
!= -1)
230 /* Check for overflows. */
231 if ((start
> rdm
->next
) || (rdm
->next
> rdm
->sym_len
))
237 ident
.ascii
= rdm
->sym
+ start
;
238 ident
.ascii_len
= len
;
242 ident
.punycode_len
= 0;
243 while (ident
.ascii_len
> 0)
247 /* The last '_' is a separator between ascii & punycode. */
248 if (ident
.ascii
[ident
.ascii_len
] == '_')
251 ident
.punycode_len
++;
253 if (!ident
.punycode_len
)
258 ident
.punycode
= ident
.ascii
+ (len
- ident
.punycode_len
);
261 if (ident
.ascii_len
== 0)
267 /* Printing functions. */
270 print_str (struct rust_demangler
*rdm
, const char *data
, size_t len
)
272 if (!rdm
->errored
&& !rdm
->skipping_printing
)
273 rdm
->callback (data
, len
, rdm
->callback_opaque
);
276 #define PRINT(s) print_str (rdm, s, strlen (s))
279 print_uint64 (struct rust_demangler
*rdm
, uint64_t x
)
282 snprintf (s
, 21, "%" PRIu64
, x
);
287 print_uint64_hex (struct rust_demangler
*rdm
, uint64_t x
)
290 snprintf (s
, 17, "%" PRIx64
, x
);
294 /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
296 decode_lower_hex_nibble (char nibble
)
298 if ('0' <= nibble
&& nibble
<= '9')
300 if ('a' <= nibble
&& nibble
<= 'f')
301 return 0xa + (nibble
- 'a');
305 /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
307 decode_legacy_escape (const char *e
, size_t len
, size_t *out_len
)
310 size_t escape_len
= 0;
311 int lo_nibble
= -1, hi_nibble
= -1;
313 if (len
< 3 || e
[0] != '$')
329 if (e
[0] == 'S' && e
[1] == 'P')
331 else if (e
[0] == 'B' && e
[1] == 'P')
333 else if (e
[0] == 'R' && e
[1] == 'F')
335 else if (e
[0] == 'L' && e
[1] == 'T')
337 else if (e
[0] == 'G' && e
[1] == 'T')
339 else if (e
[0] == 'L' && e
[1] == 'P')
341 else if (e
[0] == 'R' && e
[1] == 'P')
343 else if (e
[0] == 'u' && len
> 3)
347 hi_nibble
= decode_lower_hex_nibble (e
[1]);
350 lo_nibble
= decode_lower_hex_nibble (e
[2]);
354 /* Only allow non-control ASCII characters. */
357 c
= (hi_nibble
<< 4) | lo_nibble
;
363 if (!c
|| len
<= escape_len
|| e
[escape_len
] != '$')
366 *out_len
= 2 + escape_len
;
371 print_ident (struct rust_demangler
*rdm
, struct rust_mangled_ident ident
)
375 size_t len
, cap
, punycode_pos
, j
;
376 /* Punycode parameters and state. */
378 size_t base
, t_min
, t_max
, skew
, damp
, bias
, i
;
379 size_t delta
, w
, k
, t
;
381 if (rdm
->errored
|| rdm
->skipping_printing
)
384 if (rdm
->version
== -1)
386 /* Ignore leading underscores preceding escape sequences.
387 The mangler inserts an underscore to make sure the
388 identifier begins with a XID_Start character. */
389 if (ident
.ascii_len
>= 2 && ident
.ascii
[0] == '_'
390 && ident
.ascii
[1] == '$')
396 while (ident
.ascii_len
> 0)
398 /* Handle legacy escape sequences ("$...$", ".." or "."). */
399 if (ident
.ascii
[0] == '$')
402 = decode_legacy_escape (ident
.ascii
, ident
.ascii_len
, &len
);
404 print_str (rdm
, &unescaped
, 1);
407 /* Unexpected escape sequence, print the rest verbatim. */
408 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
412 else if (ident
.ascii
[0] == '.')
414 if (ident
.ascii_len
>= 2 && ident
.ascii
[1] == '.')
416 /* ".." becomes "::" */
428 /* Print everything before the next escape sequence, at once. */
429 for (len
= 0; len
< ident
.ascii_len
; len
++)
430 if (ident
.ascii
[len
] == '$' || ident
.ascii
[len
] == '.')
433 print_str (rdm
, ident
.ascii
, len
);
437 ident
.ascii_len
-= len
;
445 print_str (rdm
, ident
.ascii
, ident
.ascii_len
);
451 while (cap
< ident
.ascii_len
)
454 /* Check for overflows. */
455 if ((cap
* 4) / 4 != cap
)
462 /* Store the output codepoints as groups of 4 UTF-8 bytes. */
463 out
= (uint8_t *)malloc (cap
* 4);
470 /* Populate initial output from ASCII fragment. */
471 for (len
= 0; len
< ident
.ascii_len
; len
++)
477 p
[3] = ident
.ascii
[len
];
480 /* Punycode parameters and initial state. */
491 while (punycode_pos
< ident
.punycode_len
)
493 /* Read one delta value. */
500 t
= k
< bias
? 0 : (k
- bias
);
506 if (punycode_pos
>= ident
.punycode_len
)
508 d
= ident
.punycode
[punycode_pos
++];
512 else if (ISDIGIT (d
))
525 /* Compute the new insert position and character. */
531 /* Ensure enough space is available. */
535 /* Check for overflows. */
536 if ((cap
* 4) / 4 != cap
|| cap
< len
)
542 p
= (uint8_t *)realloc (out
, cap
* 4);
550 /* Move the characters after the insert position. */
552 memmove (p
+ 4, p
, (len
- i
- 1) * 4);
554 /* Insert the new character, as UTF-8 bytes. */
555 p
[0] = c
>= 0x10000 ? 0xf0 | (c
>> 18) : 0;
556 p
[1] = c
>= 0x800 ? (c
< 0x10000 ? 0xe0 : 0x80) | ((c
>> 12) & 0x3f) : 0;
557 p
[2] = (c
< 0x800 ? 0xc0 : 0x80) | ((c
>> 6) & 0x3f);
558 p
[3] = 0x80 | (c
& 0x3f);
560 /* If there are no more deltas, decoding is complete. */
561 if (punycode_pos
== ident
.punycode_len
)
566 /* Perform bias adaptation. */
570 delta
+= delta
/ len
;
572 while (delta
> ((base
- t_min
) * t_max
) / 2)
574 delta
/= base
- t_min
;
577 bias
= k
+ ((base
- t_min
+ 1) * delta
) / (delta
+ skew
);
580 /* Remove all the 0 bytes to leave behind an UTF-8 string. */
581 for (i
= 0, j
= 0; i
< len
* 4; i
++)
585 print_str (rdm
, (const char *)out
, j
);
591 /* Print the lifetime according to the previously decoded index.
592 An index of `0` always refers to `'_`, but starting with `1`,
593 indices refer to late-bound lifetimes introduced by a binder. */
595 print_lifetime_from_index (struct rust_demangler
*rdm
, uint64_t lt
)
607 depth
= rdm
->bound_lifetime_depth
- lt
;
608 /* Try to print lifetimes alphabetically first. */
612 print_str (rdm
, &c
, 1);
616 /* Use `'_123` after running out of letters. */
618 print_uint64 (rdm
, depth
);
622 /* Demangling functions. */
624 static void demangle_binder (struct rust_demangler
*rdm
);
625 static void demangle_path (struct rust_demangler
*rdm
, int in_value
);
626 static void demangle_generic_arg (struct rust_demangler
*rdm
);
627 static void demangle_type (struct rust_demangler
*rdm
);
628 static int demangle_path_maybe_open_generics (struct rust_demangler
*rdm
);
629 static void demangle_dyn_trait (struct rust_demangler
*rdm
);
630 static void demangle_const (struct rust_demangler
*rdm
);
631 static void demangle_const_uint (struct rust_demangler
*rdm
);
632 static void demangle_const_int (struct rust_demangler
*rdm
);
633 static void demangle_const_bool (struct rust_demangler
*rdm
);
634 static void demangle_const_char (struct rust_demangler
*rdm
);
636 /* Optionally enter a binder ('G') for late-bound lifetimes,
637 printing e.g. `for<'a, 'b> `, and make those lifetimes visible
638 to the caller (via depth level, which the caller should reset). */
640 demangle_binder (struct rust_demangler
*rdm
)
642 uint64_t i
, bound_lifetimes
;
647 bound_lifetimes
= parse_opt_integer_62 (rdm
, 'G');
648 if (bound_lifetimes
> 0)
651 for (i
= 0; i
< bound_lifetimes
; i
++)
655 rdm
->bound_lifetime_depth
++;
656 print_lifetime_from_index (rdm
, 1);
663 demangle_path (struct rust_demangler
*rdm
, int in_value
)
666 int was_skipping_printing
;
667 size_t i
, backref
, old_next
;
669 struct rust_mangled_ident name
;
674 switch (tag
= next (rdm
))
677 dis
= parse_disambiguator (rdm
);
678 name
= parse_ident (rdm
);
680 print_ident (rdm
, name
);
684 print_uint64_hex (rdm
, dis
);
690 if (!ISLOWER (ns
) && !ISUPPER (ns
))
696 demangle_path (rdm
, in_value
);
698 dis
= parse_disambiguator (rdm
);
699 name
= parse_ident (rdm
);
703 /* Special namespaces, like closures and shims. */
714 print_str (rdm
, &ns
, 1);
716 if (name
.ascii
|| name
.punycode
)
719 print_ident (rdm
, name
);
722 print_uint64 (rdm
, dis
);
727 /* Implementation-specific/unspecified namespaces. */
729 if (name
.ascii
|| name
.punycode
)
732 print_ident (rdm
, name
);
738 /* Ignore the `impl`'s own path.*/
739 parse_disambiguator (rdm
);
740 was_skipping_printing
= rdm
->skipping_printing
;
741 rdm
->skipping_printing
= 1;
742 demangle_path (rdm
, in_value
);
743 rdm
->skipping_printing
= was_skipping_printing
;
751 demangle_path (rdm
, 0);
756 demangle_path (rdm
, in_value
);
760 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
764 demangle_generic_arg (rdm
);
769 backref
= parse_integer_62 (rdm
);
770 if (!rdm
->skipping_printing
)
772 old_next
= rdm
->next
;
774 demangle_path (rdm
, in_value
);
775 rdm
->next
= old_next
;
785 demangle_generic_arg (struct rust_demangler
*rdm
)
790 lt
= parse_integer_62 (rdm
);
791 print_lifetime_from_index (rdm
, lt
);
793 else if (eat (rdm
, 'K'))
794 demangle_const (rdm
);
800 basic_type (char tag
)
853 demangle_type (struct rust_demangler
*rdm
)
856 size_t i
, old_next
, backref
;
857 uint64_t lt
, old_bound_lifetime_depth
;
859 struct rust_mangled_ident abi
;
866 basic
= basic_type (tag
);
880 lt
= parse_integer_62 (rdm
);
883 print_lifetime_from_index (rdm
, lt
);
907 demangle_const (rdm
);
913 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
924 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
925 demangle_binder (rdm
);
939 abi
= parse_ident (rdm
);
940 if (!abi
.ascii
|| abi
.punycode
)
949 /* If the ABI had any `-`, they were replaced with `_`,
950 so the parts between `_` have to be re-joined with `-`. */
951 for (i
= 0; i
< abi
.ascii_len
; i
++)
953 if (abi
.ascii
[i
] == '_')
955 print_str (rdm
, abi
.ascii
, i
);
958 abi
.ascii_len
-= i
+ 1;
962 print_str (rdm
, abi
.ascii
, abi
.ascii_len
);
968 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
978 /* Skip printing the return type if it's 'u', i.e. `()`. */
986 /* Restore `bound_lifetime_depth` to outside the binder. */
988 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
993 old_bound_lifetime_depth
= rdm
->bound_lifetime_depth
;
994 demangle_binder (rdm
);
996 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1000 demangle_dyn_trait (rdm
);
1003 /* Restore `bound_lifetime_depth` to outside the binder. */
1004 rdm
->bound_lifetime_depth
= old_bound_lifetime_depth
;
1006 if (!eat (rdm
, 'L'))
1011 lt
= parse_integer_62 (rdm
);
1015 print_lifetime_from_index (rdm
, lt
);
1019 backref
= parse_integer_62 (rdm
);
1020 if (!rdm
->skipping_printing
)
1022 old_next
= rdm
->next
;
1023 rdm
->next
= backref
;
1024 demangle_type (rdm
);
1025 rdm
->next
= old_next
;
1029 /* Go back to the tag, so `demangle_path` also sees it. */
1031 demangle_path (rdm
, 0);
1035 /* A trait in a trait object may have some "existential projections"
1036 (i.e. associated type bindings) after it, which should be printed
1037 in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1038 To this end, this method will keep the `<...>` of an 'I' path
1039 open, by omitting the `>`, and return `Ok(true)` in that case. */
1041 demangle_path_maybe_open_generics (struct rust_demangler
*rdm
)
1044 size_t i
, old_next
, backref
;
1053 backref
= parse_integer_62 (rdm
);
1054 if (!rdm
->skipping_printing
)
1056 old_next
= rdm
->next
;
1057 rdm
->next
= backref
;
1058 open
= demangle_path_maybe_open_generics (rdm
);
1059 rdm
->next
= old_next
;
1062 else if (eat (rdm
, 'I'))
1064 demangle_path (rdm
, 0);
1067 for (i
= 0; !rdm
->errored
&& !eat (rdm
, 'E'); i
++)
1071 demangle_generic_arg (rdm
);
1075 demangle_path (rdm
, 0);
1080 demangle_dyn_trait (struct rust_demangler
*rdm
)
1083 struct rust_mangled_ident name
;
1088 open
= demangle_path_maybe_open_generics (rdm
);
1090 while (eat (rdm
, 'p'))
1098 name
= parse_ident (rdm
);
1099 print_ident (rdm
, name
);
1101 demangle_type (rdm
);
1109 demangle_const (struct rust_demangler
*rdm
)
1112 size_t old_next
, backref
;
1119 backref
= parse_integer_62 (rdm
);
1120 if (!rdm
->skipping_printing
)
1122 old_next
= rdm
->next
;
1123 rdm
->next
= backref
;
1124 demangle_const (rdm
);
1125 rdm
->next
= old_next
;
1130 ty_tag
= next (rdm
);
1138 /* Unsigned integer types. */
1145 demangle_const_uint (rdm
);
1148 /* Signed integer types. */
1155 demangle_const_int (rdm
);
1160 demangle_const_bool (rdm
);
1165 demangle_const_char (rdm
);
1179 PRINT (basic_type (ty_tag
));
1184 demangle_const_uint (struct rust_demangler
*rdm
)
1192 hex_len
= parse_hex_nibbles (rdm
, &value
);
1196 /* Print anything that doesn't fit in `uint64_t` verbatim. */
1198 print_str (rdm
, rdm
->sym
+ (rdm
->next
- hex_len
), hex_len
);
1200 else if (hex_len
> 0)
1201 print_uint64 (rdm
, value
);
1207 demangle_const_int (struct rust_demangler
*rdm
)
1211 demangle_const_uint (rdm
);
1215 demangle_const_bool (struct rust_demangler
*rdm
)
1219 if (parse_hex_nibbles (rdm
, &value
) != 1)
1227 else if (value
== 1)
1234 demangle_const_char (struct rust_demangler
*rdm
)
1239 hex_len
= parse_hex_nibbles (rdm
, &value
);
1241 if (hex_len
== 0 || hex_len
> 8)
1247 /* Match Rust's character "debug" output as best as we can. */
1251 else if (value
== '\r')
1253 else if (value
== '\n')
1255 else if (value
> ' ' && value
< '~')
1257 /* Rust also considers many non-ASCII codepoints to be printable, but
1258 that logic is not easily ported to C. */
1260 print_str (rdm
, &c
, 1);
1265 print_uint64_hex (rdm
, value
);
1271 /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
1272 The hex digits must contain at least 5 distinct digits. */
1274 is_legacy_prefixed_hash (struct rust_mangled_ident ident
)
1280 if (ident
.ascii_len
!= 17 || ident
.ascii
[0] != 'h')
1284 for (i
= 0; i
< 16; i
++)
1286 nibble
= decode_lower_hex_nibble (ident
.ascii
[1 + i
]);
1289 seen
|= (uint16_t)1 << nibble
;
1292 /* Count how many distinct digits were seen. */
1305 rust_demangle_callback (const char *mangled
, int options
,
1306 demangle_callbackref callback
, void *opaque
)
1309 struct rust_demangler rdm
;
1310 struct rust_mangled_ident ident
;
1315 rdm
.callback_opaque
= opaque
;
1316 rdm
.callback
= callback
;
1320 rdm
.skipping_printing
= 0;
1321 rdm
.verbose
= (options
& DMGL_VERBOSE
) != 0;
1323 rdm
.bound_lifetime_depth
= 0;
1325 /* Rust symbols always start with _R (v0) or _ZN (legacy). */
1326 if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'R')
1328 else if (rdm
.sym
[0] == '_' && rdm
.sym
[1] == 'Z' && rdm
.sym
[2] == 'N')
1336 /* Paths (v0) always start with uppercase characters. */
1337 if (rdm
.version
!= -1 && !ISUPPER (rdm
.sym
[0]))
1340 /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
1341 for (p
= rdm
.sym
; *p
; p
++)
1345 if (*p
== '_' || ISALNUM (*p
))
1348 /* Legacy Rust symbols can also contain [.:$] characters. */
1349 if (rdm
.version
== -1 && (*p
== '$' || *p
== '.' || *p
== ':'))
1355 /* Legacy Rust symbols need to be handled separately. */
1356 if (rdm
.version
== -1)
1358 /* Legacy Rust symbols always end with E. */
1359 if (!(rdm
.sym_len
> 0 && rdm
.sym
[rdm
.sym_len
- 1] == 'E'))
1363 /* Legacy Rust symbols also always end with a path segment
1364 that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
1365 This early check, before any parse_ident calls, should
1366 quickly filter out most C++ symbols unrelated to Rust. */
1367 if (!(rdm
.sym_len
> 19
1368 && !memcmp (&rdm
.sym
[rdm
.sym_len
- 19], "17h", 3)))
1373 ident
= parse_ident (&rdm
);
1374 if (rdm
.errored
|| !ident
.ascii
)
1377 while (rdm
.next
< rdm
.sym_len
);
1379 /* The last path segment should be the hash. */
1380 if (!is_legacy_prefixed_hash (ident
))
1383 /* Reset the state for a second pass, to print the symbol. */
1385 if (!rdm
.verbose
&& rdm
.sym_len
> 19)
1387 /* Hide the last segment, containing the hash, if not verbose. */
1394 print_str (&rdm
, "::", 2);
1396 ident
= parse_ident (&rdm
);
1397 print_ident (&rdm
, ident
);
1399 while (rdm
.next
< rdm
.sym_len
);
1403 demangle_path (&rdm
, 1);
1405 /* Skip instantiating crate. */
1406 if (!rdm
.errored
&& rdm
.next
< rdm
.sym_len
)
1408 rdm
.skipping_printing
= 1;
1409 demangle_path (&rdm
, 0);
1412 /* It's an error to not reach the end. */
1413 rdm
.errored
|= rdm
.next
!= rdm
.sym_len
;
1416 return !rdm
.errored
;
1419 /* Growable string buffers. */
1429 str_buf_reserve (struct str_buf
*buf
, size_t extra
)
1431 size_t available
, min_new_cap
, new_cap
;
1434 /* Allocation failed before. */
1438 available
= buf
->cap
- buf
->len
;
1440 if (extra
<= available
)
1443 min_new_cap
= buf
->cap
+ (extra
- available
);
1445 /* Check for overflows. */
1446 if (min_new_cap
< buf
->cap
)
1457 /* Double capacity until sufficiently large. */
1458 while (new_cap
< min_new_cap
)
1462 /* Check for overflows. */
1463 if (new_cap
< buf
->cap
)
1470 new_ptr
= (char *)realloc (buf
->ptr
, new_cap
);
1471 if (new_ptr
== NULL
)
1487 str_buf_append (struct str_buf
*buf
, const char *data
, size_t len
)
1489 str_buf_reserve (buf
, len
);
1493 memcpy (buf
->ptr
+ buf
->len
, data
, len
);
1498 str_buf_demangle_callback (const char *data
, size_t len
, void *opaque
)
1500 str_buf_append ((struct str_buf
*)opaque
, data
, len
);
1504 rust_demangle (const char *mangled
, int options
)
1514 success
= rust_demangle_callback (mangled
, options
,
1515 str_buf_demangle_callback
, &out
);
1523 str_buf_append (&out
, "\0", 1);