1 1.1 mrg /* Demangler for the Rust programming language 2 1.1.1.8 mrg Copyright (C) 2016-2024 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.8 mrg while (!eat (rdm, '_') && !rdm->errored) 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.8 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 1086 1.1.1.8 mrg { 1087 1.1.1.8 mrg ++ rdm->recursion; 1088 1.1.1.8 mrg if (rdm->recursion > RUST_MAX_RECURSION_COUNT) 1089 1.1.1.8 mrg { 1090 1.1.1.8 mrg /* FIXME: There ought to be a way to report 1091 1.1.1.8 mrg that the recursion limit has been reached. */ 1092 1.1.1.8 mrg rdm->errored = 1; 1093 1.1.1.8 mrg goto end_of_func; 1094 1.1.1.8 mrg } 1095 1.1.1.8 mrg } 1096 1.1.1.8 mrg 1097 1.1.1.7 mrg if (eat (rdm, 'B')) 1098 1.1.1.7 mrg { 1099 1.1.1.7 mrg backref = parse_integer_62 (rdm); 1100 1.1.1.7 mrg if (!rdm->skipping_printing) 1101 1.1.1.7 mrg { 1102 1.1.1.7 mrg old_next = rdm->next; 1103 1.1.1.7 mrg rdm->next = backref; 1104 1.1.1.7 mrg open = demangle_path_maybe_open_generics (rdm); 1105 1.1.1.7 mrg rdm->next = old_next; 1106 1.1.1.7 mrg } 1107 1.1.1.7 mrg } 1108 1.1.1.7 mrg else if (eat (rdm, 'I')) 1109 1.1.1.7 mrg { 1110 1.1.1.7 mrg demangle_path (rdm, 0); 1111 1.1.1.7 mrg PRINT ("<"); 1112 1.1.1.7 mrg open = 1; 1113 1.1.1.7 mrg for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) 1114 1.1.1.7 mrg { 1115 1.1.1.7 mrg if (i > 0) 1116 1.1.1.7 mrg PRINT (", "); 1117 1.1.1.7 mrg demangle_generic_arg (rdm); 1118 1.1.1.7 mrg } 1119 1.1.1.7 mrg } 1120 1.1.1.7 mrg else 1121 1.1.1.7 mrg demangle_path (rdm, 0); 1122 1.1.1.8 mrg 1123 1.1.1.8 mrg end_of_func: 1124 1.1.1.8 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 1125 1.1.1.8 mrg -- rdm->recursion; 1126 1.1.1.8 mrg 1127 1.1.1.7 mrg return open; 1128 1.1.1.7 mrg } 1129 1.1.1.7 mrg 1130 1.1.1.7 mrg static void 1131 1.1.1.7 mrg demangle_dyn_trait (struct rust_demangler *rdm) 1132 1.1.1.7 mrg { 1133 1.1.1.7 mrg int open; 1134 1.1.1.7 mrg struct rust_mangled_ident name; 1135 1.1.1.7 mrg 1136 1.1.1.7 mrg if (rdm->errored) 1137 1.1.1.7 mrg return; 1138 1.1.1.7 mrg 1139 1.1.1.7 mrg open = demangle_path_maybe_open_generics (rdm); 1140 1.1.1.7 mrg 1141 1.1.1.7 mrg while (eat (rdm, 'p')) 1142 1.1.1.7 mrg { 1143 1.1.1.7 mrg if (!open) 1144 1.1.1.7 mrg PRINT ("<"); 1145 1.1.1.7 mrg else 1146 1.1.1.7 mrg PRINT (", "); 1147 1.1.1.7 mrg open = 1; 1148 1.1.1.7 mrg 1149 1.1.1.7 mrg name = parse_ident (rdm); 1150 1.1.1.7 mrg print_ident (rdm, name); 1151 1.1.1.7 mrg PRINT (" = "); 1152 1.1.1.7 mrg demangle_type (rdm); 1153 1.1.1.7 mrg } 1154 1.1.1.7 mrg 1155 1.1.1.7 mrg if (open) 1156 1.1.1.7 mrg PRINT (">"); 1157 1.1.1.7 mrg } 1158 1.1.1.7 mrg 1159 1.1.1.7 mrg static void 1160 1.1.1.7 mrg demangle_const (struct rust_demangler *rdm) 1161 1.1.1.7 mrg { 1162 1.1.1.7 mrg char ty_tag; 1163 1.1.1.7 mrg size_t old_next, backref; 1164 1.1.1.7 mrg 1165 1.1.1.7 mrg if (rdm->errored) 1166 1.1.1.7 mrg return; 1167 1.1.1.7 mrg 1168 1.1.1.8 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 1169 1.1.1.8 mrg { 1170 1.1.1.8 mrg ++ rdm->recursion; 1171 1.1.1.8 mrg if (rdm->recursion > RUST_MAX_RECURSION_COUNT) 1172 1.1.1.8 mrg /* FIXME: There ought to be a way to report 1173 1.1.1.8 mrg that the recursion limit has been reached. */ 1174 1.1.1.8 mrg goto fail_return; 1175 1.1.1.8 mrg } 1176 1.1.1.8 mrg 1177 1.1.1.7 mrg if (eat (rdm, 'B')) 1178 1.1.1.7 mrg { 1179 1.1.1.7 mrg backref = parse_integer_62 (rdm); 1180 1.1.1.7 mrg if (!rdm->skipping_printing) 1181 1.1.1.7 mrg { 1182 1.1.1.7 mrg old_next = rdm->next; 1183 1.1.1.7 mrg rdm->next = backref; 1184 1.1.1.7 mrg demangle_const (rdm); 1185 1.1.1.7 mrg rdm->next = old_next; 1186 1.1.1.7 mrg } 1187 1.1.1.8 mrg goto pass_return; 1188 1.1.1.7 mrg } 1189 1.1.1.7 mrg 1190 1.1.1.7 mrg ty_tag = next (rdm); 1191 1.1.1.7 mrg switch (ty_tag) 1192 1.1.1.7 mrg { 1193 1.1.1.7 mrg /* Placeholder. */ 1194 1.1.1.7 mrg case 'p': 1195 1.1.1.7 mrg PRINT ("_"); 1196 1.1.1.8 mrg goto pass_return; 1197 1.1.1.7 mrg 1198 1.1.1.7 mrg /* Unsigned integer types. */ 1199 1.1.1.7 mrg case 'h': 1200 1.1.1.7 mrg case 't': 1201 1.1.1.7 mrg case 'm': 1202 1.1.1.7 mrg case 'y': 1203 1.1.1.7 mrg case 'o': 1204 1.1.1.7 mrg case 'j': 1205 1.1.1.7 mrg demangle_const_uint (rdm); 1206 1.1.1.7 mrg break; 1207 1.1.1.7 mrg 1208 1.1.1.7 mrg /* Signed integer types. */ 1209 1.1.1.7 mrg case 'a': 1210 1.1.1.7 mrg case 's': 1211 1.1.1.7 mrg case 'l': 1212 1.1.1.7 mrg case 'x': 1213 1.1.1.7 mrg case 'n': 1214 1.1.1.7 mrg case 'i': 1215 1.1.1.7 mrg demangle_const_int (rdm); 1216 1.1.1.7 mrg break; 1217 1.1.1.7 mrg 1218 1.1.1.7 mrg /* Boolean. */ 1219 1.1.1.7 mrg case 'b': 1220 1.1.1.7 mrg demangle_const_bool (rdm); 1221 1.1.1.7 mrg break; 1222 1.1.1.7 mrg 1223 1.1.1.7 mrg /* Character. */ 1224 1.1.1.7 mrg case 'c': 1225 1.1.1.7 mrg demangle_const_char (rdm); 1226 1.1.1.7 mrg break; 1227 1.1.1.7 mrg 1228 1.1.1.7 mrg default: 1229 1.1.1.8 mrg goto fail_return; 1230 1.1.1.7 mrg } 1231 1.1.1.7 mrg 1232 1.1.1.8 mrg if (!rdm->errored && rdm->verbose) 1233 1.1.1.7 mrg { 1234 1.1.1.7 mrg PRINT (": "); 1235 1.1.1.7 mrg PRINT (basic_type (ty_tag)); 1236 1.1.1.7 mrg } 1237 1.1.1.8 mrg goto pass_return; 1238 1.1.1.8 mrg 1239 1.1.1.8 mrg fail_return: 1240 1.1.1.8 mrg rdm->errored = 1; 1241 1.1.1.8 mrg pass_return: 1242 1.1.1.8 mrg if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 1243 1.1.1.8 mrg -- rdm->recursion; 1244 1.1.1.7 mrg } 1245 1.1.1.7 mrg 1246 1.1.1.7 mrg static void 1247 1.1.1.7 mrg demangle_const_uint (struct rust_demangler *rdm) 1248 1.1.1.7 mrg { 1249 1.1.1.7 mrg size_t hex_len; 1250 1.1.1.7 mrg uint64_t value; 1251 1.1.1.7 mrg 1252 1.1.1.7 mrg if (rdm->errored) 1253 1.1.1.7 mrg return; 1254 1.1.1.7 mrg 1255 1.1.1.7 mrg hex_len = parse_hex_nibbles (rdm, &value); 1256 1.1.1.7 mrg 1257 1.1.1.7 mrg if (hex_len > 16) 1258 1.1.1.7 mrg { 1259 1.1.1.7 mrg /* Print anything that doesn't fit in `uint64_t` verbatim. */ 1260 1.1.1.7 mrg PRINT ("0x"); 1261 1.1.1.7 mrg print_str (rdm, rdm->sym + (rdm->next - hex_len), hex_len); 1262 1.1.1.7 mrg } 1263 1.1.1.7 mrg else if (hex_len > 0) 1264 1.1.1.7 mrg print_uint64 (rdm, value); 1265 1.1.1.7 mrg else 1266 1.1.1.7 mrg rdm->errored = 1; 1267 1.1.1.7 mrg } 1268 1.1.1.7 mrg 1269 1.1.1.7 mrg static void 1270 1.1.1.7 mrg demangle_const_int (struct rust_demangler *rdm) 1271 1.1.1.7 mrg { 1272 1.1.1.7 mrg if (eat (rdm, 'n')) 1273 1.1.1.7 mrg PRINT ("-"); 1274 1.1.1.7 mrg demangle_const_uint (rdm); 1275 1.1.1.7 mrg } 1276 1.1.1.7 mrg 1277 1.1.1.7 mrg static void 1278 1.1.1.7 mrg demangle_const_bool (struct rust_demangler *rdm) 1279 1.1.1.7 mrg { 1280 1.1.1.7 mrg uint64_t value; 1281 1.1.1.7 mrg 1282 1.1.1.7 mrg if (parse_hex_nibbles (rdm, &value) != 1) 1283 1.1.1.7 mrg { 1284 1.1.1.7 mrg rdm->errored = 1; 1285 1.1.1.7 mrg return; 1286 1.1.1.7 mrg } 1287 1.1.1.7 mrg 1288 1.1.1.7 mrg if (value == 0) 1289 1.1.1.7 mrg PRINT ("false"); 1290 1.1.1.7 mrg else if (value == 1) 1291 1.1.1.7 mrg PRINT ("true"); 1292 1.1.1.7 mrg else 1293 1.1.1.7 mrg rdm->errored = 1; 1294 1.1.1.7 mrg } 1295 1.1.1.7 mrg 1296 1.1.1.7 mrg static void 1297 1.1.1.7 mrg demangle_const_char (struct rust_demangler *rdm) 1298 1.1.1.7 mrg { 1299 1.1.1.7 mrg size_t hex_len; 1300 1.1.1.7 mrg uint64_t value; 1301 1.1.1.7 mrg 1302 1.1.1.7 mrg hex_len = parse_hex_nibbles (rdm, &value); 1303 1.1.1.7 mrg 1304 1.1.1.7 mrg if (hex_len == 0 || hex_len > 8) 1305 1.1.1.7 mrg { 1306 1.1.1.7 mrg rdm->errored = 1; 1307 1.1.1.7 mrg return; 1308 1.1.1.7 mrg } 1309 1.1.1.7 mrg 1310 1.1.1.7 mrg /* Match Rust's character "debug" output as best as we can. */ 1311 1.1.1.7 mrg PRINT ("'"); 1312 1.1.1.7 mrg if (value == '\t') 1313 1.1.1.7 mrg PRINT ("\\t"); 1314 1.1.1.7 mrg else if (value == '\r') 1315 1.1.1.7 mrg PRINT ("\\r"); 1316 1.1.1.7 mrg else if (value == '\n') 1317 1.1.1.7 mrg PRINT ("\\n"); 1318 1.1.1.7 mrg else if (value > ' ' && value < '~') 1319 1.1.1.7 mrg { 1320 1.1.1.7 mrg /* Rust also considers many non-ASCII codepoints to be printable, but 1321 1.1.1.7 mrg that logic is not easily ported to C. */ 1322 1.1.1.7 mrg char c = value; 1323 1.1.1.7 mrg print_str (rdm, &c, 1); 1324 1.1.1.7 mrg } 1325 1.1.1.7 mrg else 1326 1.1.1.7 mrg { 1327 1.1.1.7 mrg PRINT ("\\u{"); 1328 1.1.1.7 mrg print_uint64_hex (rdm, value); 1329 1.1.1.7 mrg PRINT ("}"); 1330 1.1.1.7 mrg } 1331 1.1.1.7 mrg PRINT ("'"); 1332 1.1.1.6 mrg } 1333 1.1.1.6 mrg 1334 1.1.1.6 mrg /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits. 1335 1.1.1.6 mrg The hex digits must contain at least 5 distinct digits. */ 1336 1.1 mrg static int 1337 1.1.1.6 mrg is_legacy_prefixed_hash (struct rust_mangled_ident ident) 1338 1.1 mrg { 1339 1.1.1.6 mrg uint16_t seen; 1340 1.1.1.6 mrg int nibble; 1341 1.1.1.6 mrg size_t i, count; 1342 1.1 mrg 1343 1.1.1.6 mrg if (ident.ascii_len != 17 || ident.ascii[0] != 'h') 1344 1.1 mrg return 0; 1345 1.1 mrg 1346 1.1.1.6 mrg seen = 0; 1347 1.1.1.6 mrg for (i = 0; i < 16; i++) 1348 1.1.1.6 mrg { 1349 1.1.1.6 mrg nibble = decode_lower_hex_nibble (ident.ascii[1 + i]); 1350 1.1.1.6 mrg if (nibble < 0) 1351 1.1.1.6 mrg return 0; 1352 1.1.1.6 mrg seen |= (uint16_t)1 << nibble; 1353 1.1.1.6 mrg } 1354 1.1 mrg 1355 1.1.1.6 mrg /* Count how many distinct digits were seen. */ 1356 1.1 mrg count = 0; 1357 1.1.1.6 mrg while (seen) 1358 1.1.1.6 mrg { 1359 1.1.1.6 mrg if (seen & 1) 1360 1.1.1.6 mrg count++; 1361 1.1.1.6 mrg seen >>= 1; 1362 1.1.1.6 mrg } 1363 1.1 mrg 1364 1.1.1.6 mrg return count >= 5; 1365 1.1 mrg } 1366 1.1 mrg 1367 1.1.1.6 mrg int 1368 1.1.1.6 mrg rust_demangle_callback (const char *mangled, int options, 1369 1.1.1.6 mrg demangle_callbackref callback, void *opaque) 1370 1.1 mrg { 1371 1.1.1.6 mrg const char *p; 1372 1.1.1.6 mrg struct rust_demangler rdm; 1373 1.1.1.6 mrg struct rust_mangled_ident ident; 1374 1.1.1.6 mrg 1375 1.1.1.6 mrg rdm.sym = mangled; 1376 1.1.1.6 mrg rdm.sym_len = 0; 1377 1.1.1.6 mrg 1378 1.1.1.6 mrg rdm.callback_opaque = opaque; 1379 1.1.1.6 mrg rdm.callback = callback; 1380 1.1.1.6 mrg 1381 1.1.1.6 mrg rdm.next = 0; 1382 1.1.1.6 mrg rdm.errored = 0; 1383 1.1.1.7 mrg rdm.skipping_printing = 0; 1384 1.1.1.6 mrg rdm.verbose = (options & DMGL_VERBOSE) != 0; 1385 1.1.1.6 mrg rdm.version = 0; 1386 1.1.1.7 mrg rdm.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0; 1387 1.1.1.7 mrg rdm.bound_lifetime_depth = 0; 1388 1.1.1.6 mrg 1389 1.1.1.7 mrg /* Rust symbols always start with _R (v0) or _ZN (legacy). */ 1390 1.1.1.7 mrg if (rdm.sym[0] == '_' && rdm.sym[1] == 'R') 1391 1.1.1.7 mrg rdm.sym += 2; 1392 1.1.1.7 mrg else if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N') 1393 1.1.1.6 mrg { 1394 1.1.1.6 mrg rdm.sym += 3; 1395 1.1.1.6 mrg rdm.version = -1; 1396 1.1.1.6 mrg } 1397 1.1.1.6 mrg else 1398 1.1.1.6 mrg return 0; 1399 1.1.1.6 mrg 1400 1.1.1.7 mrg /* Paths (v0) always start with uppercase characters. */ 1401 1.1.1.7 mrg if (rdm.version != -1 && !ISUPPER (rdm.sym[0])) 1402 1.1.1.7 mrg return 0; 1403 1.1.1.7 mrg 1404 1.1.1.7 mrg /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */ 1405 1.1.1.6 mrg for (p = rdm.sym; *p; p++) 1406 1.1.1.6 mrg { 1407 1.1.1.7 mrg /* Rust v0 symbols can have '.' suffixes, ignore those. */ 1408 1.1.1.7 mrg if (rdm.version == 0 && *p == '.') 1409 1.1.1.7 mrg break; 1410 1.1.1.7 mrg 1411 1.1.1.6 mrg rdm.sym_len++; 1412 1.1 mrg 1413 1.1.1.6 mrg if (*p == '_' || ISALNUM (*p)) 1414 1.1.1.6 mrg continue; 1415 1.1 mrg 1416 1.1.1.7 mrg /* Legacy Rust symbols can also contain [.:$] characters. 1417 1.1.1.7 mrg Or @ in the .suffix (which will be skipped, see below). */ 1418 1.1.1.7 mrg if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':' 1419 1.1.1.7 mrg || *p == '@')) 1420 1.1.1.6 mrg continue; 1421 1.1.1.6 mrg 1422 1.1.1.6 mrg return 0; 1423 1.1.1.6 mrg } 1424 1.1.1.6 mrg 1425 1.1.1.6 mrg /* Legacy Rust symbols need to be handled separately. */ 1426 1.1.1.6 mrg if (rdm.version == -1) 1427 1.1.1.6 mrg { 1428 1.1.1.7 mrg /* Legacy Rust symbols always end with E. But can be followed by a 1429 1.1.1.7 mrg .suffix (which we want to ignore). */ 1430 1.1.1.7 mrg int dot_suffix = 1; 1431 1.1.1.7 mrg while (rdm.sym_len > 0 && 1432 1.1.1.7 mrg !(dot_suffix && rdm.sym[rdm.sym_len - 1] == 'E')) 1433 1.1.1.7 mrg { 1434 1.1.1.7 mrg dot_suffix = rdm.sym[rdm.sym_len - 1] == '.'; 1435 1.1.1.7 mrg rdm.sym_len--; 1436 1.1.1.7 mrg } 1437 1.1.1.7 mrg 1438 1.1.1.6 mrg if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E')) 1439 1.1.1.6 mrg return 0; 1440 1.1.1.6 mrg rdm.sym_len--; 1441 1.1.1.6 mrg 1442 1.1.1.6 mrg /* Legacy Rust symbols also always end with a path segment 1443 1.1.1.6 mrg that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'. 1444 1.1.1.6 mrg This early check, before any parse_ident calls, should 1445 1.1.1.6 mrg quickly filter out most C++ symbols unrelated to Rust. */ 1446 1.1.1.6 mrg if (!(rdm.sym_len > 19 1447 1.1.1.6 mrg && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3))) 1448 1.1.1.6 mrg return 0; 1449 1.1.1.6 mrg 1450 1.1.1.6 mrg do 1451 1.1.1.6 mrg { 1452 1.1.1.6 mrg ident = parse_ident (&rdm); 1453 1.1.1.6 mrg if (rdm.errored || !ident.ascii) 1454 1.1.1.6 mrg return 0; 1455 1.1.1.6 mrg } 1456 1.1.1.6 mrg while (rdm.next < rdm.sym_len); 1457 1.1.1.6 mrg 1458 1.1.1.6 mrg /* The last path segment should be the hash. */ 1459 1.1.1.6 mrg if (!is_legacy_prefixed_hash (ident)) 1460 1.1.1.6 mrg return 0; 1461 1.1.1.6 mrg 1462 1.1.1.6 mrg /* Reset the state for a second pass, to print the symbol. */ 1463 1.1.1.6 mrg rdm.next = 0; 1464 1.1.1.6 mrg if (!rdm.verbose && rdm.sym_len > 19) 1465 1.1.1.6 mrg { 1466 1.1.1.6 mrg /* Hide the last segment, containing the hash, if not verbose. */ 1467 1.1.1.6 mrg rdm.sym_len -= 19; 1468 1.1.1.6 mrg } 1469 1.1.1.6 mrg 1470 1.1.1.6 mrg do 1471 1.1.1.6 mrg { 1472 1.1.1.6 mrg if (rdm.next > 0) 1473 1.1.1.6 mrg print_str (&rdm, "::", 2); 1474 1.1.1.6 mrg 1475 1.1.1.6 mrg ident = parse_ident (&rdm); 1476 1.1.1.6 mrg print_ident (&rdm, ident); 1477 1.1.1.6 mrg } 1478 1.1.1.6 mrg while (rdm.next < rdm.sym_len); 1479 1.1.1.6 mrg } 1480 1.1.1.6 mrg else 1481 1.1.1.7 mrg { 1482 1.1.1.7 mrg demangle_path (&rdm, 1); 1483 1.1.1.7 mrg 1484 1.1.1.7 mrg /* Skip instantiating crate. */ 1485 1.1.1.7 mrg if (!rdm.errored && rdm.next < rdm.sym_len) 1486 1.1.1.7 mrg { 1487 1.1.1.7 mrg rdm.skipping_printing = 1; 1488 1.1.1.7 mrg demangle_path (&rdm, 0); 1489 1.1.1.7 mrg } 1490 1.1.1.7 mrg 1491 1.1.1.7 mrg /* It's an error to not reach the end. */ 1492 1.1.1.7 mrg rdm.errored |= rdm.next != rdm.sym_len; 1493 1.1.1.7 mrg } 1494 1.1.1.6 mrg 1495 1.1.1.6 mrg return !rdm.errored; 1496 1.1.1.6 mrg } 1497 1.1.1.6 mrg 1498 1.1.1.6 mrg /* Growable string buffers. */ 1499 1.1.1.6 mrg struct str_buf 1500 1.1.1.6 mrg { 1501 1.1.1.6 mrg char *ptr; 1502 1.1.1.6 mrg size_t len; 1503 1.1.1.6 mrg size_t cap; 1504 1.1.1.6 mrg int errored; 1505 1.1.1.6 mrg }; 1506 1.1.1.6 mrg 1507 1.1.1.6 mrg static void 1508 1.1.1.6 mrg str_buf_reserve (struct str_buf *buf, size_t extra) 1509 1.1.1.6 mrg { 1510 1.1.1.6 mrg size_t available, min_new_cap, new_cap; 1511 1.1.1.6 mrg char *new_ptr; 1512 1.1.1.6 mrg 1513 1.1.1.6 mrg /* Allocation failed before. */ 1514 1.1.1.6 mrg if (buf->errored) 1515 1.1.1.6 mrg return; 1516 1.1.1.6 mrg 1517 1.1.1.6 mrg available = buf->cap - buf->len; 1518 1.1.1.6 mrg 1519 1.1.1.6 mrg if (extra <= available) 1520 1.1 mrg return; 1521 1.1 mrg 1522 1.1.1.6 mrg min_new_cap = buf->cap + (extra - available); 1523 1.1.1.6 mrg 1524 1.1.1.6 mrg /* Check for overflows. */ 1525 1.1.1.6 mrg if (min_new_cap < buf->cap) 1526 1.1.1.6 mrg { 1527 1.1.1.6 mrg buf->errored = 1; 1528 1.1.1.6 mrg return; 1529 1.1.1.6 mrg } 1530 1.1.1.6 mrg 1531 1.1.1.6 mrg new_cap = buf->cap; 1532 1.1.1.6 mrg 1533 1.1.1.6 mrg if (new_cap == 0) 1534 1.1.1.6 mrg new_cap = 4; 1535 1.1.1.6 mrg 1536 1.1.1.6 mrg /* Double capacity until sufficiently large. */ 1537 1.1.1.6 mrg while (new_cap < min_new_cap) 1538 1.1.1.6 mrg { 1539 1.1.1.6 mrg new_cap *= 2; 1540 1.1.1.6 mrg 1541 1.1.1.6 mrg /* Check for overflows. */ 1542 1.1.1.6 mrg if (new_cap < buf->cap) 1543 1.1.1.6 mrg { 1544 1.1.1.6 mrg buf->errored = 1; 1545 1.1.1.6 mrg return; 1546 1.1.1.6 mrg } 1547 1.1.1.6 mrg } 1548 1.1.1.6 mrg 1549 1.1.1.6 mrg new_ptr = (char *)realloc (buf->ptr, new_cap); 1550 1.1.1.6 mrg if (new_ptr == NULL) 1551 1.1.1.6 mrg { 1552 1.1.1.6 mrg free (buf->ptr); 1553 1.1.1.6 mrg buf->ptr = NULL; 1554 1.1.1.6 mrg buf->len = 0; 1555 1.1.1.6 mrg buf->cap = 0; 1556 1.1.1.6 mrg buf->errored = 1; 1557 1.1.1.6 mrg } 1558 1.1.1.6 mrg else 1559 1.1.1.6 mrg { 1560 1.1.1.6 mrg buf->ptr = new_ptr; 1561 1.1.1.6 mrg buf->cap = new_cap; 1562 1.1.1.6 mrg } 1563 1.1 mrg } 1564 1.1 mrg 1565 1.1.1.6 mrg static void 1566 1.1.1.6 mrg str_buf_append (struct str_buf *buf, const char *data, size_t len) 1567 1.1 mrg { 1568 1.1.1.6 mrg str_buf_reserve (buf, len); 1569 1.1.1.6 mrg if (buf->errored) 1570 1.1.1.6 mrg return; 1571 1.1 mrg 1572 1.1.1.6 mrg memcpy (buf->ptr + buf->len, data, len); 1573 1.1.1.6 mrg buf->len += len; 1574 1.1.1.6 mrg } 1575 1.1 mrg 1576 1.1.1.6 mrg static void 1577 1.1.1.6 mrg str_buf_demangle_callback (const char *data, size_t len, void *opaque) 1578 1.1.1.6 mrg { 1579 1.1.1.6 mrg str_buf_append ((struct str_buf *)opaque, data, len); 1580 1.1.1.6 mrg } 1581 1.1.1.6 mrg 1582 1.1.1.6 mrg char * 1583 1.1.1.6 mrg rust_demangle (const char *mangled, int options) 1584 1.1.1.6 mrg { 1585 1.1.1.6 mrg struct str_buf out; 1586 1.1.1.6 mrg int success; 1587 1.1 mrg 1588 1.1.1.6 mrg out.ptr = NULL; 1589 1.1.1.6 mrg out.len = 0; 1590 1.1.1.6 mrg out.cap = 0; 1591 1.1.1.6 mrg out.errored = 0; 1592 1.1.1.6 mrg 1593 1.1.1.6 mrg success = rust_demangle_callback (mangled, options, 1594 1.1.1.6 mrg str_buf_demangle_callback, &out); 1595 1.1.1.6 mrg 1596 1.1.1.6 mrg if (!success) 1597 1.1.1.6 mrg { 1598 1.1.1.6 mrg free (out.ptr); 1599 1.1.1.6 mrg return NULL; 1600 1.1.1.6 mrg } 1601 1.1 mrg 1602 1.1.1.6 mrg str_buf_append (&out, "\0", 1); 1603 1.1.1.6 mrg return out.ptr; 1604 1.1 mrg } 1605