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