rust-demangle.c revision 1.1.1.7 1 1.1 mrg /* Demangler for the Rust programming language
2 1.1.1.7 mrg Copyright (C) 2016-2022 Free Software Foundation, Inc.
3 1.1 mrg Written by David Tolnay (dtolnay (at) gmail.com).
4 1.1.1.7 mrg Rewritten by Eduard-Mihai Burtescu (eddyb (at) lyken.rs) for v0 support.
5 1.1 mrg
6 1.1 mrg This file is part of the libiberty library.
7 1.1 mrg Libiberty is free software; you can redistribute it and/or
8 1.1 mrg modify it under the terms of the GNU Library General Public
9 1.1 mrg License as published by the Free Software Foundation; either
10 1.1 mrg version 2 of the License, or (at your option) any later version.
11 1.1 mrg
12 1.1 mrg In addition to the permissions in the GNU Library General Public
13 1.1 mrg License, the Free Software Foundation gives you unlimited permission
14 1.1 mrg to link the compiled version of this file into combinations with other
15 1.1 mrg programs, and to distribute those combinations without any restriction
16 1.1 mrg coming from the use of this file. (The Library Public License
17 1.1 mrg restrictions do apply in other respects; for example, they cover
18 1.1 mrg modification of the file, and distribution when not linked into a
19 1.1 mrg combined executable.)
20 1.1 mrg
21 1.1 mrg Libiberty is distributed in the hope that it will be useful,
22 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
23 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 1.1 mrg Library General Public License for more details.
25 1.1 mrg
26 1.1 mrg You should have received a copy of the GNU Library General Public
27 1.1 mrg License along with libiberty; see the file COPYING.LIB.
28 1.1 mrg If not, see <http://www.gnu.org/licenses/>. */
29 1.1 mrg
30 1.1 mrg
31 1.1 mrg #ifdef HAVE_CONFIG_H
32 1.1 mrg #include "config.h"
33 1.1 mrg #endif
34 1.1 mrg
35 1.1 mrg #include "safe-ctype.h"
36 1.1 mrg
37 1.1.1.6 mrg #include <inttypes.h>
38 1.1 mrg #include <sys/types.h>
39 1.1 mrg #include <string.h>
40 1.1 mrg #include <stdio.h>
41 1.1.1.6 mrg #include <stdlib.h>
42 1.1 mrg
43 1.1 mrg #ifdef HAVE_STRING_H
44 1.1 mrg #include <string.h>
45 1.1 mrg #else
46 1.1 mrg extern size_t strlen(const char *s);
47 1.1 mrg extern int strncmp(const char *s1, const char *s2, size_t n);
48 1.1 mrg extern void *memset(void *s, int c, size_t n);
49 1.1 mrg #endif
50 1.1 mrg
51 1.1 mrg #include <demangle.h>
52 1.1 mrg #include "libiberty.h"
53 1.1 mrg
54 1.1.1.6 mrg struct rust_demangler
55 1.1.1.6 mrg {
56 1.1.1.6 mrg const char *sym;
57 1.1.1.6 mrg size_t sym_len;
58 1.1 mrg
59 1.1.1.6 mrg void *callback_opaque;
60 1.1.1.6 mrg demangle_callbackref callback;
61 1.1 mrg
62 1.1.1.6 mrg /* Position of the next character to read from the symbol. */
63 1.1.1.6 mrg size_t next;
64 1.1 mrg
65 1.1.1.6 mrg /* Non-zero if any error occurred. */
66 1.1.1.6 mrg int errored;
67 1.1 mrg
68 1.1.1.7 mrg /* Non-zero if nothing should be printed. */
69 1.1.1.7 mrg int skipping_printing;
70 1.1.1.7 mrg
71 1.1.1.6 mrg /* Non-zero if printing should be verbose (e.g. include hashes). */
72 1.1.1.6 mrg int verbose;
73 1.1 mrg
74 1.1.1.6 mrg /* Rust mangling version, with legacy mangling being -1. */
75 1.1.1.6 mrg int version;
76 1.1.1.7 mrg
77 1.1.1.7 mrg /* Recursion depth. */
78 1.1.1.7 mrg unsigned int recursion;
79 1.1.1.7 mrg /* Maximum number of times demangle_path may be called recursively. */
80 1.1.1.7 mrg #define RUST_MAX_RECURSION_COUNT 1024
81 1.1.1.7 mrg #define RUST_NO_RECURSION_LIMIT ((unsigned int) -1)
82 1.1.1.7 mrg
83 1.1.1.7 mrg uint64_t bound_lifetime_depth;
84 1.1.1.6 mrg };
85 1.1 mrg
86 1.1.1.6 mrg /* Parsing functions. */
87 1.1 mrg
88 1.1.1.6 mrg static char
89 1.1.1.6 mrg peek (const struct rust_demangler *rdm)
90 1.1 mrg {
91 1.1.1.6 mrg if (rdm->next < rdm->sym_len)
92 1.1.1.6 mrg return rdm->sym[rdm->next];
93 1.1.1.6 mrg return 0;
94 1.1.1.6 mrg }
95 1.1 mrg
96 1.1.1.7 mrg static int
97 1.1.1.7 mrg eat (struct rust_demangler *rdm, char c)
98 1.1.1.7 mrg {
99 1.1.1.7 mrg if (peek (rdm) == c)
100 1.1.1.7 mrg {
101 1.1.1.7 mrg rdm->next++;
102 1.1.1.7 mrg return 1;
103 1.1.1.7 mrg }
104 1.1.1.7 mrg else
105 1.1.1.7 mrg return 0;
106 1.1.1.7 mrg }
107 1.1.1.7 mrg
108 1.1.1.6 mrg static char
109 1.1.1.6 mrg next (struct rust_demangler *rdm)
110 1.1.1.6 mrg {
111 1.1.1.6 mrg char c = peek (rdm);
112 1.1.1.6 mrg if (!c)
113 1.1.1.6 mrg rdm->errored = 1;
114 1.1.1.6 mrg else
115 1.1.1.6 mrg rdm->next++;
116 1.1.1.6 mrg return c;
117 1.1.1.6 mrg }
118 1.1.1.6 mrg
119 1.1.1.7 mrg static uint64_t
120 1.1.1.7 mrg parse_integer_62 (struct rust_demangler *rdm)
121 1.1.1.7 mrg {
122 1.1.1.7 mrg char c;
123 1.1.1.7 mrg uint64_t x;
124 1.1.1.7 mrg
125 1.1.1.7 mrg if (eat (rdm, '_'))
126 1.1.1.7 mrg return 0;
127 1.1.1.7 mrg
128 1.1.1.7 mrg x = 0;
129 1.1.1.7 mrg while (!eat (rdm, '_'))
130 1.1.1.7 mrg {
131 1.1.1.7 mrg c = next (rdm);
132 1.1.1.7 mrg x *= 62;
133 1.1.1.7 mrg if (ISDIGIT (c))
134 1.1.1.7 mrg x += c - '0';
135 1.1.1.7 mrg else if (ISLOWER (c))
136 1.1.1.7 mrg x += 10 + (c - 'a');
137 1.1.1.7 mrg else if (ISUPPER (c))
138 1.1.1.7 mrg x += 10 + 26 + (c - 'A');
139 1.1.1.7 mrg else
140 1.1.1.7 mrg {
141 1.1.1.7 mrg rdm->errored = 1;
142 1.1.1.7 mrg return 0;
143 1.1.1.7 mrg }
144 1.1.1.7 mrg }
145 1.1.1.7 mrg return x + 1;
146 1.1.1.7 mrg }
147 1.1.1.7 mrg
148 1.1.1.7 mrg static uint64_t
149 1.1.1.7 mrg parse_opt_integer_62 (struct rust_demangler *rdm, char tag)
150 1.1.1.7 mrg {
151 1.1.1.7 mrg if (!eat (rdm, tag))
152 1.1.1.7 mrg return 0;
153 1.1.1.7 mrg return 1 + parse_integer_62 (rdm);
154 1.1.1.7 mrg }
155 1.1.1.7 mrg
156 1.1.1.7 mrg static uint64_t
157 1.1.1.7 mrg parse_disambiguator (struct rust_demangler *rdm)
158 1.1.1.7 mrg {
159 1.1.1.7 mrg return parse_opt_integer_62 (rdm, 's');
160 1.1.1.7 mrg }
161 1.1.1.7 mrg
162 1.1.1.7 mrg static size_t
163 1.1.1.7 mrg parse_hex_nibbles (struct rust_demangler *rdm, uint64_t *value)
164 1.1.1.7 mrg {
165 1.1.1.7 mrg char c;
166 1.1.1.7 mrg size_t hex_len;
167 1.1.1.7 mrg
168 1.1.1.7 mrg hex_len = 0;
169 1.1.1.7 mrg *value = 0;
170 1.1.1.7 mrg
171 1.1.1.7 mrg while (!eat (rdm, '_'))
172 1.1.1.7 mrg {
173 1.1.1.7 mrg *value <<= 4;
174 1.1.1.7 mrg
175 1.1.1.7 mrg c = next (rdm);
176 1.1.1.7 mrg if (ISDIGIT (c))
177 1.1.1.7 mrg *value |= c - '0';
178 1.1.1.7 mrg else if (c >= 'a' && c <= 'f')
179 1.1.1.7 mrg *value |= 10 + (c - 'a');
180 1.1.1.7 mrg else
181 1.1.1.7 mrg {
182 1.1.1.7 mrg rdm->errored = 1;
183 1.1.1.7 mrg return 0;
184 1.1.1.7 mrg }
185 1.1.1.7 mrg hex_len++;
186 1.1.1.7 mrg }
187 1.1.1.7 mrg
188 1.1.1.7 mrg return hex_len;
189 1.1.1.7 mrg }
190 1.1.1.7 mrg
191 1.1.1.6 mrg struct rust_mangled_ident
192 1.1.1.6 mrg {
193 1.1.1.6 mrg /* ASCII part of the identifier. */
194 1.1.1.6 mrg const char *ascii;
195 1.1.1.6 mrg size_t ascii_len;
196 1.1.1.7 mrg
197 1.1.1.7 mrg /* Punycode insertion codes for Unicode codepoints, if any. */
198 1.1.1.7 mrg const char *punycode;
199 1.1.1.7 mrg size_t punycode_len;
200 1.1.1.6 mrg };
201 1.1.1.6 mrg
202 1.1.1.6 mrg static struct rust_mangled_ident
203 1.1.1.6 mrg parse_ident (struct rust_demangler *rdm)
204 1.1.1.6 mrg {
205 1.1.1.6 mrg char c;
206 1.1.1.6 mrg size_t start, len;
207 1.1.1.7 mrg int is_punycode = 0;
208 1.1.1.6 mrg struct rust_mangled_ident ident;
209 1.1.1.6 mrg
210 1.1.1.6 mrg ident.ascii = NULL;
211 1.1.1.6 mrg ident.ascii_len = 0;
212 1.1.1.7 mrg ident.punycode = NULL;
213 1.1.1.7 mrg ident.punycode_len = 0;
214 1.1.1.7 mrg
215 1.1.1.7 mrg if (rdm->version != -1)
216 1.1.1.7 mrg is_punycode = eat (rdm, 'u');
217 1.1.1.6 mrg
218 1.1.1.6 mrg c = next (rdm);
219 1.1.1.6 mrg if (!ISDIGIT (c))
220 1.1.1.6 mrg {
221 1.1.1.6 mrg rdm->errored = 1;
222 1.1.1.6 mrg return ident;
223 1.1.1.6 mrg }
224 1.1.1.6 mrg len = c - '0';
225 1.1.1.6 mrg
226 1.1.1.6 mrg if (c != '0')
227 1.1.1.6 mrg while (ISDIGIT (peek (rdm)))
228 1.1.1.6 mrg len = len * 10 + (next (rdm) - '0');
229 1.1.1.6 mrg
230 1.1.1.7 mrg /* Skip past the optional `_` separator (v0). */
231 1.1.1.7 mrg if (rdm->version != -1)
232 1.1.1.7 mrg eat (rdm, '_');
233 1.1.1.7 mrg
234 1.1.1.6 mrg start = rdm->next;
235 1.1.1.6 mrg rdm->next += len;
236 1.1.1.6 mrg /* Check for overflows. */
237 1.1.1.6 mrg if ((start > rdm->next) || (rdm->next > rdm->sym_len))
238 1.1.1.6 mrg {
239 1.1.1.6 mrg rdm->errored = 1;
240 1.1.1.6 mrg return ident;
241 1.1.1.6 mrg }
242 1.1.1.6 mrg
243 1.1.1.6 mrg ident.ascii = rdm->sym + start;
244 1.1.1.6 mrg ident.ascii_len = len;
245 1.1.1.6 mrg
246 1.1.1.7 mrg if (is_punycode)
247 1.1.1.7 mrg {
248 1.1.1.7 mrg ident.punycode_len = 0;
249 1.1.1.7 mrg while (ident.ascii_len > 0)
250 1.1.1.7 mrg {
251 1.1.1.7 mrg ident.ascii_len--;
252 1.1.1.7 mrg
253 1.1.1.7 mrg /* The last '_' is a separator between ascii & punycode. */
254 1.1.1.7 mrg if (ident.ascii[ident.ascii_len] == '_')
255 1.1.1.7 mrg break;
256 1.1.1.7 mrg
257 1.1.1.7 mrg ident.punycode_len++;
258 1.1.1.7 mrg }
259 1.1.1.7 mrg if (!ident.punycode_len)
260 1.1.1.7 mrg {
261 1.1.1.7 mrg rdm->errored = 1;
262 1.1.1.7 mrg return ident;
263 1.1.1.7 mrg }
264 1.1.1.7 mrg ident.punycode = ident.ascii + (len - ident.punycode_len);
265 1.1.1.7 mrg }
266 1.1.1.7 mrg
267 1.1.1.6 mrg if (ident.ascii_len == 0)
268 1.1.1.6 mrg ident.ascii = NULL;
269 1.1.1.6 mrg
270 1.1.1.6 mrg return ident;
271 1.1.1.6 mrg }
272 1.1.1.6 mrg
273 1.1.1.6 mrg /* Printing functions. */
274 1.1.1.6 mrg
275 1.1.1.6 mrg static void
276 1.1.1.6 mrg print_str (struct rust_demangler *rdm, const char *data, size_t len)
277 1.1.1.6 mrg {
278 1.1.1.7 mrg if (!rdm->errored && !rdm->skipping_printing)
279 1.1.1.6 mrg rdm->callback (data, len, rdm->callback_opaque);
280 1.1.1.6 mrg }
281 1.1.1.6 mrg
282 1.1.1.6 mrg #define PRINT(s) print_str (rdm, s, strlen (s))
283 1.1.1.6 mrg
284 1.1.1.7 mrg static void
285 1.1.1.7 mrg print_uint64 (struct rust_demangler *rdm, uint64_t x)
286 1.1.1.7 mrg {
287 1.1.1.7 mrg char s[21];
288 1.1.1.7 mrg snprintf (s, 21, "%" PRIu64, x);
289 1.1.1.7 mrg PRINT (s);
290 1.1.1.7 mrg }
291 1.1.1.7 mrg
292 1.1.1.7 mrg static void
293 1.1.1.7 mrg print_uint64_hex (struct rust_demangler *rdm, uint64_t x)
294 1.1.1.7 mrg {
295 1.1.1.7 mrg char s[17];
296 1.1.1.7 mrg snprintf (s, 17, "%" PRIx64, x);
297 1.1.1.7 mrg PRINT (s);
298 1.1.1.7 mrg }
299 1.1.1.7 mrg
300 1.1.1.6 mrg /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
301 1.1.1.6 mrg static int
302 1.1.1.6 mrg decode_lower_hex_nibble (char nibble)
303 1.1.1.6 mrg {
304 1.1.1.6 mrg if ('0' <= nibble && nibble <= '9')
305 1.1.1.6 mrg return nibble - '0';
306 1.1.1.6 mrg if ('a' <= nibble && nibble <= 'f')
307 1.1.1.6 mrg return 0xa + (nibble - 'a');
308 1.1.1.6 mrg return -1;
309 1.1.1.6 mrg }
310 1.1.1.6 mrg
311 1.1.1.6 mrg /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
312 1.1.1.6 mrg static char
313 1.1.1.6 mrg decode_legacy_escape (const char *e, size_t len, size_t *out_len)
314 1.1.1.6 mrg {
315 1.1.1.6 mrg char c = 0;
316 1.1.1.6 mrg size_t escape_len = 0;
317 1.1.1.6 mrg int lo_nibble = -1, hi_nibble = -1;
318 1.1 mrg
319 1.1.1.6 mrg if (len < 3 || e[0] != '$')
320 1.1 mrg return 0;
321 1.1 mrg
322 1.1.1.6 mrg e++;
323 1.1.1.6 mrg len--;
324 1.1.1.6 mrg
325 1.1.1.6 mrg if (e[0] == 'C')
326 1.1.1.6 mrg {
327 1.1.1.6 mrg escape_len = 1;
328 1.1.1.6 mrg
329 1.1.1.6 mrg c = ',';
330 1.1.1.6 mrg }
331 1.1.1.6 mrg else if (len > 2)
332 1.1.1.6 mrg {
333 1.1.1.6 mrg escape_len = 2;
334 1.1.1.6 mrg
335 1.1.1.6 mrg if (e[0] == 'S' && e[1] == 'P')
336 1.1.1.6 mrg c = '@';
337 1.1.1.6 mrg else if (e[0] == 'B' && e[1] == 'P')
338 1.1.1.6 mrg c = '*';
339 1.1.1.6 mrg else if (e[0] == 'R' && e[1] == 'F')
340 1.1.1.6 mrg c = '&';
341 1.1.1.6 mrg else if (e[0] == 'L' && e[1] == 'T')
342 1.1.1.6 mrg c = '<';
343 1.1.1.6 mrg else if (e[0] == 'G' && e[1] == 'T')
344 1.1.1.6 mrg c = '>';
345 1.1.1.6 mrg else if (e[0] == 'L' && e[1] == 'P')
346 1.1.1.6 mrg c = '(';
347 1.1.1.6 mrg else if (e[0] == 'R' && e[1] == 'P')
348 1.1.1.6 mrg c = ')';
349 1.1.1.6 mrg else if (e[0] == 'u' && len > 3)
350 1.1.1.6 mrg {
351 1.1.1.6 mrg escape_len = 3;
352 1.1.1.6 mrg
353 1.1.1.6 mrg hi_nibble = decode_lower_hex_nibble (e[1]);
354 1.1.1.6 mrg if (hi_nibble < 0)
355 1.1.1.6 mrg return 0;
356 1.1.1.6 mrg lo_nibble = decode_lower_hex_nibble (e[2]);
357 1.1.1.6 mrg if (lo_nibble < 0)
358 1.1.1.6 mrg return 0;
359 1.1.1.6 mrg
360 1.1.1.6 mrg /* Only allow non-control ASCII characters. */
361 1.1.1.6 mrg if (hi_nibble > 7)
362 1.1.1.6 mrg return 0;
363 1.1.1.6 mrg c = (hi_nibble << 4) | lo_nibble;
364 1.1.1.6 mrg if (c < 0x20)
365 1.1.1.6 mrg return 0;
366 1.1.1.6 mrg }
367 1.1.1.6 mrg }
368 1.1.1.6 mrg
369 1.1.1.6 mrg if (!c || len <= escape_len || e[escape_len] != '$')
370 1.1 mrg return 0;
371 1.1 mrg
372 1.1.1.6 mrg *out_len = 2 + escape_len;
373 1.1.1.6 mrg return c;
374 1.1 mrg }
375 1.1 mrg
376 1.1.1.6 mrg static void
377 1.1.1.6 mrg print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
378 1.1.1.6 mrg {
379 1.1.1.6 mrg char unescaped;
380 1.1.1.7 mrg uint8_t *out, *p, d;
381 1.1.1.7 mrg size_t len, cap, punycode_pos, j;
382 1.1.1.7 mrg /* Punycode parameters and state. */
383 1.1.1.7 mrg uint32_t c;
384 1.1.1.7 mrg size_t base, t_min, t_max, skew, damp, bias, i;
385 1.1.1.7 mrg size_t delta, w, k, t;
386 1.1.1.6 mrg
387 1.1.1.7 mrg if (rdm->errored || rdm->skipping_printing)
388 1.1.1.6 mrg return;
389 1.1.1.6 mrg
390 1.1.1.6 mrg if (rdm->version == -1)
391 1.1.1.6 mrg {
392 1.1.1.6 mrg /* Ignore leading underscores preceding escape sequences.
393 1.1.1.6 mrg The mangler inserts an underscore to make sure the
394 1.1.1.6 mrg identifier begins with a XID_Start character. */
395 1.1.1.6 mrg if (ident.ascii_len >= 2 && ident.ascii[0] == '_'
396 1.1.1.6 mrg && ident.ascii[1] == '$')
397 1.1.1.6 mrg {
398 1.1.1.6 mrg ident.ascii++;
399 1.1.1.6 mrg ident.ascii_len--;
400 1.1.1.6 mrg }
401 1.1.1.6 mrg
402 1.1.1.6 mrg while (ident.ascii_len > 0)
403 1.1.1.6 mrg {
404 1.1.1.6 mrg /* Handle legacy escape sequences ("$...$", ".." or "."). */
405 1.1.1.6 mrg if (ident.ascii[0] == '$')
406 1.1.1.6 mrg {
407 1.1.1.6 mrg unescaped
408 1.1.1.6 mrg = decode_legacy_escape (ident.ascii, ident.ascii_len, &len);
409 1.1.1.6 mrg if (unescaped)
410 1.1.1.6 mrg print_str (rdm, &unescaped, 1);
411 1.1.1.6 mrg else
412 1.1.1.6 mrg {
413 1.1.1.6 mrg /* Unexpected escape sequence, print the rest verbatim. */
414 1.1.1.6 mrg print_str (rdm, ident.ascii, ident.ascii_len);
415 1.1.1.6 mrg return;
416 1.1.1.6 mrg }
417 1.1.1.6 mrg }
418 1.1.1.6 mrg else if (ident.ascii[0] == '.')
419 1.1.1.6 mrg {
420 1.1.1.6 mrg if (ident.ascii_len >= 2 && ident.ascii[1] == '.')
421 1.1.1.6 mrg {
422 1.1.1.6 mrg /* ".." becomes "::" */
423 1.1.1.6 mrg PRINT ("::");
424 1.1.1.6 mrg len = 2;
425 1.1.1.6 mrg }
426 1.1.1.6 mrg else
427 1.1.1.6 mrg {
428 1.1.1.7 mrg PRINT (".");
429 1.1.1.6 mrg len = 1;
430 1.1.1.6 mrg }
431 1.1.1.6 mrg }
432 1.1.1.6 mrg else
433 1.1.1.6 mrg {
434 1.1.1.6 mrg /* Print everything before the next escape sequence, at once. */
435 1.1.1.6 mrg for (len = 0; len < ident.ascii_len; len++)
436 1.1.1.6 mrg if (ident.ascii[len] == '$' || ident.ascii[len] == '.')
437 1.1.1.6 mrg break;
438 1.1.1.6 mrg
439 1.1.1.6 mrg print_str (rdm, ident.ascii, len);
440 1.1.1.6 mrg }
441 1.1.1.6 mrg
442 1.1.1.6 mrg ident.ascii += len;
443 1.1.1.6 mrg ident.ascii_len -= len;
444 1.1.1.6 mrg }
445 1.1 mrg
446 1.1.1.6 mrg return;
447 1.1.1.6 mrg }
448 1.1.1.7 mrg
449 1.1.1.7 mrg if (!ident.punycode)
450 1.1.1.7 mrg {
451 1.1.1.7 mrg print_str (rdm, ident.ascii, ident.ascii_len);
452 1.1.1.7 mrg return;
453 1.1.1.7 mrg }
454 1.1.1.7 mrg
455 1.1.1.7 mrg len = 0;
456 1.1.1.7 mrg cap = 4;
457 1.1.1.7 mrg while (cap < ident.ascii_len)
458 1.1.1.7 mrg {
459 1.1.1.7 mrg cap *= 2;
460 1.1.1.7 mrg /* Check for overflows. */
461 1.1.1.7 mrg if ((cap * 4) / 4 != cap)
462 1.1.1.7 mrg {
463 1.1.1.7 mrg rdm->errored = 1;
464 1.1.1.7 mrg return;
465 1.1.1.7 mrg }
466 1.1.1.7 mrg }
467 1.1.1.7 mrg
468 1.1.1.7 mrg /* Store the output codepoints as groups of 4 UTF-8 bytes. */
469 1.1.1.7 mrg out = (uint8_t *)malloc (cap * 4);
470 1.1.1.7 mrg if (!out)
471 1.1.1.7 mrg {
472 1.1.1.7 mrg rdm->errored = 1;
473 1.1.1.7 mrg return;
474 1.1.1.7 mrg }
475 1.1.1.7 mrg
476 1.1.1.7 mrg /* Populate initial output from ASCII fragment. */
477 1.1.1.7 mrg for (len = 0; len < ident.ascii_len; len++)
478 1.1.1.7 mrg {
479 1.1.1.7 mrg p = out + 4 * len;
480 1.1.1.7 mrg p[0] = 0;
481 1.1.1.7 mrg p[1] = 0;
482 1.1.1.7 mrg p[2] = 0;
483 1.1.1.7 mrg p[3] = ident.ascii[len];
484 1.1.1.7 mrg }
485 1.1.1.7 mrg
486 1.1.1.7 mrg /* Punycode parameters and initial state. */
487 1.1.1.7 mrg base = 36;
488 1.1.1.7 mrg t_min = 1;
489 1.1.1.7 mrg t_max = 26;
490 1.1.1.7 mrg skew = 38;
491 1.1.1.7 mrg damp = 700;
492 1.1.1.7 mrg bias = 72;
493 1.1.1.7 mrg i = 0;
494 1.1.1.7 mrg c = 0x80;
495 1.1.1.7 mrg
496 1.1.1.7 mrg punycode_pos = 0;
497 1.1.1.7 mrg while (punycode_pos < ident.punycode_len)
498 1.1.1.7 mrg {
499 1.1.1.7 mrg /* Read one delta value. */
500 1.1.1.7 mrg delta = 0;
501 1.1.1.7 mrg w = 1;
502 1.1.1.7 mrg k = 0;
503 1.1.1.7 mrg do
504 1.1.1.7 mrg {
505 1.1.1.7 mrg k += base;
506 1.1.1.7 mrg t = k < bias ? 0 : (k - bias);
507 1.1.1.7 mrg if (t < t_min)
508 1.1.1.7 mrg t = t_min;
509 1.1.1.7 mrg if (t > t_max)
510 1.1.1.7 mrg t = t_max;
511 1.1.1.7 mrg
512 1.1.1.7 mrg if (punycode_pos >= ident.punycode_len)
513 1.1.1.7 mrg goto cleanup;
514 1.1.1.7 mrg d = ident.punycode[punycode_pos++];
515 1.1.1.7 mrg
516 1.1.1.7 mrg if (ISLOWER (d))
517 1.1.1.7 mrg d = d - 'a';
518 1.1.1.7 mrg else if (ISDIGIT (d))
519 1.1.1.7 mrg d = 26 + (d - '0');
520 1.1.1.7 mrg else
521 1.1.1.7 mrg {
522 1.1.1.7 mrg rdm->errored = 1;
523 1.1.1.7 mrg goto cleanup;
524 1.1.1.7 mrg }
525 1.1.1.7 mrg
526 1.1.1.7 mrg delta += d * w;
527 1.1.1.7 mrg w *= base - t;
528 1.1.1.7 mrg }
529 1.1.1.7 mrg while (d >= t);
530 1.1.1.7 mrg
531 1.1.1.7 mrg /* Compute the new insert position and character. */
532 1.1.1.7 mrg len++;
533 1.1.1.7 mrg i += delta;
534 1.1.1.7 mrg c += i / len;
535 1.1.1.7 mrg i %= len;
536 1.1.1.7 mrg
537 1.1.1.7 mrg /* Ensure enough space is available. */
538 1.1.1.7 mrg if (cap < len)
539 1.1.1.7 mrg {
540 1.1.1.7 mrg cap *= 2;
541 1.1.1.7 mrg /* Check for overflows. */
542 1.1.1.7 mrg if ((cap * 4) / 4 != cap || cap < len)
543 1.1.1.7 mrg {
544 1.1.1.7 mrg rdm->errored = 1;
545 1.1.1.7 mrg goto cleanup;
546 1.1.1.7 mrg }
547 1.1.1.7 mrg }
548 1.1.1.7 mrg p = (uint8_t *)realloc (out, cap * 4);
549 1.1.1.7 mrg if (!p)
550 1.1.1.7 mrg {
551 1.1.1.7 mrg rdm->errored = 1;
552 1.1.1.7 mrg goto cleanup;
553 1.1.1.7 mrg }
554 1.1.1.7 mrg out = p;
555 1.1.1.7 mrg
556 1.1.1.7 mrg /* Move the characters after the insert position. */
557 1.1.1.7 mrg p = out + i * 4;
558 1.1.1.7 mrg memmove (p + 4, p, (len - i - 1) * 4);
559 1.1.1.7 mrg
560 1.1.1.7 mrg /* Insert the new character, as UTF-8 bytes. */
561 1.1.1.7 mrg p[0] = c >= 0x10000 ? 0xf0 | (c >> 18) : 0;
562 1.1.1.7 mrg p[1] = c >= 0x800 ? (c < 0x10000 ? 0xe0 : 0x80) | ((c >> 12) & 0x3f) : 0;
563 1.1.1.7 mrg p[2] = (c < 0x800 ? 0xc0 : 0x80) | ((c >> 6) & 0x3f);
564 1.1.1.7 mrg p[3] = 0x80 | (c & 0x3f);
565 1.1.1.7 mrg
566 1.1.1.7 mrg /* If there are no more deltas, decoding is complete. */
567 1.1.1.7 mrg if (punycode_pos == ident.punycode_len)
568 1.1.1.7 mrg break;
569 1.1.1.7 mrg
570 1.1.1.7 mrg i++;
571 1.1.1.7 mrg
572 1.1.1.7 mrg /* Perform bias adaptation. */
573 1.1.1.7 mrg delta /= damp;
574 1.1.1.7 mrg damp = 2;
575 1.1.1.7 mrg
576 1.1.1.7 mrg delta += delta / len;
577 1.1.1.7 mrg k = 0;
578 1.1.1.7 mrg while (delta > ((base - t_min) * t_max) / 2)
579 1.1.1.7 mrg {
580 1.1.1.7 mrg delta /= base - t_min;
581 1.1.1.7 mrg k += base;
582 1.1.1.7 mrg }
583 1.1.1.7 mrg bias = k + ((base - t_min + 1) * delta) / (delta + skew);
584 1.1.1.7 mrg }
585 1.1.1.7 mrg
586 1.1.1.7 mrg /* Remove all the 0 bytes to leave behind an UTF-8 string. */
587 1.1.1.7 mrg for (i = 0, j = 0; i < len * 4; i++)
588 1.1.1.7 mrg if (out[i] != 0)
589 1.1.1.7 mrg out[j++] = out[i];
590 1.1.1.7 mrg
591 1.1.1.7 mrg print_str (rdm, (const char *)out, j);
592 1.1.1.7 mrg
593 1.1.1.7 mrg cleanup:
594 1.1.1.7 mrg free (out);
595 1.1.1.7 mrg }
596 1.1.1.7 mrg
597 1.1.1.7 mrg /* Print the lifetime according to the previously decoded index.
598 1.1.1.7 mrg An index of `0` always refers to `'_`, but starting with `1`,
599 1.1.1.7 mrg indices refer to late-bound lifetimes introduced by a binder. */
600 1.1.1.7 mrg static void
601 1.1.1.7 mrg print_lifetime_from_index (struct rust_demangler *rdm, uint64_t lt)
602 1.1.1.7 mrg {
603 1.1.1.7 mrg char c;
604 1.1.1.7 mrg uint64_t depth;
605 1.1.1.7 mrg
606 1.1.1.7 mrg PRINT ("'");
607 1.1.1.7 mrg if (lt == 0)
608 1.1.1.7 mrg {
609 1.1.1.7 mrg PRINT ("_");
610 1.1.1.7 mrg return;
611 1.1.1.7 mrg }
612 1.1.1.7 mrg
613 1.1.1.7 mrg depth = rdm->bound_lifetime_depth - lt;
614 1.1.1.7 mrg /* Try to print lifetimes alphabetically first. */
615 1.1.1.7 mrg if (depth < 26)
616 1.1.1.7 mrg {
617 1.1.1.7 mrg c = 'a' + depth;
618 1.1.1.7 mrg print_str (rdm, &c, 1);
619 1.1.1.7 mrg }
620 1.1.1.7 mrg else
621 1.1.1.7 mrg {
622 1.1.1.7 mrg /* Use `'_123` after running out of letters. */
623 1.1.1.7 mrg PRINT ("_");
624 1.1.1.7 mrg print_uint64 (rdm, depth);
625 1.1.1.7 mrg }
626 1.1.1.7 mrg }
627 1.1.1.7 mrg
628 1.1.1.7 mrg /* Demangling functions. */
629 1.1.1.7 mrg
630 1.1.1.7 mrg static void demangle_binder (struct rust_demangler *rdm);
631 1.1.1.7 mrg static void demangle_path (struct rust_demangler *rdm, int in_value);
632 1.1.1.7 mrg static void demangle_generic_arg (struct rust_demangler *rdm);
633 1.1.1.7 mrg static void demangle_type (struct rust_demangler *rdm);
634 1.1.1.7 mrg static int demangle_path_maybe_open_generics (struct rust_demangler *rdm);
635 1.1.1.7 mrg static void demangle_dyn_trait (struct rust_demangler *rdm);
636 1.1.1.7 mrg static void demangle_const (struct rust_demangler *rdm);
637 1.1.1.7 mrg static void demangle_const_uint (struct rust_demangler *rdm);
638 1.1.1.7 mrg static void demangle_const_int (struct rust_demangler *rdm);
639 1.1.1.7 mrg static void demangle_const_bool (struct rust_demangler *rdm);
640 1.1.1.7 mrg static void demangle_const_char (struct rust_demangler *rdm);
641 1.1.1.7 mrg
642 1.1.1.7 mrg /* Optionally enter a binder ('G') for late-bound lifetimes,
643 1.1.1.7 mrg printing e.g. `for<'a, 'b> `, and make those lifetimes visible
644 1.1.1.7 mrg to the caller (via depth level, which the caller should reset). */
645 1.1.1.7 mrg static void
646 1.1.1.7 mrg demangle_binder (struct rust_demangler *rdm)
647 1.1.1.7 mrg {
648 1.1.1.7 mrg uint64_t i, bound_lifetimes;
649 1.1.1.7 mrg
650 1.1.1.7 mrg if (rdm->errored)
651 1.1.1.7 mrg return;
652 1.1.1.7 mrg
653 1.1.1.7 mrg bound_lifetimes = parse_opt_integer_62 (rdm, 'G');
654 1.1.1.7 mrg if (bound_lifetimes > 0)
655 1.1.1.7 mrg {
656 1.1.1.7 mrg PRINT ("for<");
657 1.1.1.7 mrg for (i = 0; i < bound_lifetimes; i++)
658 1.1.1.7 mrg {
659 1.1.1.7 mrg if (i > 0)
660 1.1.1.7 mrg PRINT (", ");
661 1.1.1.7 mrg rdm->bound_lifetime_depth++;
662 1.1.1.7 mrg print_lifetime_from_index (rdm, 1);
663 1.1.1.7 mrg }
664 1.1.1.7 mrg PRINT ("> ");
665 1.1.1.7 mrg }
666 1.1.1.7 mrg }
667 1.1.1.7 mrg
668 1.1.1.7 mrg static void
669 1.1.1.7 mrg demangle_path (struct rust_demangler *rdm, int in_value)
670 1.1.1.7 mrg {
671 1.1.1.7 mrg char tag, ns;
672 1.1.1.7 mrg int was_skipping_printing;
673 1.1.1.7 mrg size_t i, backref, old_next;
674 1.1.1.7 mrg uint64_t dis;
675 1.1.1.7 mrg struct rust_mangled_ident name;
676 1.1.1.7 mrg
677 1.1.1.7 mrg if (rdm->errored)
678 1.1.1.7 mrg return;
679 1.1.1.7 mrg
680 1.1.1.7 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT)
681 1.1.1.7 mrg {
682 1.1.1.7 mrg ++ rdm->recursion;
683 1.1.1.7 mrg if (rdm->recursion > RUST_MAX_RECURSION_COUNT)
684 1.1.1.7 mrg /* FIXME: There ought to be a way to report
685 1.1.1.7 mrg that the recursion limit has been reached. */
686 1.1.1.7 mrg goto fail_return;
687 1.1.1.7 mrg }
688 1.1.1.7 mrg
689 1.1.1.7 mrg switch (tag = next (rdm))
690 1.1.1.7 mrg {
691 1.1.1.7 mrg case 'C':
692 1.1.1.7 mrg dis = parse_disambiguator (rdm);
693 1.1.1.7 mrg name = parse_ident (rdm);
694 1.1.1.7 mrg
695 1.1.1.7 mrg print_ident (rdm, name);
696 1.1.1.7 mrg if (rdm->verbose)
697 1.1.1.7 mrg {
698 1.1.1.7 mrg PRINT ("[");
699 1.1.1.7 mrg print_uint64_hex (rdm, dis);
700 1.1.1.7 mrg PRINT ("]");
701 1.1.1.7 mrg }
702 1.1.1.7 mrg break;
703 1.1.1.7 mrg case 'N':
704 1.1.1.7 mrg ns = next (rdm);
705 1.1.1.7 mrg if (!ISLOWER (ns) && !ISUPPER (ns))
706 1.1.1.7 mrg goto fail_return;
707 1.1.1.7 mrg
708 1.1.1.7 mrg demangle_path (rdm, in_value);
709 1.1.1.7 mrg
710 1.1.1.7 mrg dis = parse_disambiguator (rdm);
711 1.1.1.7 mrg name = parse_ident (rdm);
712 1.1.1.7 mrg
713 1.1.1.7 mrg if (ISUPPER (ns))
714 1.1.1.7 mrg {
715 1.1.1.7 mrg /* Special namespaces, like closures and shims. */
716 1.1.1.7 mrg PRINT ("::{");
717 1.1.1.7 mrg switch (ns)
718 1.1.1.7 mrg {
719 1.1.1.7 mrg case 'C':
720 1.1.1.7 mrg PRINT ("closure");
721 1.1.1.7 mrg break;
722 1.1.1.7 mrg case 'S':
723 1.1.1.7 mrg PRINT ("shim");
724 1.1.1.7 mrg break;
725 1.1.1.7 mrg default:
726 1.1.1.7 mrg print_str (rdm, &ns, 1);
727 1.1.1.7 mrg }
728 1.1.1.7 mrg if (name.ascii || name.punycode)
729 1.1.1.7 mrg {
730 1.1.1.7 mrg PRINT (":");
731 1.1.1.7 mrg print_ident (rdm, name);
732 1.1.1.7 mrg }
733 1.1.1.7 mrg PRINT ("#");
734 1.1.1.7 mrg print_uint64 (rdm, dis);
735 1.1.1.7 mrg PRINT ("}");
736 1.1.1.7 mrg }
737 1.1.1.7 mrg else
738 1.1.1.7 mrg {
739 1.1.1.7 mrg /* Implementation-specific/unspecified namespaces. */
740 1.1.1.7 mrg
741 1.1.1.7 mrg if (name.ascii || name.punycode)
742 1.1.1.7 mrg {
743 1.1.1.7 mrg PRINT ("::");
744 1.1.1.7 mrg print_ident (rdm, name);
745 1.1.1.7 mrg }
746 1.1.1.7 mrg }
747 1.1.1.7 mrg break;
748 1.1.1.7 mrg case 'M':
749 1.1.1.7 mrg case 'X':
750 1.1.1.7 mrg /* Ignore the `impl`'s own path.*/
751 1.1.1.7 mrg parse_disambiguator (rdm);
752 1.1.1.7 mrg was_skipping_printing = rdm->skipping_printing;
753 1.1.1.7 mrg rdm->skipping_printing = 1;
754 1.1.1.7 mrg demangle_path (rdm, in_value);
755 1.1.1.7 mrg rdm->skipping_printing = was_skipping_printing;
756 1.1.1.7 mrg /* fallthrough */
757 1.1.1.7 mrg case 'Y':
758 1.1.1.7 mrg PRINT ("<");
759 1.1.1.7 mrg demangle_type (rdm);
760 1.1.1.7 mrg if (tag != 'M')
761 1.1.1.7 mrg {
762 1.1.1.7 mrg PRINT (" as ");
763 1.1.1.7 mrg demangle_path (rdm, 0);
764 1.1.1.7 mrg }
765 1.1.1.7 mrg PRINT (">");
766 1.1.1.7 mrg break;
767 1.1.1.7 mrg case 'I':
768 1.1.1.7 mrg demangle_path (rdm, in_value);
769 1.1.1.7 mrg if (in_value)
770 1.1.1.7 mrg PRINT ("::");
771 1.1.1.7 mrg PRINT ("<");
772 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
773 1.1.1.7 mrg {
774 1.1.1.7 mrg if (i > 0)
775 1.1.1.7 mrg PRINT (", ");
776 1.1.1.7 mrg demangle_generic_arg (rdm);
777 1.1.1.7 mrg }
778 1.1.1.7 mrg PRINT (">");
779 1.1.1.7 mrg break;
780 1.1.1.7 mrg case 'B':
781 1.1.1.7 mrg backref = parse_integer_62 (rdm);
782 1.1.1.7 mrg if (!rdm->skipping_printing)
783 1.1.1.7 mrg {
784 1.1.1.7 mrg old_next = rdm->next;
785 1.1.1.7 mrg rdm->next = backref;
786 1.1.1.7 mrg demangle_path (rdm, in_value);
787 1.1.1.7 mrg rdm->next = old_next;
788 1.1.1.7 mrg }
789 1.1.1.7 mrg break;
790 1.1.1.7 mrg default:
791 1.1.1.7 mrg goto fail_return;
792 1.1.1.7 mrg }
793 1.1.1.7 mrg goto pass_return;
794 1.1.1.7 mrg
795 1.1.1.7 mrg fail_return:
796 1.1.1.7 mrg rdm->errored = 1;
797 1.1.1.7 mrg pass_return:
798 1.1.1.7 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT)
799 1.1.1.7 mrg -- rdm->recursion;
800 1.1.1.7 mrg }
801 1.1.1.7 mrg
802 1.1.1.7 mrg static void
803 1.1.1.7 mrg demangle_generic_arg (struct rust_demangler *rdm)
804 1.1.1.7 mrg {
805 1.1.1.7 mrg uint64_t lt;
806 1.1.1.7 mrg if (eat (rdm, 'L'))
807 1.1.1.7 mrg {
808 1.1.1.7 mrg lt = parse_integer_62 (rdm);
809 1.1.1.7 mrg print_lifetime_from_index (rdm, lt);
810 1.1.1.7 mrg }
811 1.1.1.7 mrg else if (eat (rdm, 'K'))
812 1.1.1.7 mrg demangle_const (rdm);
813 1.1.1.7 mrg else
814 1.1.1.7 mrg demangle_type (rdm);
815 1.1.1.7 mrg }
816 1.1.1.7 mrg
817 1.1.1.7 mrg static const char *
818 1.1.1.7 mrg basic_type (char tag)
819 1.1.1.7 mrg {
820 1.1.1.7 mrg switch (tag)
821 1.1.1.7 mrg {
822 1.1.1.7 mrg case 'b':
823 1.1.1.7 mrg return "bool";
824 1.1.1.7 mrg case 'c':
825 1.1.1.7 mrg return "char";
826 1.1.1.7 mrg case 'e':
827 1.1.1.7 mrg return "str";
828 1.1.1.7 mrg case 'u':
829 1.1.1.7 mrg return "()";
830 1.1.1.7 mrg case 'a':
831 1.1.1.7 mrg return "i8";
832 1.1.1.7 mrg case 's':
833 1.1.1.7 mrg return "i16";
834 1.1.1.7 mrg case 'l':
835 1.1.1.7 mrg return "i32";
836 1.1.1.7 mrg case 'x':
837 1.1.1.7 mrg return "i64";
838 1.1.1.7 mrg case 'n':
839 1.1.1.7 mrg return "i128";
840 1.1.1.7 mrg case 'i':
841 1.1.1.7 mrg return "isize";
842 1.1.1.7 mrg case 'h':
843 1.1.1.7 mrg return "u8";
844 1.1.1.7 mrg case 't':
845 1.1.1.7 mrg return "u16";
846 1.1.1.7 mrg case 'm':
847 1.1.1.7 mrg return "u32";
848 1.1.1.7 mrg case 'y':
849 1.1.1.7 mrg return "u64";
850 1.1.1.7 mrg case 'o':
851 1.1.1.7 mrg return "u128";
852 1.1.1.7 mrg case 'j':
853 1.1.1.7 mrg return "usize";
854 1.1.1.7 mrg case 'f':
855 1.1.1.7 mrg return "f32";
856 1.1.1.7 mrg case 'd':
857 1.1.1.7 mrg return "f64";
858 1.1.1.7 mrg case 'z':
859 1.1.1.7 mrg return "!";
860 1.1.1.7 mrg case 'p':
861 1.1.1.7 mrg return "_";
862 1.1.1.7 mrg case 'v':
863 1.1.1.7 mrg return "...";
864 1.1.1.7 mrg
865 1.1.1.7 mrg default:
866 1.1.1.7 mrg return NULL;
867 1.1.1.7 mrg }
868 1.1.1.7 mrg }
869 1.1.1.7 mrg
870 1.1.1.7 mrg static void
871 1.1.1.7 mrg demangle_type (struct rust_demangler *rdm)
872 1.1.1.7 mrg {
873 1.1.1.7 mrg char tag;
874 1.1.1.7 mrg size_t i, old_next, backref;
875 1.1.1.7 mrg uint64_t lt, old_bound_lifetime_depth;
876 1.1.1.7 mrg const char *basic;
877 1.1.1.7 mrg struct rust_mangled_ident abi;
878 1.1.1.7 mrg
879 1.1.1.7 mrg if (rdm->errored)
880 1.1.1.7 mrg return;
881 1.1.1.7 mrg
882 1.1.1.7 mrg tag = next (rdm);
883 1.1.1.7 mrg
884 1.1.1.7 mrg basic = basic_type (tag);
885 1.1.1.7 mrg if (basic)
886 1.1.1.7 mrg {
887 1.1.1.7 mrg PRINT (basic);
888 1.1.1.7 mrg return;
889 1.1.1.7 mrg }
890 1.1.1.7 mrg
891 1.1.1.7 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT)
892 1.1.1.7 mrg {
893 1.1.1.7 mrg ++ rdm->recursion;
894 1.1.1.7 mrg if (rdm->recursion > RUST_MAX_RECURSION_COUNT)
895 1.1.1.7 mrg /* FIXME: There ought to be a way to report
896 1.1.1.7 mrg that the recursion limit has been reached. */
897 1.1.1.7 mrg {
898 1.1.1.7 mrg rdm->errored = 1;
899 1.1.1.7 mrg -- rdm->recursion;
900 1.1.1.7 mrg return;
901 1.1.1.7 mrg }
902 1.1.1.7 mrg }
903 1.1.1.7 mrg
904 1.1.1.7 mrg switch (tag)
905 1.1.1.7 mrg {
906 1.1.1.7 mrg case 'R':
907 1.1.1.7 mrg case 'Q':
908 1.1.1.7 mrg PRINT ("&");
909 1.1.1.7 mrg if (eat (rdm, 'L'))
910 1.1.1.7 mrg {
911 1.1.1.7 mrg lt = parse_integer_62 (rdm);
912 1.1.1.7 mrg if (lt)
913 1.1.1.7 mrg {
914 1.1.1.7 mrg print_lifetime_from_index (rdm, lt);
915 1.1.1.7 mrg PRINT (" ");
916 1.1.1.7 mrg }
917 1.1.1.7 mrg }
918 1.1.1.7 mrg if (tag != 'R')
919 1.1.1.7 mrg PRINT ("mut ");
920 1.1.1.7 mrg demangle_type (rdm);
921 1.1.1.7 mrg break;
922 1.1.1.7 mrg case 'P':
923 1.1.1.7 mrg case 'O':
924 1.1.1.7 mrg PRINT ("*");
925 1.1.1.7 mrg if (tag != 'P')
926 1.1.1.7 mrg PRINT ("mut ");
927 1.1.1.7 mrg else
928 1.1.1.7 mrg PRINT ("const ");
929 1.1.1.7 mrg demangle_type (rdm);
930 1.1.1.7 mrg break;
931 1.1.1.7 mrg case 'A':
932 1.1.1.7 mrg case 'S':
933 1.1.1.7 mrg PRINT ("[");
934 1.1.1.7 mrg demangle_type (rdm);
935 1.1.1.7 mrg if (tag == 'A')
936 1.1.1.7 mrg {
937 1.1.1.7 mrg PRINT ("; ");
938 1.1.1.7 mrg demangle_const (rdm);
939 1.1.1.7 mrg }
940 1.1.1.7 mrg PRINT ("]");
941 1.1.1.7 mrg break;
942 1.1.1.7 mrg case 'T':
943 1.1.1.7 mrg PRINT ("(");
944 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
945 1.1.1.7 mrg {
946 1.1.1.7 mrg if (i > 0)
947 1.1.1.7 mrg PRINT (", ");
948 1.1.1.7 mrg demangle_type (rdm);
949 1.1.1.7 mrg }
950 1.1.1.7 mrg if (i == 1)
951 1.1.1.7 mrg PRINT (",");
952 1.1.1.7 mrg PRINT (")");
953 1.1.1.7 mrg break;
954 1.1.1.7 mrg case 'F':
955 1.1.1.7 mrg old_bound_lifetime_depth = rdm->bound_lifetime_depth;
956 1.1.1.7 mrg demangle_binder (rdm);
957 1.1.1.7 mrg
958 1.1.1.7 mrg if (eat (rdm, 'U'))
959 1.1.1.7 mrg PRINT ("unsafe ");
960 1.1.1.7 mrg
961 1.1.1.7 mrg if (eat (rdm, 'K'))
962 1.1.1.7 mrg {
963 1.1.1.7 mrg if (eat (rdm, 'C'))
964 1.1.1.7 mrg {
965 1.1.1.7 mrg abi.ascii = "C";
966 1.1.1.7 mrg abi.ascii_len = 1;
967 1.1.1.7 mrg }
968 1.1.1.7 mrg else
969 1.1.1.7 mrg {
970 1.1.1.7 mrg abi = parse_ident (rdm);
971 1.1.1.7 mrg if (!abi.ascii || abi.punycode)
972 1.1.1.7 mrg {
973 1.1.1.7 mrg rdm->errored = 1;
974 1.1.1.7 mrg goto restore;
975 1.1.1.7 mrg }
976 1.1.1.7 mrg }
977 1.1.1.7 mrg
978 1.1.1.7 mrg PRINT ("extern \"");
979 1.1.1.7 mrg
980 1.1.1.7 mrg /* If the ABI had any `-`, they were replaced with `_`,
981 1.1.1.7 mrg so the parts between `_` have to be re-joined with `-`. */
982 1.1.1.7 mrg for (i = 0; i < abi.ascii_len; i++)
983 1.1.1.7 mrg {
984 1.1.1.7 mrg if (abi.ascii[i] == '_')
985 1.1.1.7 mrg {
986 1.1.1.7 mrg print_str (rdm, abi.ascii, i);
987 1.1.1.7 mrg PRINT ("-");
988 1.1.1.7 mrg abi.ascii += i + 1;
989 1.1.1.7 mrg abi.ascii_len -= i + 1;
990 1.1.1.7 mrg i = 0;
991 1.1.1.7 mrg }
992 1.1.1.7 mrg }
993 1.1.1.7 mrg print_str (rdm, abi.ascii, abi.ascii_len);
994 1.1.1.7 mrg
995 1.1.1.7 mrg PRINT ("\" ");
996 1.1.1.7 mrg }
997 1.1.1.7 mrg
998 1.1.1.7 mrg PRINT ("fn(");
999 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
1000 1.1.1.7 mrg {
1001 1.1.1.7 mrg if (i > 0)
1002 1.1.1.7 mrg PRINT (", ");
1003 1.1.1.7 mrg demangle_type (rdm);
1004 1.1.1.7 mrg }
1005 1.1.1.7 mrg PRINT (")");
1006 1.1.1.7 mrg
1007 1.1.1.7 mrg if (eat (rdm, 'u'))
1008 1.1.1.7 mrg {
1009 1.1.1.7 mrg /* Skip printing the return type if it's 'u', i.e. `()`. */
1010 1.1.1.7 mrg }
1011 1.1.1.7 mrg else
1012 1.1.1.7 mrg {
1013 1.1.1.7 mrg PRINT (" -> ");
1014 1.1.1.7 mrg demangle_type (rdm);
1015 1.1.1.7 mrg }
1016 1.1.1.7 mrg
1017 1.1.1.7 mrg /* Restore `bound_lifetime_depth` to outside the binder. */
1018 1.1.1.7 mrg restore:
1019 1.1.1.7 mrg rdm->bound_lifetime_depth = old_bound_lifetime_depth;
1020 1.1.1.7 mrg break;
1021 1.1.1.7 mrg case 'D':
1022 1.1.1.7 mrg PRINT ("dyn ");
1023 1.1.1.7 mrg
1024 1.1.1.7 mrg old_bound_lifetime_depth = rdm->bound_lifetime_depth;
1025 1.1.1.7 mrg demangle_binder (rdm);
1026 1.1.1.7 mrg
1027 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
1028 1.1.1.7 mrg {
1029 1.1.1.7 mrg if (i > 0)
1030 1.1.1.7 mrg PRINT (" + ");
1031 1.1.1.7 mrg demangle_dyn_trait (rdm);
1032 1.1.1.7 mrg }
1033 1.1.1.7 mrg
1034 1.1.1.7 mrg /* Restore `bound_lifetime_depth` to outside the binder. */
1035 1.1.1.7 mrg rdm->bound_lifetime_depth = old_bound_lifetime_depth;
1036 1.1.1.7 mrg
1037 1.1.1.7 mrg if (!eat (rdm, 'L'))
1038 1.1.1.7 mrg {
1039 1.1.1.7 mrg rdm->errored = 1;
1040 1.1.1.7 mrg return;
1041 1.1.1.7 mrg }
1042 1.1.1.7 mrg lt = parse_integer_62 (rdm);
1043 1.1.1.7 mrg if (lt)
1044 1.1.1.7 mrg {
1045 1.1.1.7 mrg PRINT (" + ");
1046 1.1.1.7 mrg print_lifetime_from_index (rdm, lt);
1047 1.1.1.7 mrg }
1048 1.1.1.7 mrg break;
1049 1.1.1.7 mrg case 'B':
1050 1.1.1.7 mrg backref = parse_integer_62 (rdm);
1051 1.1.1.7 mrg if (!rdm->skipping_printing)
1052 1.1.1.7 mrg {
1053 1.1.1.7 mrg old_next = rdm->next;
1054 1.1.1.7 mrg rdm->next = backref;
1055 1.1.1.7 mrg demangle_type (rdm);
1056 1.1.1.7 mrg rdm->next = old_next;
1057 1.1.1.7 mrg }
1058 1.1.1.7 mrg break;
1059 1.1.1.7 mrg default:
1060 1.1.1.7 mrg /* Go back to the tag, so `demangle_path` also sees it. */
1061 1.1.1.7 mrg rdm->next--;
1062 1.1.1.7 mrg demangle_path (rdm, 0);
1063 1.1.1.7 mrg }
1064 1.1.1.7 mrg
1065 1.1.1.7 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT)
1066 1.1.1.7 mrg -- rdm->recursion;
1067 1.1.1.7 mrg }
1068 1.1.1.7 mrg
1069 1.1.1.7 mrg /* A trait in a trait object may have some "existential projections"
1070 1.1.1.7 mrg (i.e. associated type bindings) after it, which should be printed
1071 1.1.1.7 mrg in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`.
1072 1.1.1.7 mrg To this end, this method will keep the `<...>` of an 'I' path
1073 1.1.1.7 mrg open, by omitting the `>`, and return `Ok(true)` in that case. */
1074 1.1.1.7 mrg static int
1075 1.1.1.7 mrg demangle_path_maybe_open_generics (struct rust_demangler *rdm)
1076 1.1.1.7 mrg {
1077 1.1.1.7 mrg int open;
1078 1.1.1.7 mrg size_t i, old_next, backref;
1079 1.1.1.7 mrg
1080 1.1.1.7 mrg open = 0;
1081 1.1.1.7 mrg
1082 1.1.1.7 mrg if (rdm->errored)
1083 1.1.1.7 mrg return open;
1084 1.1.1.7 mrg
1085 1.1.1.7 mrg if (eat (rdm, 'B'))
1086 1.1.1.7 mrg {
1087 1.1.1.7 mrg backref = parse_integer_62 (rdm);
1088 1.1.1.7 mrg if (!rdm->skipping_printing)
1089 1.1.1.7 mrg {
1090 1.1.1.7 mrg old_next = rdm->next;
1091 1.1.1.7 mrg rdm->next = backref;
1092 1.1.1.7 mrg open = demangle_path_maybe_open_generics (rdm);
1093 1.1.1.7 mrg rdm->next = old_next;
1094 1.1.1.7 mrg }
1095 1.1.1.7 mrg }
1096 1.1.1.7 mrg else if (eat (rdm, 'I'))
1097 1.1.1.7 mrg {
1098 1.1.1.7 mrg demangle_path (rdm, 0);
1099 1.1.1.7 mrg PRINT ("<");
1100 1.1.1.7 mrg open = 1;
1101 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++)
1102 1.1.1.7 mrg {
1103 1.1.1.7 mrg if (i > 0)
1104 1.1.1.7 mrg PRINT (", ");
1105 1.1.1.7 mrg demangle_generic_arg (rdm);
1106 1.1.1.7 mrg }
1107 1.1.1.7 mrg }
1108 1.1.1.7 mrg else
1109 1.1.1.7 mrg demangle_path (rdm, 0);
1110 1.1.1.7 mrg return open;
1111 1.1.1.7 mrg }
1112 1.1.1.7 mrg
1113 1.1.1.7 mrg static void
1114 1.1.1.7 mrg demangle_dyn_trait (struct rust_demangler *rdm)
1115 1.1.1.7 mrg {
1116 1.1.1.7 mrg int open;
1117 1.1.1.7 mrg struct rust_mangled_ident name;
1118 1.1.1.7 mrg
1119 1.1.1.7 mrg if (rdm->errored)
1120 1.1.1.7 mrg return;
1121 1.1.1.7 mrg
1122 1.1.1.7 mrg open = demangle_path_maybe_open_generics (rdm);
1123 1.1.1.7 mrg
1124 1.1.1.7 mrg while (eat (rdm, 'p'))
1125 1.1.1.7 mrg {
1126 1.1.1.7 mrg if (!open)
1127 1.1.1.7 mrg PRINT ("<");
1128 1.1.1.7 mrg else
1129 1.1.1.7 mrg PRINT (", ");
1130 1.1.1.7 mrg open = 1;
1131 1.1.1.7 mrg
1132 1.1.1.7 mrg name = parse_ident (rdm);
1133 1.1.1.7 mrg print_ident (rdm, name);
1134 1.1.1.7 mrg PRINT (" = ");
1135 1.1.1.7 mrg demangle_type (rdm);
1136 1.1.1.7 mrg }
1137 1.1.1.7 mrg
1138 1.1.1.7 mrg if (open)
1139 1.1.1.7 mrg PRINT (">");
1140 1.1.1.7 mrg }
1141 1.1.1.7 mrg
1142 1.1.1.7 mrg static void
1143 1.1.1.7 mrg demangle_const (struct rust_demangler *rdm)
1144 1.1.1.7 mrg {
1145 1.1.1.7 mrg char ty_tag;
1146 1.1.1.7 mrg size_t old_next, backref;
1147 1.1.1.7 mrg
1148 1.1.1.7 mrg if (rdm->errored)
1149 1.1.1.7 mrg return;
1150 1.1.1.7 mrg
1151 1.1.1.7 mrg if (eat (rdm, 'B'))
1152 1.1.1.7 mrg {
1153 1.1.1.7 mrg backref = parse_integer_62 (rdm);
1154 1.1.1.7 mrg if (!rdm->skipping_printing)
1155 1.1.1.7 mrg {
1156 1.1.1.7 mrg old_next = rdm->next;
1157 1.1.1.7 mrg rdm->next = backref;
1158 1.1.1.7 mrg demangle_const (rdm);
1159 1.1.1.7 mrg rdm->next = old_next;
1160 1.1.1.7 mrg }
1161 1.1.1.7 mrg return;
1162 1.1.1.7 mrg }
1163 1.1.1.7 mrg
1164 1.1.1.7 mrg ty_tag = next (rdm);
1165 1.1.1.7 mrg switch (ty_tag)
1166 1.1.1.7 mrg {
1167 1.1.1.7 mrg /* Placeholder. */
1168 1.1.1.7 mrg case 'p':
1169 1.1.1.7 mrg PRINT ("_");
1170 1.1.1.7 mrg return;
1171 1.1.1.7 mrg
1172 1.1.1.7 mrg /* Unsigned integer types. */
1173 1.1.1.7 mrg case 'h':
1174 1.1.1.7 mrg case 't':
1175 1.1.1.7 mrg case 'm':
1176 1.1.1.7 mrg case 'y':
1177 1.1.1.7 mrg case 'o':
1178 1.1.1.7 mrg case 'j':
1179 1.1.1.7 mrg demangle_const_uint (rdm);
1180 1.1.1.7 mrg break;
1181 1.1.1.7 mrg
1182 1.1.1.7 mrg /* Signed integer types. */
1183 1.1.1.7 mrg case 'a':
1184 1.1.1.7 mrg case 's':
1185 1.1.1.7 mrg case 'l':
1186 1.1.1.7 mrg case 'x':
1187 1.1.1.7 mrg case 'n':
1188 1.1.1.7 mrg case 'i':
1189 1.1.1.7 mrg demangle_const_int (rdm);
1190 1.1.1.7 mrg break;
1191 1.1.1.7 mrg
1192 1.1.1.7 mrg /* Boolean. */
1193 1.1.1.7 mrg case 'b':
1194 1.1.1.7 mrg demangle_const_bool (rdm);
1195 1.1.1.7 mrg break;
1196 1.1.1.7 mrg
1197 1.1.1.7 mrg /* Character. */
1198 1.1.1.7 mrg case 'c':
1199 1.1.1.7 mrg demangle_const_char (rdm);
1200 1.1.1.7 mrg break;
1201 1.1.1.7 mrg
1202 1.1.1.7 mrg default:
1203 1.1.1.7 mrg rdm->errored = 1;
1204 1.1.1.7 mrg return;
1205 1.1.1.7 mrg }
1206 1.1.1.7 mrg
1207 1.1.1.7 mrg if (rdm->errored)
1208 1.1.1.7 mrg return;
1209 1.1.1.7 mrg
1210 1.1.1.7 mrg if (rdm->verbose)
1211 1.1.1.7 mrg {
1212 1.1.1.7 mrg PRINT (": ");
1213 1.1.1.7 mrg PRINT (basic_type (ty_tag));
1214 1.1.1.7 mrg }
1215 1.1.1.7 mrg }
1216 1.1.1.7 mrg
1217 1.1.1.7 mrg static void
1218 1.1.1.7 mrg demangle_const_uint (struct rust_demangler *rdm)
1219 1.1.1.7 mrg {
1220 1.1.1.7 mrg size_t hex_len;
1221 1.1.1.7 mrg uint64_t value;
1222 1.1.1.7 mrg
1223 1.1.1.7 mrg if (rdm->errored)
1224 1.1.1.7 mrg return;
1225 1.1.1.7 mrg
1226 1.1.1.7 mrg hex_len = parse_hex_nibbles (rdm, &value);
1227 1.1.1.7 mrg
1228 1.1.1.7 mrg if (hex_len > 16)
1229 1.1.1.7 mrg {
1230 1.1.1.7 mrg /* Print anything that doesn't fit in `uint64_t` verbatim. */
1231 1.1.1.7 mrg PRINT ("0x");
1232 1.1.1.7 mrg print_str (rdm, rdm->sym + (rdm->next - hex_len), hex_len);
1233 1.1.1.7 mrg }
1234 1.1.1.7 mrg else if (hex_len > 0)
1235 1.1.1.7 mrg print_uint64 (rdm, value);
1236 1.1.1.7 mrg else
1237 1.1.1.7 mrg rdm->errored = 1;
1238 1.1.1.7 mrg }
1239 1.1.1.7 mrg
1240 1.1.1.7 mrg static void
1241 1.1.1.7 mrg demangle_const_int (struct rust_demangler *rdm)
1242 1.1.1.7 mrg {
1243 1.1.1.7 mrg if (eat (rdm, 'n'))
1244 1.1.1.7 mrg PRINT ("-");
1245 1.1.1.7 mrg demangle_const_uint (rdm);
1246 1.1.1.7 mrg }
1247 1.1.1.7 mrg
1248 1.1.1.7 mrg static void
1249 1.1.1.7 mrg demangle_const_bool (struct rust_demangler *rdm)
1250 1.1.1.7 mrg {
1251 1.1.1.7 mrg uint64_t value;
1252 1.1.1.7 mrg
1253 1.1.1.7 mrg if (parse_hex_nibbles (rdm, &value) != 1)
1254 1.1.1.7 mrg {
1255 1.1.1.7 mrg rdm->errored = 1;
1256 1.1.1.7 mrg return;
1257 1.1.1.7 mrg }
1258 1.1.1.7 mrg
1259 1.1.1.7 mrg if (value == 0)
1260 1.1.1.7 mrg PRINT ("false");
1261 1.1.1.7 mrg else if (value == 1)
1262 1.1.1.7 mrg PRINT ("true");
1263 1.1.1.7 mrg else
1264 1.1.1.7 mrg rdm->errored = 1;
1265 1.1.1.7 mrg }
1266 1.1.1.7 mrg
1267 1.1.1.7 mrg static void
1268 1.1.1.7 mrg demangle_const_char (struct rust_demangler *rdm)
1269 1.1.1.7 mrg {
1270 1.1.1.7 mrg size_t hex_len;
1271 1.1.1.7 mrg uint64_t value;
1272 1.1.1.7 mrg
1273 1.1.1.7 mrg hex_len = parse_hex_nibbles (rdm, &value);
1274 1.1.1.7 mrg
1275 1.1.1.7 mrg if (hex_len == 0 || hex_len > 8)
1276 1.1.1.7 mrg {
1277 1.1.1.7 mrg rdm->errored = 1;
1278 1.1.1.7 mrg return;
1279 1.1.1.7 mrg }
1280 1.1.1.7 mrg
1281 1.1.1.7 mrg /* Match Rust's character "debug" output as best as we can. */
1282 1.1.1.7 mrg PRINT ("'");
1283 1.1.1.7 mrg if (value == '\t')
1284 1.1.1.7 mrg PRINT ("\\t");
1285 1.1.1.7 mrg else if (value == '\r')
1286 1.1.1.7 mrg PRINT ("\\r");
1287 1.1.1.7 mrg else if (value == '\n')
1288 1.1.1.7 mrg PRINT ("\\n");
1289 1.1.1.7 mrg else if (value > ' ' && value < '~')
1290 1.1.1.7 mrg {
1291 1.1.1.7 mrg /* Rust also considers many non-ASCII codepoints to be printable, but
1292 1.1.1.7 mrg that logic is not easily ported to C. */
1293 1.1.1.7 mrg char c = value;
1294 1.1.1.7 mrg print_str (rdm, &c, 1);
1295 1.1.1.7 mrg }
1296 1.1.1.7 mrg else
1297 1.1.1.7 mrg {
1298 1.1.1.7 mrg PRINT ("\\u{");
1299 1.1.1.7 mrg print_uint64_hex (rdm, value);
1300 1.1.1.7 mrg PRINT ("}");
1301 1.1.1.7 mrg }
1302 1.1.1.7 mrg PRINT ("'");
1303 1.1.1.6 mrg }
1304 1.1.1.6 mrg
1305 1.1.1.6 mrg /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
1306 1.1.1.6 mrg The hex digits must contain at least 5 distinct digits. */
1307 1.1 mrg static int
1308 1.1.1.6 mrg is_legacy_prefixed_hash (struct rust_mangled_ident ident)
1309 1.1 mrg {
1310 1.1.1.6 mrg uint16_t seen;
1311 1.1.1.6 mrg int nibble;
1312 1.1.1.6 mrg size_t i, count;
1313 1.1 mrg
1314 1.1.1.6 mrg if (ident.ascii_len != 17 || ident.ascii[0] != 'h')
1315 1.1 mrg return 0;
1316 1.1 mrg
1317 1.1.1.6 mrg seen = 0;
1318 1.1.1.6 mrg for (i = 0; i < 16; i++)
1319 1.1.1.6 mrg {
1320 1.1.1.6 mrg nibble = decode_lower_hex_nibble (ident.ascii[1 + i]);
1321 1.1.1.6 mrg if (nibble < 0)
1322 1.1.1.6 mrg return 0;
1323 1.1.1.6 mrg seen |= (uint16_t)1 << nibble;
1324 1.1.1.6 mrg }
1325 1.1 mrg
1326 1.1.1.6 mrg /* Count how many distinct digits were seen. */
1327 1.1 mrg count = 0;
1328 1.1.1.6 mrg while (seen)
1329 1.1.1.6 mrg {
1330 1.1.1.6 mrg if (seen & 1)
1331 1.1.1.6 mrg count++;
1332 1.1.1.6 mrg seen >>= 1;
1333 1.1.1.6 mrg }
1334 1.1 mrg
1335 1.1.1.6 mrg return count >= 5;
1336 1.1 mrg }
1337 1.1 mrg
1338 1.1.1.6 mrg int
1339 1.1.1.6 mrg rust_demangle_callback (const char *mangled, int options,
1340 1.1.1.6 mrg demangle_callbackref callback, void *opaque)
1341 1.1 mrg {
1342 1.1.1.6 mrg const char *p;
1343 1.1.1.6 mrg struct rust_demangler rdm;
1344 1.1.1.6 mrg struct rust_mangled_ident ident;
1345 1.1.1.6 mrg
1346 1.1.1.6 mrg rdm.sym = mangled;
1347 1.1.1.6 mrg rdm.sym_len = 0;
1348 1.1.1.6 mrg
1349 1.1.1.6 mrg rdm.callback_opaque = opaque;
1350 1.1.1.6 mrg rdm.callback = callback;
1351 1.1.1.6 mrg
1352 1.1.1.6 mrg rdm.next = 0;
1353 1.1.1.6 mrg rdm.errored = 0;
1354 1.1.1.7 mrg rdm.skipping_printing = 0;
1355 1.1.1.6 mrg rdm.verbose = (options & DMGL_VERBOSE) != 0;
1356 1.1.1.6 mrg rdm.version = 0;
1357 1.1.1.7 mrg rdm.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0;
1358 1.1.1.7 mrg rdm.bound_lifetime_depth = 0;
1359 1.1.1.6 mrg
1360 1.1.1.7 mrg /* Rust symbols always start with _R (v0) or _ZN (legacy). */
1361 1.1.1.7 mrg if (rdm.sym[0] == '_' && rdm.sym[1] == 'R')
1362 1.1.1.7 mrg rdm.sym += 2;
1363 1.1.1.7 mrg else if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N')
1364 1.1.1.6 mrg {
1365 1.1.1.6 mrg rdm.sym += 3;
1366 1.1.1.6 mrg rdm.version = -1;
1367 1.1.1.6 mrg }
1368 1.1.1.6 mrg else
1369 1.1.1.6 mrg return 0;
1370 1.1.1.6 mrg
1371 1.1.1.7 mrg /* Paths (v0) always start with uppercase characters. */
1372 1.1.1.7 mrg if (rdm.version != -1 && !ISUPPER (rdm.sym[0]))
1373 1.1.1.7 mrg return 0;
1374 1.1.1.7 mrg
1375 1.1.1.7 mrg /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */
1376 1.1.1.6 mrg for (p = rdm.sym; *p; p++)
1377 1.1.1.6 mrg {
1378 1.1.1.7 mrg /* Rust v0 symbols can have '.' suffixes, ignore those. */
1379 1.1.1.7 mrg if (rdm.version == 0 && *p == '.')
1380 1.1.1.7 mrg break;
1381 1.1.1.7 mrg
1382 1.1.1.6 mrg rdm.sym_len++;
1383 1.1 mrg
1384 1.1.1.6 mrg if (*p == '_' || ISALNUM (*p))
1385 1.1.1.6 mrg continue;
1386 1.1 mrg
1387 1.1.1.7 mrg /* Legacy Rust symbols can also contain [.:$] characters.
1388 1.1.1.7 mrg Or @ in the .suffix (which will be skipped, see below). */
1389 1.1.1.7 mrg if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':'
1390 1.1.1.7 mrg || *p == '@'))
1391 1.1.1.6 mrg continue;
1392 1.1.1.6 mrg
1393 1.1.1.6 mrg return 0;
1394 1.1.1.6 mrg }
1395 1.1.1.6 mrg
1396 1.1.1.6 mrg /* Legacy Rust symbols need to be handled separately. */
1397 1.1.1.6 mrg if (rdm.version == -1)
1398 1.1.1.6 mrg {
1399 1.1.1.7 mrg /* Legacy Rust symbols always end with E. But can be followed by a
1400 1.1.1.7 mrg .suffix (which we want to ignore). */
1401 1.1.1.7 mrg int dot_suffix = 1;
1402 1.1.1.7 mrg while (rdm.sym_len > 0 &&
1403 1.1.1.7 mrg !(dot_suffix && rdm.sym[rdm.sym_len - 1] == 'E'))
1404 1.1.1.7 mrg {
1405 1.1.1.7 mrg dot_suffix = rdm.sym[rdm.sym_len - 1] == '.';
1406 1.1.1.7 mrg rdm.sym_len--;
1407 1.1.1.7 mrg }
1408 1.1.1.7 mrg
1409 1.1.1.6 mrg if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E'))
1410 1.1.1.6 mrg return 0;
1411 1.1.1.6 mrg rdm.sym_len--;
1412 1.1.1.6 mrg
1413 1.1.1.6 mrg /* Legacy Rust symbols also always end with a path segment
1414 1.1.1.6 mrg that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
1415 1.1.1.6 mrg This early check, before any parse_ident calls, should
1416 1.1.1.6 mrg quickly filter out most C++ symbols unrelated to Rust. */
1417 1.1.1.6 mrg if (!(rdm.sym_len > 19
1418 1.1.1.6 mrg && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3)))
1419 1.1.1.6 mrg return 0;
1420 1.1.1.6 mrg
1421 1.1.1.6 mrg do
1422 1.1.1.6 mrg {
1423 1.1.1.6 mrg ident = parse_ident (&rdm);
1424 1.1.1.6 mrg if (rdm.errored || !ident.ascii)
1425 1.1.1.6 mrg return 0;
1426 1.1.1.6 mrg }
1427 1.1.1.6 mrg while (rdm.next < rdm.sym_len);
1428 1.1.1.6 mrg
1429 1.1.1.6 mrg /* The last path segment should be the hash. */
1430 1.1.1.6 mrg if (!is_legacy_prefixed_hash (ident))
1431 1.1.1.6 mrg return 0;
1432 1.1.1.6 mrg
1433 1.1.1.6 mrg /* Reset the state for a second pass, to print the symbol. */
1434 1.1.1.6 mrg rdm.next = 0;
1435 1.1.1.6 mrg if (!rdm.verbose && rdm.sym_len > 19)
1436 1.1.1.6 mrg {
1437 1.1.1.6 mrg /* Hide the last segment, containing the hash, if not verbose. */
1438 1.1.1.6 mrg rdm.sym_len -= 19;
1439 1.1.1.6 mrg }
1440 1.1.1.6 mrg
1441 1.1.1.6 mrg do
1442 1.1.1.6 mrg {
1443 1.1.1.6 mrg if (rdm.next > 0)
1444 1.1.1.6 mrg print_str (&rdm, "::", 2);
1445 1.1.1.6 mrg
1446 1.1.1.6 mrg ident = parse_ident (&rdm);
1447 1.1.1.6 mrg print_ident (&rdm, ident);
1448 1.1.1.6 mrg }
1449 1.1.1.6 mrg while (rdm.next < rdm.sym_len);
1450 1.1.1.6 mrg }
1451 1.1.1.6 mrg else
1452 1.1.1.7 mrg {
1453 1.1.1.7 mrg demangle_path (&rdm, 1);
1454 1.1.1.7 mrg
1455 1.1.1.7 mrg /* Skip instantiating crate. */
1456 1.1.1.7 mrg if (!rdm.errored && rdm.next < rdm.sym_len)
1457 1.1.1.7 mrg {
1458 1.1.1.7 mrg rdm.skipping_printing = 1;
1459 1.1.1.7 mrg demangle_path (&rdm, 0);
1460 1.1.1.7 mrg }
1461 1.1.1.7 mrg
1462 1.1.1.7 mrg /* It's an error to not reach the end. */
1463 1.1.1.7 mrg rdm.errored |= rdm.next != rdm.sym_len;
1464 1.1.1.7 mrg }
1465 1.1.1.6 mrg
1466 1.1.1.6 mrg return !rdm.errored;
1467 1.1.1.6 mrg }
1468 1.1.1.6 mrg
1469 1.1.1.6 mrg /* Growable string buffers. */
1470 1.1.1.6 mrg struct str_buf
1471 1.1.1.6 mrg {
1472 1.1.1.6 mrg char *ptr;
1473 1.1.1.6 mrg size_t len;
1474 1.1.1.6 mrg size_t cap;
1475 1.1.1.6 mrg int errored;
1476 1.1.1.6 mrg };
1477 1.1.1.6 mrg
1478 1.1.1.6 mrg static void
1479 1.1.1.6 mrg str_buf_reserve (struct str_buf *buf, size_t extra)
1480 1.1.1.6 mrg {
1481 1.1.1.6 mrg size_t available, min_new_cap, new_cap;
1482 1.1.1.6 mrg char *new_ptr;
1483 1.1.1.6 mrg
1484 1.1.1.6 mrg /* Allocation failed before. */
1485 1.1.1.6 mrg if (buf->errored)
1486 1.1.1.6 mrg return;
1487 1.1.1.6 mrg
1488 1.1.1.6 mrg available = buf->cap - buf->len;
1489 1.1.1.6 mrg
1490 1.1.1.6 mrg if (extra <= available)
1491 1.1 mrg return;
1492 1.1 mrg
1493 1.1.1.6 mrg min_new_cap = buf->cap + (extra - available);
1494 1.1.1.6 mrg
1495 1.1.1.6 mrg /* Check for overflows. */
1496 1.1.1.6 mrg if (min_new_cap < buf->cap)
1497 1.1.1.6 mrg {
1498 1.1.1.6 mrg buf->errored = 1;
1499 1.1.1.6 mrg return;
1500 1.1.1.6 mrg }
1501 1.1.1.6 mrg
1502 1.1.1.6 mrg new_cap = buf->cap;
1503 1.1.1.6 mrg
1504 1.1.1.6 mrg if (new_cap == 0)
1505 1.1.1.6 mrg new_cap = 4;
1506 1.1.1.6 mrg
1507 1.1.1.6 mrg /* Double capacity until sufficiently large. */
1508 1.1.1.6 mrg while (new_cap < min_new_cap)
1509 1.1.1.6 mrg {
1510 1.1.1.6 mrg new_cap *= 2;
1511 1.1.1.6 mrg
1512 1.1.1.6 mrg /* Check for overflows. */
1513 1.1.1.6 mrg if (new_cap < buf->cap)
1514 1.1.1.6 mrg {
1515 1.1.1.6 mrg buf->errored = 1;
1516 1.1.1.6 mrg return;
1517 1.1.1.6 mrg }
1518 1.1.1.6 mrg }
1519 1.1.1.6 mrg
1520 1.1.1.6 mrg new_ptr = (char *)realloc (buf->ptr, new_cap);
1521 1.1.1.6 mrg if (new_ptr == NULL)
1522 1.1.1.6 mrg {
1523 1.1.1.6 mrg free (buf->ptr);
1524 1.1.1.6 mrg buf->ptr = NULL;
1525 1.1.1.6 mrg buf->len = 0;
1526 1.1.1.6 mrg buf->cap = 0;
1527 1.1.1.6 mrg buf->errored = 1;
1528 1.1.1.6 mrg }
1529 1.1.1.6 mrg else
1530 1.1.1.6 mrg {
1531 1.1.1.6 mrg buf->ptr = new_ptr;
1532 1.1.1.6 mrg buf->cap = new_cap;
1533 1.1.1.6 mrg }
1534 1.1 mrg }
1535 1.1 mrg
1536 1.1.1.6 mrg static void
1537 1.1.1.6 mrg str_buf_append (struct str_buf *buf, const char *data, size_t len)
1538 1.1 mrg {
1539 1.1.1.6 mrg str_buf_reserve (buf, len);
1540 1.1.1.6 mrg if (buf->errored)
1541 1.1.1.6 mrg return;
1542 1.1 mrg
1543 1.1.1.6 mrg memcpy (buf->ptr + buf->len, data, len);
1544 1.1.1.6 mrg buf->len += len;
1545 1.1.1.6 mrg }
1546 1.1 mrg
1547 1.1.1.6 mrg static void
1548 1.1.1.6 mrg str_buf_demangle_callback (const char *data, size_t len, void *opaque)
1549 1.1.1.6 mrg {
1550 1.1.1.6 mrg str_buf_append ((struct str_buf *)opaque, data, len);
1551 1.1.1.6 mrg }
1552 1.1.1.6 mrg
1553 1.1.1.6 mrg char *
1554 1.1.1.6 mrg rust_demangle (const char *mangled, int options)
1555 1.1.1.6 mrg {
1556 1.1.1.6 mrg struct str_buf out;
1557 1.1.1.6 mrg int success;
1558 1.1 mrg
1559 1.1.1.6 mrg out.ptr = NULL;
1560 1.1.1.6 mrg out.len = 0;
1561 1.1.1.6 mrg out.cap = 0;
1562 1.1.1.6 mrg out.errored = 0;
1563 1.1.1.6 mrg
1564 1.1.1.6 mrg success = rust_demangle_callback (mangled, options,
1565 1.1.1.6 mrg str_buf_demangle_callback, &out);
1566 1.1.1.6 mrg
1567 1.1.1.6 mrg if (!success)
1568 1.1.1.6 mrg {
1569 1.1.1.6 mrg free (out.ptr);
1570 1.1.1.6 mrg return NULL;
1571 1.1.1.6 mrg }
1572 1.1 mrg
1573 1.1.1.6 mrg str_buf_append (&out, "\0", 1);
1574 1.1.1.6 mrg return out.ptr;
1575 1.1 mrg }
1576