Home | History | Annotate | Line # | Download | only in libiberty
rust-demangle.c revision 1.1.1.8
      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