1*60869b22SIan Rogers // SPDX-License-Identifier: Apache-2.0 OR MIT 2*60869b22SIan Rogers 3*60869b22SIan Rogers // The contents of this file come from the Rust rustc-demangle library, hosted 4*60869b22SIan Rogers // in the <https://github.com/rust-lang/rustc-demangle> repository, licensed 5*60869b22SIan Rogers // under "Apache-2.0 OR MIT". For copyright details, see 6*60869b22SIan Rogers // <https://github.com/rust-lang/rustc-demangle/blob/main/README.md>. 7*60869b22SIan Rogers // Please note that the file should be kept as close as possible to upstream. 8*60869b22SIan Rogers 9*60869b22SIan Rogers // Code for demangling Rust symbols. This code is mostly 10*60869b22SIan Rogers // a line-by-line translation of the Rust code in `rustc-demangle`. 11*60869b22SIan Rogers 12*60869b22SIan Rogers // you can find the latest version of this code in https://github.com/rust-lang/rustc-demangle 13*60869b22SIan Rogers 14*60869b22SIan Rogers #include <stdint.h> 15*60869b22SIan Rogers #include <stddef.h> 16*60869b22SIan Rogers #include <string.h> 17*60869b22SIan Rogers #include <stdbool.h> 18*60869b22SIan Rogers #include <sys/param.h> 19*60869b22SIan Rogers #include <stdio.h> 20*60869b22SIan Rogers 21*60869b22SIan Rogers #include "demangle-rust-v0.h" 22*60869b22SIan Rogers 23*60869b22SIan Rogers #if defined(__GNUC__) || defined(__clang__) 24*60869b22SIan Rogers #define NODISCARD __attribute__((warn_unused_result)) 25*60869b22SIan Rogers #else 26*60869b22SIan Rogers #define NODISCARD 27*60869b22SIan Rogers #endif 28*60869b22SIan Rogers 29*60869b22SIan Rogers #define MAX_DEPTH 500 30*60869b22SIan Rogers 31*60869b22SIan Rogers typedef enum { 32*60869b22SIan Rogers DemangleOk, 33*60869b22SIan Rogers DemangleInvalid, 34*60869b22SIan Rogers DemangleRecursed, 35*60869b22SIan Rogers DemangleBug, 36*60869b22SIan Rogers } demangle_status; 37*60869b22SIan Rogers 38*60869b22SIan Rogers struct demangle_v0 { 39*60869b22SIan Rogers const char *mangled; 40*60869b22SIan Rogers size_t mangled_len; 41*60869b22SIan Rogers }; 42*60869b22SIan Rogers 43*60869b22SIan Rogers struct demangle_legacy { 44*60869b22SIan Rogers const char *mangled; 45*60869b22SIan Rogers size_t mangled_len; 46*60869b22SIan Rogers size_t elements; 47*60869b22SIan Rogers }; 48*60869b22SIan Rogers 49*60869b22SIan Rogers // private version of memrchr to avoid _GNU_SOURCE 50*60869b22SIan Rogers static void *demangle_memrchr(const void *s, int c, size_t n) { 51*60869b22SIan Rogers const uint8_t *s_ = s; 52*60869b22SIan Rogers for (; n != 0; n--) { 53*60869b22SIan Rogers if (s_[n-1] == c) { 54*60869b22SIan Rogers return (void*)&s_[n-1]; 55*60869b22SIan Rogers } 56*60869b22SIan Rogers } 57*60869b22SIan Rogers return NULL; 58*60869b22SIan Rogers } 59*60869b22SIan Rogers 60*60869b22SIan Rogers 61*60869b22SIan Rogers static bool unicode_iscontrol(uint32_t ch) { 62*60869b22SIan Rogers // this is *technically* a unicode table, but 63*60869b22SIan Rogers // some unicode properties are simpler than you might think 64*60869b22SIan Rogers return ch < 0x20 || (ch >= 0x7f && ch < 0xa0); 65*60869b22SIan Rogers } 66*60869b22SIan Rogers 67*60869b22SIan Rogers // "good enough" tables, the only consequence is that when printing 68*60869b22SIan Rogers // *constant strings*, some characters are printed as `\u{abcd}` rather than themselves. 69*60869b22SIan Rogers // 70*60869b22SIan Rogers // I'm leaving these here to allow easily replacing them with actual 71*60869b22SIan Rogers // tables if desired. 72*60869b22SIan Rogers static bool unicode_isprint(uint32_t ch) { 73*60869b22SIan Rogers if (ch < 0x20) { 74*60869b22SIan Rogers return false; 75*60869b22SIan Rogers } 76*60869b22SIan Rogers if (ch < 0x7f) { 77*60869b22SIan Rogers return true; 78*60869b22SIan Rogers } 79*60869b22SIan Rogers return false; 80*60869b22SIan Rogers } 81*60869b22SIan Rogers 82*60869b22SIan Rogers static bool unicode_isgraphemextend(uint32_t ch) { 83*60869b22SIan Rogers (void)ch; 84*60869b22SIan Rogers return false; 85*60869b22SIan Rogers } 86*60869b22SIan Rogers 87*60869b22SIan Rogers static bool str_isascii(const char *s, size_t s_len) { 88*60869b22SIan Rogers for (size_t i = 0; i < s_len; i++) { 89*60869b22SIan Rogers if (s[i] & 0x80) { 90*60869b22SIan Rogers return false; 91*60869b22SIan Rogers } 92*60869b22SIan Rogers } 93*60869b22SIan Rogers 94*60869b22SIan Rogers return true; 95*60869b22SIan Rogers } 96*60869b22SIan Rogers 97*60869b22SIan Rogers typedef enum { 98*60869b22SIan Rogers PunycodeOk, 99*60869b22SIan Rogers PunycodeError 100*60869b22SIan Rogers } punycode_status; 101*60869b22SIan Rogers 102*60869b22SIan Rogers struct parser { 103*60869b22SIan Rogers // the parser assumes that `sym` has a safe "terminating byte". It might be NUL, 104*60869b22SIan Rogers // but it might also be something else if a symbol is "truncated". 105*60869b22SIan Rogers const char *sym; 106*60869b22SIan Rogers size_t sym_len; 107*60869b22SIan Rogers size_t next; 108*60869b22SIan Rogers uint32_t depth; 109*60869b22SIan Rogers }; 110*60869b22SIan Rogers 111*60869b22SIan Rogers struct printer { 112*60869b22SIan Rogers demangle_status status; // if status == 0 parser is valid 113*60869b22SIan Rogers struct parser parser; 114*60869b22SIan Rogers char *out; // NULL for no output [in which case out_len is not decremented] 115*60869b22SIan Rogers size_t out_len; 116*60869b22SIan Rogers uint32_t bound_lifetime_depth; 117*60869b22SIan Rogers bool alternate; 118*60869b22SIan Rogers }; 119*60869b22SIan Rogers 120*60869b22SIan Rogers static NODISCARD overflow_status printer_print_path(struct printer *printer, bool in_value); 121*60869b22SIan Rogers static NODISCARD overflow_status printer_print_type(struct printer *printer); 122*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const(struct printer *printer, bool in_value); 123*60869b22SIan Rogers 124*60869b22SIan Rogers static NODISCARD demangle_status try_parse_path(struct parser *parser) { 125*60869b22SIan Rogers struct printer printer = { 126*60869b22SIan Rogers DemangleOk, 127*60869b22SIan Rogers *parser, 128*60869b22SIan Rogers NULL, 129*60869b22SIan Rogers SIZE_MAX, 130*60869b22SIan Rogers 0, 131*60869b22SIan Rogers false 132*60869b22SIan Rogers }; 133*60869b22SIan Rogers overflow_status ignore = printer_print_path(&printer, false); // can't fail since no output 134*60869b22SIan Rogers (void)ignore; 135*60869b22SIan Rogers *parser = printer.parser; 136*60869b22SIan Rogers return printer.status; 137*60869b22SIan Rogers } 138*60869b22SIan Rogers 139*60869b22SIan Rogers NODISCARD static demangle_status rust_demangle_v0_demangle(const char *s, size_t s_len, struct demangle_v0 *res, const char **rest) { 140*60869b22SIan Rogers if (s_len > strlen(s)) { 141*60869b22SIan Rogers // s_len only exists to shorten the string, this is not a buffer API 142*60869b22SIan Rogers return DemangleInvalid; 143*60869b22SIan Rogers } 144*60869b22SIan Rogers 145*60869b22SIan Rogers const char *inner; 146*60869b22SIan Rogers size_t inner_len; 147*60869b22SIan Rogers if (s_len >= 2 && !strncmp(s, "_R", strlen("_R"))) { 148*60869b22SIan Rogers inner = s+2; 149*60869b22SIan Rogers inner_len = s_len - 2; 150*60869b22SIan Rogers } else if (s_len >= 1 && !strncmp(s, "R", strlen("R"))) { 151*60869b22SIan Rogers // On Windows, dbghelp strips leading underscores, so we accept "R..." 152*60869b22SIan Rogers // form too. 153*60869b22SIan Rogers inner = s+1; 154*60869b22SIan Rogers inner_len = s_len - 1; 155*60869b22SIan Rogers } else if (s_len >= 3 && !strncmp(s, "__R", strlen("__R"))) { 156*60869b22SIan Rogers // On OSX, symbols are prefixed with an extra _ 157*60869b22SIan Rogers inner = s+3; 158*60869b22SIan Rogers inner_len = s_len - 3; 159*60869b22SIan Rogers } else { 160*60869b22SIan Rogers return DemangleInvalid; 161*60869b22SIan Rogers } 162*60869b22SIan Rogers 163*60869b22SIan Rogers // Paths always start with uppercase characters. 164*60869b22SIan Rogers if (*inner < 'A' || *inner > 'Z') { 165*60869b22SIan Rogers return DemangleInvalid; 166*60869b22SIan Rogers } 167*60869b22SIan Rogers 168*60869b22SIan Rogers if (!str_isascii(inner, inner_len)) { 169*60869b22SIan Rogers return DemangleInvalid; 170*60869b22SIan Rogers } 171*60869b22SIan Rogers 172*60869b22SIan Rogers struct parser parser = { inner, inner_len, 0, 0 }; 173*60869b22SIan Rogers 174*60869b22SIan Rogers demangle_status status = try_parse_path(&parser); 175*60869b22SIan Rogers if (status != DemangleOk) return status; 176*60869b22SIan Rogers char next = parser.sym[parser.next]; 177*60869b22SIan Rogers 178*60869b22SIan Rogers // Instantiating crate (paths always start with uppercase characters). 179*60869b22SIan Rogers if (parser.next < parser.sym_len && next >= 'A' && next <= 'Z') { 180*60869b22SIan Rogers status = try_parse_path(&parser); 181*60869b22SIan Rogers if (status != DemangleOk) return status; 182*60869b22SIan Rogers } 183*60869b22SIan Rogers 184*60869b22SIan Rogers res->mangled = inner; 185*60869b22SIan Rogers res->mangled_len = inner_len; 186*60869b22SIan Rogers if (rest) { 187*60869b22SIan Rogers *rest = parser.sym + parser.next; 188*60869b22SIan Rogers } 189*60869b22SIan Rogers 190*60869b22SIan Rogers return DemangleOk; 191*60869b22SIan Rogers } 192*60869b22SIan Rogers 193*60869b22SIan Rogers // This might require `len` to be up to 3 characters bigger than the real output len in case of utf-8 194*60869b22SIan Rogers NODISCARD static overflow_status rust_demangle_v0_display_demangle(struct demangle_v0 res, char *out, size_t len, bool alternate) { 195*60869b22SIan Rogers struct printer printer = { 196*60869b22SIan Rogers DemangleOk, 197*60869b22SIan Rogers { 198*60869b22SIan Rogers res.mangled, 199*60869b22SIan Rogers res.mangled_len, 200*60869b22SIan Rogers 0, 201*60869b22SIan Rogers 0 202*60869b22SIan Rogers }, 203*60869b22SIan Rogers out, 204*60869b22SIan Rogers len, 205*60869b22SIan Rogers 0, 206*60869b22SIan Rogers alternate 207*60869b22SIan Rogers }; 208*60869b22SIan Rogers if (printer_print_path(&printer, true) == OverflowOverflow) { 209*60869b22SIan Rogers return OverflowOverflow; 210*60869b22SIan Rogers } 211*60869b22SIan Rogers if (printer.out_len < OVERFLOW_MARGIN) { 212*60869b22SIan Rogers return OverflowOverflow; 213*60869b22SIan Rogers } 214*60869b22SIan Rogers *printer.out = '\0'; 215*60869b22SIan Rogers return OverflowOk; 216*60869b22SIan Rogers } 217*60869b22SIan Rogers 218*60869b22SIan Rogers static size_t code_to_utf8(unsigned char *buffer, uint32_t code) 219*60869b22SIan Rogers { 220*60869b22SIan Rogers if (code <= 0x7F) { 221*60869b22SIan Rogers buffer[0] = code; 222*60869b22SIan Rogers return 1; 223*60869b22SIan Rogers } 224*60869b22SIan Rogers if (code <= 0x7FF) { 225*60869b22SIan Rogers buffer[0] = 0xC0 | (code >> 6); /* 110xxxxx */ 226*60869b22SIan Rogers buffer[1] = 0x80 | (code & 0x3F); /* 10xxxxxx */ 227*60869b22SIan Rogers return 2; 228*60869b22SIan Rogers } 229*60869b22SIan Rogers if (code <= 0xFFFF) { 230*60869b22SIan Rogers buffer[0] = 0xE0 | (code >> 12); /* 1110xxxx */ 231*60869b22SIan Rogers buffer[1] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ 232*60869b22SIan Rogers buffer[2] = 0x80 | (code & 0x3F); /* 10xxxxxx */ 233*60869b22SIan Rogers return 3; 234*60869b22SIan Rogers } 235*60869b22SIan Rogers if (code <= 0x10FFFF) { 236*60869b22SIan Rogers buffer[0] = 0xF0 | (code >> 18); /* 11110xxx */ 237*60869b22SIan Rogers buffer[1] = 0x80 | ((code >> 12) & 0x3F); /* 10xxxxxx */ 238*60869b22SIan Rogers buffer[2] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ 239*60869b22SIan Rogers buffer[3] = 0x80 | (code & 0x3F); /* 10xxxxxx */ 240*60869b22SIan Rogers return 4; 241*60869b22SIan Rogers } 242*60869b22SIan Rogers return 0; 243*60869b22SIan Rogers } 244*60869b22SIan Rogers 245*60869b22SIan Rogers 246*60869b22SIan Rogers // return length of char at byte, or SIZE_MAX if invalid. buf should have 4 valid characters 247*60869b22SIan Rogers static NODISCARD size_t utf8_next_char(uint8_t *s, uint32_t *ch) { 248*60869b22SIan Rogers uint8_t byte = *s; 249*60869b22SIan Rogers // UTF8-1 = %x00-7F 250*60869b22SIan Rogers // UTF8-2 = %xC2-DF UTF8-tail 251*60869b22SIan Rogers // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / 252*60869b22SIan Rogers // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) 253*60869b22SIan Rogers // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / 254*60869b22SIan Rogers // %xF4 %x80-8F 2( UTF8-tail ) 255*60869b22SIan Rogers if (byte < 0x80) { 256*60869b22SIan Rogers *ch = byte; 257*60869b22SIan Rogers return 1; 258*60869b22SIan Rogers } else if (byte < 0xc2) { 259*60869b22SIan Rogers return SIZE_MAX; 260*60869b22SIan Rogers } else if (byte < 0xe0) { 261*60869b22SIan Rogers if (s[1] >= 0x80 && s[1] < 0xc0) { 262*60869b22SIan Rogers *ch = ((byte&0x1f)<<6) + (s[1] & 0x3f); 263*60869b22SIan Rogers return 2; 264*60869b22SIan Rogers } 265*60869b22SIan Rogers return SIZE_MAX; 266*60869b22SIan Rogers } if (byte < 0xf0) { 267*60869b22SIan Rogers if (!(s[1] >= 0x80 && s[1] < 0xc0) || !(s[2] >= 0x80 && s[2] < 0xc0)) { 268*60869b22SIan Rogers return SIZE_MAX; // basic validation 269*60869b22SIan Rogers } 270*60869b22SIan Rogers if (byte == 0xe0 && s[1] < 0xa0) { 271*60869b22SIan Rogers return SIZE_MAX; // overshort 272*60869b22SIan Rogers } 273*60869b22SIan Rogers if (byte == 0xed && s[1] >= 0xa0) { 274*60869b22SIan Rogers return SIZE_MAX; // surrogate 275*60869b22SIan Rogers } 276*60869b22SIan Rogers *ch = ((byte&0x0f)<<12) + ((s[1] & 0x3f)<<6) + (s[2] & 0x3f); 277*60869b22SIan Rogers return 3; 278*60869b22SIan Rogers } else if (byte < 0xf5) { 279*60869b22SIan Rogers if (!(s[1] >= 0x80 && s[1] < 0xc0) || !(s[2] >= 0x80 && s[2] < 0xc0) || !(s[3] >= 0x80 && s[3] < 0xc0)) { 280*60869b22SIan Rogers return SIZE_MAX; // basic validation 281*60869b22SIan Rogers } 282*60869b22SIan Rogers if (byte == 0xf0 && s[1] < 0x90) { 283*60869b22SIan Rogers return SIZE_MAX; // overshort 284*60869b22SIan Rogers } 285*60869b22SIan Rogers if (byte == 0xf4 && s[1] >= 0x90) { 286*60869b22SIan Rogers return SIZE_MAX; // over max 287*60869b22SIan Rogers } 288*60869b22SIan Rogers *ch = ((byte&0x07)<<18) + ((s[1] & 0x3f)<<12) + ((s[2] & 0x3f)<<6) + (s[3]&0x3f); 289*60869b22SIan Rogers return 4; 290*60869b22SIan Rogers } else { 291*60869b22SIan Rogers return SIZE_MAX; 292*60869b22SIan Rogers } 293*60869b22SIan Rogers } 294*60869b22SIan Rogers 295*60869b22SIan Rogers static NODISCARD bool validate_char(uint32_t n) { 296*60869b22SIan Rogers return ((n ^ 0xd800) - 0x800) < 0x110000 - 0x800; 297*60869b22SIan Rogers } 298*60869b22SIan Rogers 299*60869b22SIan Rogers #define SMALL_PUNYCODE_LEN 128 300*60869b22SIan Rogers 301*60869b22SIan Rogers static NODISCARD punycode_status punycode_decode(const char *start, size_t ascii_len, const char *punycode_start, size_t punycode_len, uint32_t (*out_)[SMALL_PUNYCODE_LEN], size_t *out_len) { 302*60869b22SIan Rogers uint32_t *out = *out_; 303*60869b22SIan Rogers 304*60869b22SIan Rogers if (punycode_len == 0) { 305*60869b22SIan Rogers return PunycodeError; 306*60869b22SIan Rogers } 307*60869b22SIan Rogers 308*60869b22SIan Rogers if (ascii_len > SMALL_PUNYCODE_LEN) { 309*60869b22SIan Rogers return PunycodeError; 310*60869b22SIan Rogers } 311*60869b22SIan Rogers for (size_t i = 0; i < ascii_len; i++) { 312*60869b22SIan Rogers out[i] = start[i]; 313*60869b22SIan Rogers } 314*60869b22SIan Rogers size_t len = ascii_len; 315*60869b22SIan Rogers 316*60869b22SIan Rogers size_t base = 36, t_min = 1, t_max = 26, skew = 38, damp = 700, bias = 72, i = 0, n = 0x80; 317*60869b22SIan Rogers for (;;) { 318*60869b22SIan Rogers size_t delta = 0, w = 1, k = 0; 319*60869b22SIan Rogers for (;;) { 320*60869b22SIan Rogers k += base; 321*60869b22SIan Rogers size_t biased = k < bias ? 0 : k - bias; 322*60869b22SIan Rogers size_t t = MIN(MAX(biased, t_min), t_max); 323*60869b22SIan Rogers size_t d; 324*60869b22SIan Rogers if (punycode_len == 0) { 325*60869b22SIan Rogers return PunycodeError; 326*60869b22SIan Rogers } 327*60869b22SIan Rogers char nx = *punycode_start++; 328*60869b22SIan Rogers punycode_len--; 329*60869b22SIan Rogers if ('a' <= nx && nx <= 'z') { 330*60869b22SIan Rogers d = nx - 'a'; 331*60869b22SIan Rogers } else if ('0' <= nx && nx <= '9') { 332*60869b22SIan Rogers d = 26 + (nx - '0'); 333*60869b22SIan Rogers } else { 334*60869b22SIan Rogers return PunycodeError; 335*60869b22SIan Rogers } 336*60869b22SIan Rogers if (w == 0 || d > SIZE_MAX / w || d*w > SIZE_MAX - delta) { 337*60869b22SIan Rogers return PunycodeError; 338*60869b22SIan Rogers } 339*60869b22SIan Rogers delta += d * w; 340*60869b22SIan Rogers if (d < t) { 341*60869b22SIan Rogers break; 342*60869b22SIan Rogers } 343*60869b22SIan Rogers if (base < t || w == 0 || (base - t) > SIZE_MAX / w) { 344*60869b22SIan Rogers return PunycodeError; 345*60869b22SIan Rogers } 346*60869b22SIan Rogers w *= (base - t); 347*60869b22SIan Rogers } 348*60869b22SIan Rogers 349*60869b22SIan Rogers len += 1; 350*60869b22SIan Rogers if (i > SIZE_MAX - delta) { 351*60869b22SIan Rogers return PunycodeError; 352*60869b22SIan Rogers } 353*60869b22SIan Rogers i += delta; 354*60869b22SIan Rogers if (n > SIZE_MAX - i / len) { 355*60869b22SIan Rogers return PunycodeError; 356*60869b22SIan Rogers } 357*60869b22SIan Rogers n += i / len; 358*60869b22SIan Rogers i %= len; 359*60869b22SIan Rogers 360*60869b22SIan Rogers // char validation 361*60869b22SIan Rogers if (n > UINT32_MAX || !validate_char((uint32_t)n)) { 362*60869b22SIan Rogers return PunycodeError; 363*60869b22SIan Rogers } 364*60869b22SIan Rogers 365*60869b22SIan Rogers // insert new character 366*60869b22SIan Rogers if (len > SMALL_PUNYCODE_LEN) { 367*60869b22SIan Rogers return PunycodeError; 368*60869b22SIan Rogers } 369*60869b22SIan Rogers memmove(out + i + 1, out + i, (len - i - 1) * sizeof(uint32_t)); 370*60869b22SIan Rogers out[i] = (uint32_t)n; 371*60869b22SIan Rogers 372*60869b22SIan Rogers // start i index at incremented position 373*60869b22SIan Rogers i++; 374*60869b22SIan Rogers 375*60869b22SIan Rogers // If there are no more deltas, decoding is complete. 376*60869b22SIan Rogers if (punycode_len == 0) { 377*60869b22SIan Rogers *out_len = len; 378*60869b22SIan Rogers return PunycodeOk; 379*60869b22SIan Rogers } 380*60869b22SIan Rogers 381*60869b22SIan Rogers // Perform bias adaptation. 382*60869b22SIan Rogers delta /= damp; 383*60869b22SIan Rogers damp = 2; 384*60869b22SIan Rogers 385*60869b22SIan Rogers delta += delta / len; 386*60869b22SIan Rogers k = 0; 387*60869b22SIan Rogers while (delta > ((base - t_min) * t_max) / 2) { 388*60869b22SIan Rogers delta /= base - t_min; 389*60869b22SIan Rogers k += base; 390*60869b22SIan Rogers } 391*60869b22SIan Rogers bias = k + ((base - t_min + 1) * delta) / (delta + skew); 392*60869b22SIan Rogers } 393*60869b22SIan Rogers } 394*60869b22SIan Rogers 395*60869b22SIan Rogers struct ident { 396*60869b22SIan Rogers const char *ascii_start; 397*60869b22SIan Rogers size_t ascii_len; 398*60869b22SIan Rogers const char *punycode_start; 399*60869b22SIan Rogers size_t punycode_len; 400*60869b22SIan Rogers }; 401*60869b22SIan Rogers 402*60869b22SIan Rogers static NODISCARD overflow_status display_ident(const char *ascii_start, size_t ascii_len, const char *punycode_start, size_t punycode_len, uint8_t *out, size_t *out_len) { 403*60869b22SIan Rogers uint32_t outbuf[SMALL_PUNYCODE_LEN]; 404*60869b22SIan Rogers 405*60869b22SIan Rogers size_t wide_len; 406*60869b22SIan Rogers size_t out_buflen = *out_len; 407*60869b22SIan Rogers 408*60869b22SIan Rogers if (punycode_len == 0) { 409*60869b22SIan Rogers if (ascii_len > out_buflen) { 410*60869b22SIan Rogers return OverflowOverflow; 411*60869b22SIan Rogers } 412*60869b22SIan Rogers memcpy(out, ascii_start, ascii_len); 413*60869b22SIan Rogers *out_len = ascii_len; 414*60869b22SIan Rogers } else if (punycode_decode(ascii_start, ascii_len, punycode_start, punycode_len, &outbuf, &wide_len) == PunycodeOk) { 415*60869b22SIan Rogers size_t narrow_len = 0; 416*60869b22SIan Rogers for (size_t i = 0; i < wide_len; i++) { 417*60869b22SIan Rogers if (out_buflen - narrow_len < 4) { 418*60869b22SIan Rogers return OverflowOverflow; 419*60869b22SIan Rogers } 420*60869b22SIan Rogers unsigned char *pos = &out[narrow_len]; 421*60869b22SIan Rogers narrow_len += code_to_utf8(pos, outbuf[i]); 422*60869b22SIan Rogers } 423*60869b22SIan Rogers *out_len = narrow_len; 424*60869b22SIan Rogers } else { 425*60869b22SIan Rogers size_t narrow_len = 0; 426*60869b22SIan Rogers if (out_buflen < strlen("punycode{")) { 427*60869b22SIan Rogers return OverflowOverflow; 428*60869b22SIan Rogers } 429*60869b22SIan Rogers memcpy(out, "punycode{", strlen("punycode{")); 430*60869b22SIan Rogers narrow_len = strlen("punycode{"); 431*60869b22SIan Rogers if (ascii_len > 0) { 432*60869b22SIan Rogers if (out_buflen - narrow_len < ascii_len || out_buflen - narrow_len - ascii_len < 1) { 433*60869b22SIan Rogers return OverflowOverflow; 434*60869b22SIan Rogers } 435*60869b22SIan Rogers memcpy(out + narrow_len, ascii_start, ascii_len); 436*60869b22SIan Rogers narrow_len += ascii_len; 437*60869b22SIan Rogers out[narrow_len] = '-'; 438*60869b22SIan Rogers narrow_len++; 439*60869b22SIan Rogers } 440*60869b22SIan Rogers if (out_buflen - narrow_len < punycode_len || out_buflen - narrow_len - punycode_len < 1) { 441*60869b22SIan Rogers return OverflowOverflow; 442*60869b22SIan Rogers } 443*60869b22SIan Rogers memcpy(out + narrow_len, punycode_start, punycode_len); 444*60869b22SIan Rogers narrow_len += punycode_len; 445*60869b22SIan Rogers out[narrow_len] = '}'; 446*60869b22SIan Rogers narrow_len++; 447*60869b22SIan Rogers *out_len = narrow_len; 448*60869b22SIan Rogers } 449*60869b22SIan Rogers 450*60869b22SIan Rogers return OverflowOk; 451*60869b22SIan Rogers } 452*60869b22SIan Rogers 453*60869b22SIan Rogers static NODISCARD bool try_parse_uint(const char *buf, size_t len, uint64_t *result) { 454*60869b22SIan Rogers size_t cur = 0; 455*60869b22SIan Rogers for(;cur < len && buf[cur] == '0';cur++); 456*60869b22SIan Rogers uint64_t result_val = 0; 457*60869b22SIan Rogers if (len - cur > 16) return false; 458*60869b22SIan Rogers for(;cur < len;cur++) { 459*60869b22SIan Rogers char c = buf[cur]; 460*60869b22SIan Rogers result_val <<= 4; 461*60869b22SIan Rogers if ('0' <= c && c <= '9') { 462*60869b22SIan Rogers result_val += c - '0'; 463*60869b22SIan Rogers } else if ('a' <= c && c <= 'f') { 464*60869b22SIan Rogers result_val += 10 + (c - 'a'); 465*60869b22SIan Rogers } else { 466*60869b22SIan Rogers return false; 467*60869b22SIan Rogers } 468*60869b22SIan Rogers } 469*60869b22SIan Rogers *result = result_val; 470*60869b22SIan Rogers return true; 471*60869b22SIan Rogers } 472*60869b22SIan Rogers 473*60869b22SIan Rogers static NODISCARD bool dinibble2int(const char *buf, uint8_t *result) { 474*60869b22SIan Rogers uint8_t result_val = 0; 475*60869b22SIan Rogers for (int i = 0; i < 2; i++) { 476*60869b22SIan Rogers char c = buf[i]; 477*60869b22SIan Rogers result_val <<= 4; 478*60869b22SIan Rogers if ('0' <= c && c <= '9') { 479*60869b22SIan Rogers result_val += c - '0'; 480*60869b22SIan Rogers } else if ('a' <= c && c <= 'f') { 481*60869b22SIan Rogers result_val += 10 + (c - 'a'); 482*60869b22SIan Rogers } else { 483*60869b22SIan Rogers return false; 484*60869b22SIan Rogers } 485*60869b22SIan Rogers } 486*60869b22SIan Rogers *result = result_val; 487*60869b22SIan Rogers return true; 488*60869b22SIan Rogers } 489*60869b22SIan Rogers 490*60869b22SIan Rogers 491*60869b22SIan Rogers typedef enum { 492*60869b22SIan Rogers NtsOk = 0, 493*60869b22SIan Rogers NtsOverflow = 1, 494*60869b22SIan Rogers NtsInvalid = 2 495*60869b22SIan Rogers } nibbles_to_string_status; 496*60869b22SIan Rogers 497*60869b22SIan Rogers // '\u{10ffff}', +margin 498*60869b22SIan Rogers #define ESCAPED_SIZE 12 499*60869b22SIan Rogers 500*60869b22SIan Rogers static NODISCARD size_t char_to_string(uint32_t ch, uint8_t quote, bool first, char (*buf)[ESCAPED_SIZE]) { 501*60869b22SIan Rogers // encode the character 502*60869b22SIan Rogers char *escaped_buf = *buf; 503*60869b22SIan Rogers escaped_buf[0] = '\\'; 504*60869b22SIan Rogers size_t escaped_len = 2; 505*60869b22SIan Rogers switch (ch) { 506*60869b22SIan Rogers case '\0': 507*60869b22SIan Rogers escaped_buf[1] = '0'; 508*60869b22SIan Rogers break; 509*60869b22SIan Rogers case '\t': 510*60869b22SIan Rogers escaped_buf[1] = 't'; 511*60869b22SIan Rogers break; 512*60869b22SIan Rogers case '\r': 513*60869b22SIan Rogers escaped_buf[1] = 'r'; 514*60869b22SIan Rogers break; 515*60869b22SIan Rogers case '\n': 516*60869b22SIan Rogers escaped_buf[1] = 'n'; 517*60869b22SIan Rogers break; 518*60869b22SIan Rogers case '\\': 519*60869b22SIan Rogers escaped_buf[1] = '\\'; 520*60869b22SIan Rogers break; 521*60869b22SIan Rogers default: 522*60869b22SIan Rogers if (ch == quote) { 523*60869b22SIan Rogers escaped_buf[1] = ch; 524*60869b22SIan Rogers } else if (!unicode_isprint(ch) || (first && unicode_isgraphemextend(ch))) { 525*60869b22SIan Rogers int hexlen = snprintf(escaped_buf, ESCAPED_SIZE, "\\u{%x}", (unsigned int)ch); 526*60869b22SIan Rogers if (hexlen < 0) { 527*60869b22SIan Rogers return 0; // (snprintf shouldn't fail!) 528*60869b22SIan Rogers } 529*60869b22SIan Rogers escaped_len = hexlen; 530*60869b22SIan Rogers } else { 531*60869b22SIan Rogers // printable character 532*60869b22SIan Rogers escaped_buf[0] = ch; 533*60869b22SIan Rogers escaped_len = 1; 534*60869b22SIan Rogers } 535*60869b22SIan Rogers break; 536*60869b22SIan Rogers } 537*60869b22SIan Rogers 538*60869b22SIan Rogers return escaped_len; 539*60869b22SIan Rogers } 540*60869b22SIan Rogers 541*60869b22SIan Rogers // convert nibbles to a single/double-quoted string 542*60869b22SIan Rogers static NODISCARD nibbles_to_string_status nibbles_to_string(const char *buf, size_t len, uint8_t *out, size_t *out_len) { 543*60869b22SIan Rogers uint8_t quote = '"'; 544*60869b22SIan Rogers bool first = true; 545*60869b22SIan Rogers 546*60869b22SIan Rogers if ((len % 2) != 0) { 547*60869b22SIan Rogers return NtsInvalid; // odd number of nibbles 548*60869b22SIan Rogers } 549*60869b22SIan Rogers 550*60869b22SIan Rogers size_t cur_out_len = 0; 551*60869b22SIan Rogers 552*60869b22SIan Rogers // write starting quote 553*60869b22SIan Rogers if (out != NULL) { 554*60869b22SIan Rogers cur_out_len = *out_len; 555*60869b22SIan Rogers if (cur_out_len == 0) { 556*60869b22SIan Rogers return NtsOverflow; 557*60869b22SIan Rogers } 558*60869b22SIan Rogers *out++ = quote; 559*60869b22SIan Rogers cur_out_len--; 560*60869b22SIan Rogers } 561*60869b22SIan Rogers 562*60869b22SIan Rogers uint8_t conv_buf[4] = {0}; 563*60869b22SIan Rogers size_t conv_buf_len = 0; 564*60869b22SIan Rogers while (len > 1 || conv_buf_len > 0) { 565*60869b22SIan Rogers while (len > 1 && conv_buf_len < sizeof(conv_buf)) { 566*60869b22SIan Rogers if (!dinibble2int(buf, &conv_buf[conv_buf_len])) { 567*60869b22SIan Rogers return NtsInvalid; 568*60869b22SIan Rogers } 569*60869b22SIan Rogers conv_buf_len++; 570*60869b22SIan Rogers buf += 2; 571*60869b22SIan Rogers len -= 2; 572*60869b22SIan Rogers } 573*60869b22SIan Rogers 574*60869b22SIan Rogers // conv_buf is full here if possible, process 1 UTF-8 character 575*60869b22SIan Rogers uint32_t ch = 0; 576*60869b22SIan Rogers size_t consumed = utf8_next_char(conv_buf, &ch); 577*60869b22SIan Rogers if (consumed > conv_buf_len) { 578*60869b22SIan Rogers // either SIZE_MAX (invalid UTF-8) or finished input buffer and 579*60869b22SIan Rogers // there are still bytes remaining, in both cases invalid 580*60869b22SIan Rogers return NtsInvalid; 581*60869b22SIan Rogers } 582*60869b22SIan Rogers 583*60869b22SIan Rogers // "consume" the character 584*60869b22SIan Rogers memmove(conv_buf, conv_buf+consumed, conv_buf_len-consumed); 585*60869b22SIan Rogers conv_buf_len -= consumed; 586*60869b22SIan Rogers 587*60869b22SIan Rogers char escaped_buf[ESCAPED_SIZE]; 588*60869b22SIan Rogers size_t escaped_len = char_to_string(ch, '"', first, &escaped_buf); 589*60869b22SIan Rogers if (out != NULL) { 590*60869b22SIan Rogers if (cur_out_len < escaped_len) { 591*60869b22SIan Rogers return NtsOverflow; 592*60869b22SIan Rogers } 593*60869b22SIan Rogers memcpy(out, escaped_buf, escaped_len); 594*60869b22SIan Rogers out += escaped_len; 595*60869b22SIan Rogers cur_out_len -= escaped_len; 596*60869b22SIan Rogers } 597*60869b22SIan Rogers first = false; 598*60869b22SIan Rogers } 599*60869b22SIan Rogers 600*60869b22SIan Rogers // write ending quote 601*60869b22SIan Rogers if (out != NULL) { 602*60869b22SIan Rogers if (cur_out_len == 0) { 603*60869b22SIan Rogers return NtsOverflow; 604*60869b22SIan Rogers } 605*60869b22SIan Rogers *out++ = quote; 606*60869b22SIan Rogers cur_out_len--; 607*60869b22SIan Rogers *out_len -= cur_out_len; // subtract remaining space to get used space 608*60869b22SIan Rogers } 609*60869b22SIan Rogers 610*60869b22SIan Rogers return NtsOk; 611*60869b22SIan Rogers } 612*60869b22SIan Rogers 613*60869b22SIan Rogers static const char* basic_type(uint8_t tag) { 614*60869b22SIan Rogers switch(tag) { 615*60869b22SIan Rogers case 'b': 616*60869b22SIan Rogers return "bool"; 617*60869b22SIan Rogers case 'c': 618*60869b22SIan Rogers return "char"; 619*60869b22SIan Rogers case 'e': 620*60869b22SIan Rogers return "str"; 621*60869b22SIan Rogers case 'u': 622*60869b22SIan Rogers return "()"; 623*60869b22SIan Rogers case 'a': 624*60869b22SIan Rogers return "i8"; 625*60869b22SIan Rogers case 's': 626*60869b22SIan Rogers return "i16"; 627*60869b22SIan Rogers case 'l': 628*60869b22SIan Rogers return "i32"; 629*60869b22SIan Rogers case 'x': 630*60869b22SIan Rogers return "i64"; 631*60869b22SIan Rogers case 'n': 632*60869b22SIan Rogers return "i128"; 633*60869b22SIan Rogers case 'i': 634*60869b22SIan Rogers return "isize"; 635*60869b22SIan Rogers case 'h': 636*60869b22SIan Rogers return "u8"; 637*60869b22SIan Rogers case 't': 638*60869b22SIan Rogers return "u16"; 639*60869b22SIan Rogers case 'm': 640*60869b22SIan Rogers return "u32"; 641*60869b22SIan Rogers case 'y': 642*60869b22SIan Rogers return "u64"; 643*60869b22SIan Rogers case 'o': 644*60869b22SIan Rogers return "u128"; 645*60869b22SIan Rogers case 'j': 646*60869b22SIan Rogers return "usize"; 647*60869b22SIan Rogers case 'f': 648*60869b22SIan Rogers return "f32"; 649*60869b22SIan Rogers case 'd': 650*60869b22SIan Rogers return "f64"; 651*60869b22SIan Rogers case 'z': 652*60869b22SIan Rogers return "!"; 653*60869b22SIan Rogers case 'p': 654*60869b22SIan Rogers return "_"; 655*60869b22SIan Rogers case 'v': 656*60869b22SIan Rogers return "..."; 657*60869b22SIan Rogers default: 658*60869b22SIan Rogers return NULL; 659*60869b22SIan Rogers } 660*60869b22SIan Rogers } 661*60869b22SIan Rogers 662*60869b22SIan Rogers static NODISCARD demangle_status parser_push_depth(struct parser *parser) { 663*60869b22SIan Rogers parser->depth++; 664*60869b22SIan Rogers if (parser->depth > MAX_DEPTH) { 665*60869b22SIan Rogers return DemangleRecursed; 666*60869b22SIan Rogers } else { 667*60869b22SIan Rogers return DemangleOk; 668*60869b22SIan Rogers } 669*60869b22SIan Rogers } 670*60869b22SIan Rogers 671*60869b22SIan Rogers static demangle_status parser_pop_depth(struct parser *parser) { 672*60869b22SIan Rogers parser->depth--; 673*60869b22SIan Rogers return DemangleOk; 674*60869b22SIan Rogers } 675*60869b22SIan Rogers 676*60869b22SIan Rogers static uint8_t parser_peek(struct parser const *parser) { 677*60869b22SIan Rogers if (parser->next == parser->sym_len) { 678*60869b22SIan Rogers return 0; // add a "pseudo nul terminator" to avoid peeking past the end of a symbol 679*60869b22SIan Rogers } else { 680*60869b22SIan Rogers return parser->sym[parser->next]; 681*60869b22SIan Rogers } 682*60869b22SIan Rogers } 683*60869b22SIan Rogers 684*60869b22SIan Rogers static bool parser_eat(struct parser *parser, uint8_t ch) { 685*60869b22SIan Rogers if (parser_peek(parser) == ch) { 686*60869b22SIan Rogers if (ch != 0) { // safety: make sure we don't skip past the NUL terminator 687*60869b22SIan Rogers parser->next++; 688*60869b22SIan Rogers } 689*60869b22SIan Rogers return true; 690*60869b22SIan Rogers } else { 691*60869b22SIan Rogers return false; 692*60869b22SIan Rogers } 693*60869b22SIan Rogers } 694*60869b22SIan Rogers 695*60869b22SIan Rogers static uint8_t parser_next(struct parser *parser) { 696*60869b22SIan Rogers // don't advance after end of input, and return an imaginary NUL terminator 697*60869b22SIan Rogers if (parser->next == parser->sym_len) { 698*60869b22SIan Rogers return 0; 699*60869b22SIan Rogers } else { 700*60869b22SIan Rogers return parser->sym[parser->next++]; 701*60869b22SIan Rogers } 702*60869b22SIan Rogers } 703*60869b22SIan Rogers 704*60869b22SIan Rogers static NODISCARD demangle_status parser_ch(struct parser *parser, uint8_t *next) { 705*60869b22SIan Rogers // don't advance after end of input 706*60869b22SIan Rogers if (parser->next == parser->sym_len) { 707*60869b22SIan Rogers return DemangleInvalid; 708*60869b22SIan Rogers } else { 709*60869b22SIan Rogers *next = parser->sym[parser->next++]; 710*60869b22SIan Rogers return DemangleOk; 711*60869b22SIan Rogers } 712*60869b22SIan Rogers } 713*60869b22SIan Rogers 714*60869b22SIan Rogers struct buf { 715*60869b22SIan Rogers const char *start; 716*60869b22SIan Rogers size_t len; 717*60869b22SIan Rogers }; 718*60869b22SIan Rogers 719*60869b22SIan Rogers static NODISCARD demangle_status parser_hex_nibbles(struct parser *parser, struct buf *buf) { 720*60869b22SIan Rogers size_t start = parser->next; 721*60869b22SIan Rogers for (;;) { 722*60869b22SIan Rogers uint8_t ch = parser_next(parser); 723*60869b22SIan Rogers if (ch == '_') { 724*60869b22SIan Rogers break; 725*60869b22SIan Rogers } 726*60869b22SIan Rogers if (!(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f'))) { 727*60869b22SIan Rogers return DemangleInvalid; 728*60869b22SIan Rogers } 729*60869b22SIan Rogers } 730*60869b22SIan Rogers buf->start = parser->sym + start; 731*60869b22SIan Rogers buf->len = parser->next - start - 1; // skip final _ 732*60869b22SIan Rogers return DemangleOk; 733*60869b22SIan Rogers } 734*60869b22SIan Rogers 735*60869b22SIan Rogers static NODISCARD demangle_status parser_digit_10(struct parser *parser, uint8_t *out) { 736*60869b22SIan Rogers uint8_t ch = parser_peek(parser); 737*60869b22SIan Rogers if ('0' <= ch && ch <= '9') { 738*60869b22SIan Rogers *out = ch - '0'; 739*60869b22SIan Rogers parser->next++; 740*60869b22SIan Rogers return DemangleOk; 741*60869b22SIan Rogers } else { 742*60869b22SIan Rogers return DemangleInvalid; 743*60869b22SIan Rogers } 744*60869b22SIan Rogers } 745*60869b22SIan Rogers 746*60869b22SIan Rogers static NODISCARD demangle_status parser_digit_62(struct parser *parser, uint64_t *out) { 747*60869b22SIan Rogers uint8_t ch = parser_peek(parser); 748*60869b22SIan Rogers if ('0' <= ch && ch <= '9') { 749*60869b22SIan Rogers *out = ch - '0'; 750*60869b22SIan Rogers parser->next++; 751*60869b22SIan Rogers return DemangleOk; 752*60869b22SIan Rogers } else if ('a' <= ch && ch <= 'z') { 753*60869b22SIan Rogers *out = 10 + (ch - 'a'); 754*60869b22SIan Rogers parser->next++; 755*60869b22SIan Rogers return DemangleOk; 756*60869b22SIan Rogers } else if ('A' <= ch && ch <= 'Z') { 757*60869b22SIan Rogers *out = 10 + 26 + (ch - 'A'); 758*60869b22SIan Rogers parser->next++; 759*60869b22SIan Rogers return DemangleOk; 760*60869b22SIan Rogers } else { 761*60869b22SIan Rogers return DemangleInvalid; 762*60869b22SIan Rogers } 763*60869b22SIan Rogers } 764*60869b22SIan Rogers 765*60869b22SIan Rogers static NODISCARD demangle_status parser_integer_62(struct parser *parser, uint64_t *out) { 766*60869b22SIan Rogers if (parser_eat(parser, '_')) { 767*60869b22SIan Rogers *out = 0; 768*60869b22SIan Rogers return DemangleOk; 769*60869b22SIan Rogers } 770*60869b22SIan Rogers 771*60869b22SIan Rogers uint64_t x = 0; 772*60869b22SIan Rogers demangle_status status; 773*60869b22SIan Rogers while (!parser_eat(parser, '_')) { 774*60869b22SIan Rogers uint64_t d; 775*60869b22SIan Rogers if ((status = parser_digit_62(parser, &d)) != DemangleOk) { 776*60869b22SIan Rogers return status; 777*60869b22SIan Rogers } 778*60869b22SIan Rogers if (x > UINT64_MAX / 62) { 779*60869b22SIan Rogers return DemangleInvalid; 780*60869b22SIan Rogers } 781*60869b22SIan Rogers x *= 62; 782*60869b22SIan Rogers if (x > UINT64_MAX - d) { 783*60869b22SIan Rogers return DemangleInvalid; 784*60869b22SIan Rogers } 785*60869b22SIan Rogers x += d; 786*60869b22SIan Rogers } 787*60869b22SIan Rogers if (x == UINT64_MAX) { 788*60869b22SIan Rogers return DemangleInvalid; 789*60869b22SIan Rogers } 790*60869b22SIan Rogers *out = x + 1; 791*60869b22SIan Rogers return DemangleOk; 792*60869b22SIan Rogers } 793*60869b22SIan Rogers 794*60869b22SIan Rogers static NODISCARD demangle_status parser_opt_integer_62(struct parser *parser, uint8_t tag, uint64_t *out) { 795*60869b22SIan Rogers if (!parser_eat(parser, tag)) { 796*60869b22SIan Rogers *out = 0; 797*60869b22SIan Rogers return DemangleOk; 798*60869b22SIan Rogers } 799*60869b22SIan Rogers 800*60869b22SIan Rogers demangle_status status; 801*60869b22SIan Rogers if ((status = parser_integer_62(parser, out)) != DemangleOk) { 802*60869b22SIan Rogers return status; 803*60869b22SIan Rogers } 804*60869b22SIan Rogers if (*out == UINT64_MAX) { 805*60869b22SIan Rogers return DemangleInvalid; 806*60869b22SIan Rogers } 807*60869b22SIan Rogers *out = *out + 1; 808*60869b22SIan Rogers return DemangleOk; 809*60869b22SIan Rogers } 810*60869b22SIan Rogers 811*60869b22SIan Rogers static NODISCARD demangle_status parser_disambiguator(struct parser *parser, uint64_t *out) { 812*60869b22SIan Rogers return parser_opt_integer_62(parser, 's', out); 813*60869b22SIan Rogers } 814*60869b22SIan Rogers 815*60869b22SIan Rogers typedef uint8_t parser_namespace_type; 816*60869b22SIan Rogers 817*60869b22SIan Rogers static NODISCARD demangle_status parser_namespace(struct parser *parser, parser_namespace_type *out) { 818*60869b22SIan Rogers uint8_t next = parser_next(parser); 819*60869b22SIan Rogers if ('A' <= next && next <= 'Z') { 820*60869b22SIan Rogers *out = next; 821*60869b22SIan Rogers return DemangleOk; 822*60869b22SIan Rogers } else if ('a' <= next && next <= 'z') { 823*60869b22SIan Rogers *out = 0; 824*60869b22SIan Rogers return DemangleOk; 825*60869b22SIan Rogers } else { 826*60869b22SIan Rogers return DemangleInvalid; 827*60869b22SIan Rogers } 828*60869b22SIan Rogers } 829*60869b22SIan Rogers 830*60869b22SIan Rogers static NODISCARD demangle_status parser_backref(struct parser *parser, struct parser *out) { 831*60869b22SIan Rogers size_t start = parser->next; 832*60869b22SIan Rogers if (start == 0) { 833*60869b22SIan Rogers return DemangleBug; 834*60869b22SIan Rogers } 835*60869b22SIan Rogers size_t s_start = start - 1; 836*60869b22SIan Rogers uint64_t i; 837*60869b22SIan Rogers demangle_status status = parser_integer_62(parser, &i); 838*60869b22SIan Rogers if (status != DemangleOk) { 839*60869b22SIan Rogers return status; 840*60869b22SIan Rogers } 841*60869b22SIan Rogers if (i >= s_start) { 842*60869b22SIan Rogers return DemangleInvalid; 843*60869b22SIan Rogers } 844*60869b22SIan Rogers struct parser res = { 845*60869b22SIan Rogers .sym = parser->sym, 846*60869b22SIan Rogers .sym_len = parser->sym_len, 847*60869b22SIan Rogers .next = (size_t)i, 848*60869b22SIan Rogers .depth = parser->depth 849*60869b22SIan Rogers }; 850*60869b22SIan Rogers status = parser_push_depth(&res); 851*60869b22SIan Rogers if (status != DemangleOk) { 852*60869b22SIan Rogers return status; 853*60869b22SIan Rogers } 854*60869b22SIan Rogers *out = res; 855*60869b22SIan Rogers return DemangleOk; 856*60869b22SIan Rogers } 857*60869b22SIan Rogers 858*60869b22SIan Rogers static NODISCARD demangle_status parser_ident(struct parser *parser, struct ident *out) { 859*60869b22SIan Rogers bool is_punycode = parser_eat(parser, 'u'); 860*60869b22SIan Rogers size_t len; 861*60869b22SIan Rogers uint8_t d; 862*60869b22SIan Rogers demangle_status status = parser_digit_10(parser, &d); 863*60869b22SIan Rogers len = d; 864*60869b22SIan Rogers if (status != DemangleOk) { 865*60869b22SIan Rogers return status; 866*60869b22SIan Rogers } 867*60869b22SIan Rogers if (len) { 868*60869b22SIan Rogers for (;;) { 869*60869b22SIan Rogers status = parser_digit_10(parser, &d); 870*60869b22SIan Rogers if (status != DemangleOk) { 871*60869b22SIan Rogers break; 872*60869b22SIan Rogers } 873*60869b22SIan Rogers if (len > SIZE_MAX / 10) { 874*60869b22SIan Rogers return DemangleInvalid; 875*60869b22SIan Rogers } 876*60869b22SIan Rogers len *= 10; 877*60869b22SIan Rogers if (len > SIZE_MAX - d) { 878*60869b22SIan Rogers return DemangleInvalid; 879*60869b22SIan Rogers } 880*60869b22SIan Rogers len += d; 881*60869b22SIan Rogers } 882*60869b22SIan Rogers } 883*60869b22SIan Rogers 884*60869b22SIan Rogers // Skip past the optional `_` separator. 885*60869b22SIan Rogers parser_eat(parser, '_'); 886*60869b22SIan Rogers 887*60869b22SIan Rogers size_t start = parser->next; 888*60869b22SIan Rogers if (parser->sym_len - parser->next < len) { 889*60869b22SIan Rogers return DemangleInvalid; 890*60869b22SIan Rogers } 891*60869b22SIan Rogers parser->next += len; 892*60869b22SIan Rogers 893*60869b22SIan Rogers const char *ident = &parser->sym[start]; 894*60869b22SIan Rogers 895*60869b22SIan Rogers if (is_punycode) { 896*60869b22SIan Rogers const char *underscore = demangle_memrchr(ident, '_', (size_t)len); 897*60869b22SIan Rogers if (underscore == NULL) { 898*60869b22SIan Rogers *out = (struct ident){ 899*60869b22SIan Rogers .ascii_start="", 900*60869b22SIan Rogers .ascii_len=0, 901*60869b22SIan Rogers .punycode_start=ident, 902*60869b22SIan Rogers .punycode_len=len 903*60869b22SIan Rogers }; 904*60869b22SIan Rogers } else { 905*60869b22SIan Rogers size_t ascii_len = underscore - ident; 906*60869b22SIan Rogers // ascii_len <= len - 1 since `_` is in the first len bytes 907*60869b22SIan Rogers size_t punycode_len = len - 1 - ascii_len; 908*60869b22SIan Rogers *out = (struct ident){ 909*60869b22SIan Rogers .ascii_start=ident, 910*60869b22SIan Rogers .ascii_len=ascii_len, 911*60869b22SIan Rogers .punycode_start=underscore + 1, 912*60869b22SIan Rogers .punycode_len=punycode_len 913*60869b22SIan Rogers }; 914*60869b22SIan Rogers } 915*60869b22SIan Rogers if (out->punycode_len == 0) { 916*60869b22SIan Rogers return DemangleInvalid; 917*60869b22SIan Rogers } 918*60869b22SIan Rogers return DemangleOk; 919*60869b22SIan Rogers } else { 920*60869b22SIan Rogers *out = (struct ident) { 921*60869b22SIan Rogers .ascii_start=ident, 922*60869b22SIan Rogers .ascii_len=(size_t)len, 923*60869b22SIan Rogers .punycode_start="", 924*60869b22SIan Rogers .punycode_len=0, 925*60869b22SIan Rogers }; 926*60869b22SIan Rogers return DemangleOk; 927*60869b22SIan Rogers } 928*60869b22SIan Rogers } 929*60869b22SIan Rogers 930*60869b22SIan Rogers #define INVALID_SYNTAX "{invalid syntax}" 931*60869b22SIan Rogers 932*60869b22SIan Rogers static const char *demangle_error_message(demangle_status status) { 933*60869b22SIan Rogers switch (status) { 934*60869b22SIan Rogers case DemangleInvalid: 935*60869b22SIan Rogers return INVALID_SYNTAX; 936*60869b22SIan Rogers case DemangleBug: 937*60869b22SIan Rogers return "{bug}"; 938*60869b22SIan Rogers case DemangleRecursed: 939*60869b22SIan Rogers return "{recursion limit reached}"; 940*60869b22SIan Rogers default: 941*60869b22SIan Rogers return "{unknown error}"; 942*60869b22SIan Rogers } 943*60869b22SIan Rogers } 944*60869b22SIan Rogers 945*60869b22SIan Rogers #define PRINT(print_fn) \ 946*60869b22SIan Rogers do { \ 947*60869b22SIan Rogers if ((print_fn) == OverflowOverflow) { \ 948*60869b22SIan Rogers return OverflowOverflow; \ 949*60869b22SIan Rogers } \ 950*60869b22SIan Rogers } while(0) 951*60869b22SIan Rogers 952*60869b22SIan Rogers #define PRINT_CH(printer, s) PRINT(printer_print_ch((printer), (s))) 953*60869b22SIan Rogers #define PRINT_STR(printer, s) PRINT(printer_print_str((printer), (s))) 954*60869b22SIan Rogers #define PRINT_U64(printer, s) PRINT(printer_print_u64((printer), (s))) 955*60869b22SIan Rogers #define PRINT_IDENT(printer, s) PRINT(printer_print_ident((printer), (s))) 956*60869b22SIan Rogers 957*60869b22SIan Rogers #define INVALID(printer) \ 958*60869b22SIan Rogers do { \ 959*60869b22SIan Rogers PRINT_STR((printer), INVALID_SYNTAX); \ 960*60869b22SIan Rogers (printer)->status = DemangleInvalid; \ 961*60869b22SIan Rogers return OverflowOk; \ 962*60869b22SIan Rogers } while(0) 963*60869b22SIan Rogers 964*60869b22SIan Rogers #define PARSE(printer, method, ...) \ 965*60869b22SIan Rogers do { \ 966*60869b22SIan Rogers if ((printer)->status != DemangleOk) { \ 967*60869b22SIan Rogers PRINT_STR((printer), "?"); \ 968*60869b22SIan Rogers return OverflowOk; \ 969*60869b22SIan Rogers } else { \ 970*60869b22SIan Rogers demangle_status _parse_status = method(&(printer)->parser, ## __VA_ARGS__); \ 971*60869b22SIan Rogers if (_parse_status != DemangleOk) { \ 972*60869b22SIan Rogers PRINT_STR((printer), demangle_error_message(_parse_status)); \ 973*60869b22SIan Rogers (printer)->status = _parse_status; \ 974*60869b22SIan Rogers return OverflowOk; \ 975*60869b22SIan Rogers } \ 976*60869b22SIan Rogers } \ 977*60869b22SIan Rogers } while(0) 978*60869b22SIan Rogers 979*60869b22SIan Rogers #define PRINT_SEP_LIST(printer, body, sep) \ 980*60869b22SIan Rogers do { \ 981*60869b22SIan Rogers size_t _sep_list_i; \ 982*60869b22SIan Rogers PRINT_SEP_LIST_COUNT(printer, _sep_list_i, body, sep); \ 983*60869b22SIan Rogers } while(0) 984*60869b22SIan Rogers 985*60869b22SIan Rogers #define PRINT_SEP_LIST_COUNT(printer, count, body, sep) \ 986*60869b22SIan Rogers do { \ 987*60869b22SIan Rogers count = 0; \ 988*60869b22SIan Rogers while ((printer)->status == DemangleOk && !printer_eat((printer), 'E')) { \ 989*60869b22SIan Rogers if (count > 0) { PRINT_STR(printer, sep); } \ 990*60869b22SIan Rogers body; \ 991*60869b22SIan Rogers count++; \ 992*60869b22SIan Rogers } \ 993*60869b22SIan Rogers } while(0) 994*60869b22SIan Rogers 995*60869b22SIan Rogers static bool printer_eat(struct printer *printer, uint8_t b) { 996*60869b22SIan Rogers if (printer->status != DemangleOk) { 997*60869b22SIan Rogers return false; 998*60869b22SIan Rogers } 999*60869b22SIan Rogers 1000*60869b22SIan Rogers return parser_eat(&printer->parser, b); 1001*60869b22SIan Rogers } 1002*60869b22SIan Rogers 1003*60869b22SIan Rogers static void printer_pop_depth(struct printer *printer) { 1004*60869b22SIan Rogers if (printer->status == DemangleOk) { 1005*60869b22SIan Rogers parser_pop_depth(&printer->parser); 1006*60869b22SIan Rogers } 1007*60869b22SIan Rogers } 1008*60869b22SIan Rogers 1009*60869b22SIan Rogers static NODISCARD overflow_status printer_print_buf(struct printer *printer, const char *start, size_t len) { 1010*60869b22SIan Rogers if (printer->out == NULL) { 1011*60869b22SIan Rogers return OverflowOk; 1012*60869b22SIan Rogers } 1013*60869b22SIan Rogers if (printer->out_len < len) { 1014*60869b22SIan Rogers return OverflowOverflow; 1015*60869b22SIan Rogers } 1016*60869b22SIan Rogers 1017*60869b22SIan Rogers memcpy(printer->out, start, len); 1018*60869b22SIan Rogers printer->out += len; 1019*60869b22SIan Rogers printer->out_len -= len; 1020*60869b22SIan Rogers return OverflowOk; 1021*60869b22SIan Rogers } 1022*60869b22SIan Rogers 1023*60869b22SIan Rogers static NODISCARD overflow_status printer_print_str(struct printer *printer, const char *buf) { 1024*60869b22SIan Rogers return printer_print_buf(printer, buf, strlen(buf)); 1025*60869b22SIan Rogers } 1026*60869b22SIan Rogers 1027*60869b22SIan Rogers static NODISCARD overflow_status printer_print_ch(struct printer *printer, char ch) { 1028*60869b22SIan Rogers return printer_print_buf(printer, &ch, 1); 1029*60869b22SIan Rogers } 1030*60869b22SIan Rogers 1031*60869b22SIan Rogers static NODISCARD overflow_status printer_print_u64(struct printer *printer, uint64_t n) { 1032*60869b22SIan Rogers char buf[32] = {0}; 1033*60869b22SIan Rogers sprintf(buf, "%llu", (unsigned long long)n); // printing uint64 uses 21 < 32 chars 1034*60869b22SIan Rogers return printer_print_str(printer, buf); 1035*60869b22SIan Rogers } 1036*60869b22SIan Rogers 1037*60869b22SIan Rogers static NODISCARD overflow_status printer_print_ident(struct printer *printer, struct ident *ident) { 1038*60869b22SIan Rogers if (printer->out == NULL) { 1039*60869b22SIan Rogers return OverflowOk; 1040*60869b22SIan Rogers } 1041*60869b22SIan Rogers 1042*60869b22SIan Rogers size_t out_len = printer->out_len; 1043*60869b22SIan Rogers overflow_status status; 1044*60869b22SIan Rogers if ((status = display_ident(ident->ascii_start, ident->ascii_len, ident->punycode_start, ident->punycode_len, (uint8_t*)printer->out, &out_len)) != OverflowOk) { 1045*60869b22SIan Rogers return status; 1046*60869b22SIan Rogers } 1047*60869b22SIan Rogers printer->out += out_len; 1048*60869b22SIan Rogers printer->out_len -= out_len; 1049*60869b22SIan Rogers return OverflowOk; 1050*60869b22SIan Rogers } 1051*60869b22SIan Rogers 1052*60869b22SIan Rogers typedef overflow_status (*printer_fn)(struct printer *printer); 1053*60869b22SIan Rogers typedef overflow_status (*backref_fn)(struct printer *printer, bool *arg); 1054*60869b22SIan Rogers 1055*60869b22SIan Rogers static NODISCARD overflow_status printer_print_backref(struct printer *printer, backref_fn func, bool *arg) { 1056*60869b22SIan Rogers struct parser backref; 1057*60869b22SIan Rogers PARSE(printer, parser_backref, &backref); 1058*60869b22SIan Rogers 1059*60869b22SIan Rogers if (printer->out == NULL) { 1060*60869b22SIan Rogers return OverflowOk; 1061*60869b22SIan Rogers } 1062*60869b22SIan Rogers 1063*60869b22SIan Rogers struct parser orig_parser = printer->parser; 1064*60869b22SIan Rogers demangle_status orig_status = printer->status; // fixme not sure this is needed match for Ok on the Rust side 1065*60869b22SIan Rogers printer->parser = backref; 1066*60869b22SIan Rogers printer->status = DemangleOk; 1067*60869b22SIan Rogers overflow_status status = func(printer, arg); 1068*60869b22SIan Rogers printer->parser = orig_parser; 1069*60869b22SIan Rogers printer->status = orig_status; 1070*60869b22SIan Rogers 1071*60869b22SIan Rogers return status; 1072*60869b22SIan Rogers } 1073*60869b22SIan Rogers 1074*60869b22SIan Rogers static NODISCARD overflow_status printer_print_lifetime_from_index(struct printer *printer, uint64_t lt) { 1075*60869b22SIan Rogers // Bound lifetimes aren't tracked when skipping printing. 1076*60869b22SIan Rogers if (printer->out == NULL) { 1077*60869b22SIan Rogers return OverflowOk; 1078*60869b22SIan Rogers } 1079*60869b22SIan Rogers 1080*60869b22SIan Rogers PRINT_STR(printer, "'"); 1081*60869b22SIan Rogers if (lt == 0) { 1082*60869b22SIan Rogers PRINT_STR(printer, "_"); 1083*60869b22SIan Rogers return OverflowOk; 1084*60869b22SIan Rogers } 1085*60869b22SIan Rogers 1086*60869b22SIan Rogers if (printer->bound_lifetime_depth < lt) { 1087*60869b22SIan Rogers INVALID(printer); 1088*60869b22SIan Rogers } else { 1089*60869b22SIan Rogers uint64_t depth = printer->bound_lifetime_depth - lt; 1090*60869b22SIan Rogers if (depth < 26) { 1091*60869b22SIan Rogers PRINT_CH(printer, 'a' + depth); 1092*60869b22SIan Rogers } else { 1093*60869b22SIan Rogers PRINT_STR(printer, "_"); 1094*60869b22SIan Rogers PRINT_U64(printer, depth); 1095*60869b22SIan Rogers } 1096*60869b22SIan Rogers 1097*60869b22SIan Rogers return OverflowOk; 1098*60869b22SIan Rogers } 1099*60869b22SIan Rogers } 1100*60869b22SIan Rogers 1101*60869b22SIan Rogers static NODISCARD overflow_status printer_in_binder(struct printer *printer, printer_fn func) { 1102*60869b22SIan Rogers uint64_t bound_lifetimes; 1103*60869b22SIan Rogers PARSE(printer, parser_opt_integer_62, 'G', &bound_lifetimes); 1104*60869b22SIan Rogers 1105*60869b22SIan Rogers // Don't track bound lifetimes when skipping printing. 1106*60869b22SIan Rogers if (printer->out == NULL) { 1107*60869b22SIan Rogers return func(printer); 1108*60869b22SIan Rogers } 1109*60869b22SIan Rogers 1110*60869b22SIan Rogers if (bound_lifetimes > 0) { 1111*60869b22SIan Rogers PRINT_STR(printer, "for<"); 1112*60869b22SIan Rogers for (uint64_t i = 0; i < bound_lifetimes; i++) { 1113*60869b22SIan Rogers if (i > 0) { 1114*60869b22SIan Rogers PRINT_STR(printer, ", "); 1115*60869b22SIan Rogers } 1116*60869b22SIan Rogers printer->bound_lifetime_depth++; 1117*60869b22SIan Rogers PRINT(printer_print_lifetime_from_index(printer, 1)); 1118*60869b22SIan Rogers } 1119*60869b22SIan Rogers PRINT_STR(printer, "> "); 1120*60869b22SIan Rogers } 1121*60869b22SIan Rogers 1122*60869b22SIan Rogers overflow_status r = func(printer); 1123*60869b22SIan Rogers printer->bound_lifetime_depth -= bound_lifetimes; 1124*60869b22SIan Rogers 1125*60869b22SIan Rogers return r; 1126*60869b22SIan Rogers } 1127*60869b22SIan Rogers 1128*60869b22SIan Rogers static NODISCARD overflow_status printer_print_generic_arg(struct printer *printer) { 1129*60869b22SIan Rogers if (printer_eat(printer, 'L')) { 1130*60869b22SIan Rogers uint64_t lt; 1131*60869b22SIan Rogers PARSE(printer, parser_integer_62, <); 1132*60869b22SIan Rogers return printer_print_lifetime_from_index(printer, lt); 1133*60869b22SIan Rogers } else if (printer_eat(printer, 'K')) { 1134*60869b22SIan Rogers return printer_print_const(printer, false); 1135*60869b22SIan Rogers } else { 1136*60869b22SIan Rogers return printer_print_type(printer); 1137*60869b22SIan Rogers } 1138*60869b22SIan Rogers } 1139*60869b22SIan Rogers 1140*60869b22SIan Rogers static NODISCARD overflow_status printer_print_generic_args(struct printer *printer) { 1141*60869b22SIan Rogers PRINT_STR(printer, "<"); 1142*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_generic_arg(printer)), ", "); 1143*60869b22SIan Rogers PRINT_STR(printer, ">"); 1144*60869b22SIan Rogers return OverflowOk; 1145*60869b22SIan Rogers } 1146*60869b22SIan Rogers 1147*60869b22SIan Rogers static NODISCARD overflow_status printer_print_path_out_of_value(struct printer *printer, bool *_arg) { 1148*60869b22SIan Rogers (void)_arg; 1149*60869b22SIan Rogers return printer_print_path(printer, false); 1150*60869b22SIan Rogers } 1151*60869b22SIan Rogers 1152*60869b22SIan Rogers static NODISCARD overflow_status printer_print_path_in_value(struct printer *printer, bool *_arg) { 1153*60869b22SIan Rogers (void)_arg; 1154*60869b22SIan Rogers return printer_print_path(printer, true); 1155*60869b22SIan Rogers } 1156*60869b22SIan Rogers 1157*60869b22SIan Rogers static NODISCARD overflow_status printer_print_path(struct printer *printer, bool in_value) { 1158*60869b22SIan Rogers PARSE(printer, parser_push_depth); 1159*60869b22SIan Rogers uint8_t tag; 1160*60869b22SIan Rogers PARSE(printer, parser_ch, &tag); 1161*60869b22SIan Rogers 1162*60869b22SIan Rogers overflow_status st; 1163*60869b22SIan Rogers uint64_t dis; 1164*60869b22SIan Rogers struct ident name; 1165*60869b22SIan Rogers parser_namespace_type ns; 1166*60869b22SIan Rogers char *orig_out; 1167*60869b22SIan Rogers 1168*60869b22SIan Rogers switch(tag) { 1169*60869b22SIan Rogers case 'C': 1170*60869b22SIan Rogers PARSE(printer, parser_disambiguator, &dis); 1171*60869b22SIan Rogers PARSE(printer, parser_ident, &name); 1172*60869b22SIan Rogers 1173*60869b22SIan Rogers PRINT_IDENT(printer, &name); 1174*60869b22SIan Rogers 1175*60869b22SIan Rogers if (printer->out != NULL && !printer->alternate && dis != 0) { 1176*60869b22SIan Rogers PRINT_STR(printer, "["); 1177*60869b22SIan Rogers char buf[24] = {0}; 1178*60869b22SIan Rogers sprintf(buf, "%llx", (unsigned long long)dis); 1179*60869b22SIan Rogers PRINT_STR(printer, buf); 1180*60869b22SIan Rogers PRINT_STR(printer, "]"); 1181*60869b22SIan Rogers } 1182*60869b22SIan Rogers break; 1183*60869b22SIan Rogers case 'N': 1184*60869b22SIan Rogers PARSE(printer, parser_namespace, &ns); 1185*60869b22SIan Rogers if ((st = printer_print_path(printer, in_value)) != OverflowOk) { 1186*60869b22SIan Rogers return st; 1187*60869b22SIan Rogers } 1188*60869b22SIan Rogers 1189*60869b22SIan Rogers // HACK(eddyb) if the parser is already marked as having errored, 1190*60869b22SIan Rogers // `parse!` below will print a `?` without its preceding `::` 1191*60869b22SIan Rogers // (because printing the `::` is skipped in certain conditions, 1192*60869b22SIan Rogers // i.e. a lowercase namespace with an empty identifier), 1193*60869b22SIan Rogers // so in order to get `::?`, the `::` has to be printed here. 1194*60869b22SIan Rogers if (printer->status != DemangleOk) { 1195*60869b22SIan Rogers PRINT_STR(printer, "::"); 1196*60869b22SIan Rogers } 1197*60869b22SIan Rogers 1198*60869b22SIan Rogers PARSE(printer, parser_disambiguator, &dis); 1199*60869b22SIan Rogers PARSE(printer, parser_ident, &name); 1200*60869b22SIan Rogers // Special namespace, like closures and shims 1201*60869b22SIan Rogers if (ns) { 1202*60869b22SIan Rogers PRINT_STR(printer, "::{"); 1203*60869b22SIan Rogers if (ns == 'C') { 1204*60869b22SIan Rogers PRINT_STR(printer, "closure"); 1205*60869b22SIan Rogers } else if (ns == 'S') { 1206*60869b22SIan Rogers PRINT_STR(printer, "shim"); 1207*60869b22SIan Rogers } else { 1208*60869b22SIan Rogers PRINT_CH(printer, ns); 1209*60869b22SIan Rogers } 1210*60869b22SIan Rogers if (name.ascii_len != 0 || name.punycode_len != 0) { 1211*60869b22SIan Rogers PRINT_STR(printer, ":"); 1212*60869b22SIan Rogers PRINT_IDENT(printer, &name); 1213*60869b22SIan Rogers } 1214*60869b22SIan Rogers PRINT_STR(printer, "#"); 1215*60869b22SIan Rogers PRINT_U64(printer, dis); 1216*60869b22SIan Rogers PRINT_STR(printer, "}"); 1217*60869b22SIan Rogers } else { 1218*60869b22SIan Rogers // Implementation-specific/unspecified namespaces 1219*60869b22SIan Rogers if (name.ascii_len != 0 || name.punycode_len != 0) { 1220*60869b22SIan Rogers PRINT_STR(printer, "::"); 1221*60869b22SIan Rogers PRINT_IDENT(printer, &name); 1222*60869b22SIan Rogers } 1223*60869b22SIan Rogers } 1224*60869b22SIan Rogers break; 1225*60869b22SIan Rogers case 'M': 1226*60869b22SIan Rogers case 'X': 1227*60869b22SIan Rogers // for impls, ignore the impls own path 1228*60869b22SIan Rogers PARSE(printer, parser_disambiguator, &dis); 1229*60869b22SIan Rogers orig_out = printer->out; 1230*60869b22SIan Rogers printer->out = NULL; 1231*60869b22SIan Rogers PRINT(printer_print_path(printer, false)); 1232*60869b22SIan Rogers printer->out = orig_out; 1233*60869b22SIan Rogers 1234*60869b22SIan Rogers // fallthru 1235*60869b22SIan Rogers case 'Y': 1236*60869b22SIan Rogers PRINT_STR(printer, "<"); 1237*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1238*60869b22SIan Rogers if (tag != 'M') { 1239*60869b22SIan Rogers PRINT_STR(printer, " as "); 1240*60869b22SIan Rogers PRINT(printer_print_path(printer, false)); 1241*60869b22SIan Rogers } 1242*60869b22SIan Rogers PRINT_STR(printer, ">"); 1243*60869b22SIan Rogers break; 1244*60869b22SIan Rogers case 'I': 1245*60869b22SIan Rogers PRINT(printer_print_path(printer, in_value)); 1246*60869b22SIan Rogers if (in_value) { 1247*60869b22SIan Rogers PRINT_STR(printer, "::"); 1248*60869b22SIan Rogers } 1249*60869b22SIan Rogers PRINT(printer_print_generic_args(printer)); 1250*60869b22SIan Rogers break; 1251*60869b22SIan Rogers case 'B': 1252*60869b22SIan Rogers PRINT(printer_print_backref(printer, in_value ? printer_print_path_in_value : printer_print_path_out_of_value, NULL)); 1253*60869b22SIan Rogers break; 1254*60869b22SIan Rogers default: 1255*60869b22SIan Rogers INVALID(printer); 1256*60869b22SIan Rogers break; 1257*60869b22SIan Rogers } 1258*60869b22SIan Rogers 1259*60869b22SIan Rogers printer_pop_depth(printer); 1260*60869b22SIan Rogers return OverflowOk; 1261*60869b22SIan Rogers } 1262*60869b22SIan Rogers 1263*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const_uint(struct printer *printer, uint8_t tag) { 1264*60869b22SIan Rogers struct buf hex; 1265*60869b22SIan Rogers PARSE(printer, parser_hex_nibbles, &hex); 1266*60869b22SIan Rogers 1267*60869b22SIan Rogers uint64_t val; 1268*60869b22SIan Rogers if (try_parse_uint(hex.start, hex.len, &val)) { 1269*60869b22SIan Rogers PRINT_U64(printer, val); 1270*60869b22SIan Rogers } else { 1271*60869b22SIan Rogers PRINT_STR(printer, "0x"); 1272*60869b22SIan Rogers PRINT(printer_print_buf(printer, hex.start, hex.len)); 1273*60869b22SIan Rogers } 1274*60869b22SIan Rogers 1275*60869b22SIan Rogers if (printer->out != NULL && !printer->alternate) { 1276*60869b22SIan Rogers const char *ty = basic_type(tag); 1277*60869b22SIan Rogers if (/* safety */ ty != NULL) { 1278*60869b22SIan Rogers PRINT_STR(printer, ty); 1279*60869b22SIan Rogers } 1280*60869b22SIan Rogers } 1281*60869b22SIan Rogers 1282*60869b22SIan Rogers return OverflowOk; 1283*60869b22SIan Rogers } 1284*60869b22SIan Rogers 1285*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const_str_literal(struct printer *printer) { 1286*60869b22SIan Rogers struct buf hex; 1287*60869b22SIan Rogers PARSE(printer, parser_hex_nibbles, &hex); 1288*60869b22SIan Rogers 1289*60869b22SIan Rogers size_t out_len = SIZE_MAX; 1290*60869b22SIan Rogers nibbles_to_string_status nts_status = nibbles_to_string(hex.start, hex.len, NULL, &out_len); 1291*60869b22SIan Rogers switch (nts_status) { 1292*60869b22SIan Rogers case NtsOk: 1293*60869b22SIan Rogers if (printer->out != NULL) { 1294*60869b22SIan Rogers out_len = printer->out_len; 1295*60869b22SIan Rogers nts_status = nibbles_to_string(hex.start, hex.len, (uint8_t*)printer->out, &out_len); 1296*60869b22SIan Rogers if (nts_status != NtsOk) { 1297*60869b22SIan Rogers return OverflowOverflow; 1298*60869b22SIan Rogers } 1299*60869b22SIan Rogers printer->out += out_len; 1300*60869b22SIan Rogers printer->out_len -= out_len; 1301*60869b22SIan Rogers } 1302*60869b22SIan Rogers return OverflowOk; 1303*60869b22SIan Rogers case NtsOverflow: 1304*60869b22SIan Rogers // technically if there is a string of size `SIZE_MAX/6` whose escaped version overflows 1305*60869b22SIan Rogers // SIZE_MAX but has an invalid char, this will be a "fake" overflow. In practice, 1306*60869b22SIan Rogers // that is not going to happen and a fuzzer will not generate strings of this length. 1307*60869b22SIan Rogers return OverflowOverflow; 1308*60869b22SIan Rogers case NtsInvalid: 1309*60869b22SIan Rogers default: 1310*60869b22SIan Rogers INVALID(printer); 1311*60869b22SIan Rogers } 1312*60869b22SIan Rogers } 1313*60869b22SIan Rogers 1314*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const_struct(struct printer *printer) { 1315*60869b22SIan Rogers uint64_t dis; 1316*60869b22SIan Rogers struct ident name; 1317*60869b22SIan Rogers PARSE(printer, parser_disambiguator, &dis); 1318*60869b22SIan Rogers PARSE(printer, parser_ident, &name); 1319*60869b22SIan Rogers PRINT_IDENT(printer, &name); 1320*60869b22SIan Rogers PRINT_STR(printer, ": "); 1321*60869b22SIan Rogers return printer_print_const(printer, true); 1322*60869b22SIan Rogers } 1323*60869b22SIan Rogers 1324*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const_out_of_value(struct printer *printer, bool *_arg) { 1325*60869b22SIan Rogers (void)_arg; 1326*60869b22SIan Rogers return printer_print_const(printer, false); 1327*60869b22SIan Rogers } 1328*60869b22SIan Rogers 1329*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const_in_value(struct printer *printer, bool *_arg) { 1330*60869b22SIan Rogers (void)_arg; 1331*60869b22SIan Rogers return printer_print_const(printer, true); 1332*60869b22SIan Rogers } 1333*60869b22SIan Rogers 1334*60869b22SIan Rogers static NODISCARD overflow_status printer_print_const(struct printer *printer, bool in_value) { 1335*60869b22SIan Rogers uint8_t tag; 1336*60869b22SIan Rogers 1337*60869b22SIan Rogers PARSE(printer, parser_ch, &tag); 1338*60869b22SIan Rogers PARSE(printer, parser_push_depth); 1339*60869b22SIan Rogers 1340*60869b22SIan Rogers struct buf hex; 1341*60869b22SIan Rogers uint64_t val; 1342*60869b22SIan Rogers size_t count; 1343*60869b22SIan Rogers 1344*60869b22SIan Rogers bool opened_brace = false; 1345*60869b22SIan Rogers #define OPEN_BRACE_IF_OUTSIDE_EXPR \ 1346*60869b22SIan Rogers do { if (!in_value) { \ 1347*60869b22SIan Rogers opened_brace = true; \ 1348*60869b22SIan Rogers PRINT_STR(printer, "{"); \ 1349*60869b22SIan Rogers } } while(0) 1350*60869b22SIan Rogers 1351*60869b22SIan Rogers switch(tag) { 1352*60869b22SIan Rogers case 'p': 1353*60869b22SIan Rogers PRINT_STR(printer, "_"); 1354*60869b22SIan Rogers break; 1355*60869b22SIan Rogers // Primitive leaves with hex-encoded values (see `basic_type`). 1356*60869b22SIan Rogers case 'a': 1357*60869b22SIan Rogers case 's': 1358*60869b22SIan Rogers case 'l': 1359*60869b22SIan Rogers case 'x': 1360*60869b22SIan Rogers case 'n': 1361*60869b22SIan Rogers case 'i': 1362*60869b22SIan Rogers if (printer_eat(printer, 'n')) { 1363*60869b22SIan Rogers PRINT_STR(printer, "-"); 1364*60869b22SIan Rogers } 1365*60869b22SIan Rogers /* fallthrough */ 1366*60869b22SIan Rogers case 'h': 1367*60869b22SIan Rogers case 't': 1368*60869b22SIan Rogers case 'm': 1369*60869b22SIan Rogers case 'y': 1370*60869b22SIan Rogers case 'o': 1371*60869b22SIan Rogers case 'j': 1372*60869b22SIan Rogers PRINT(printer_print_const_uint(printer, tag)); 1373*60869b22SIan Rogers break; 1374*60869b22SIan Rogers case 'b': 1375*60869b22SIan Rogers PARSE(printer, parser_hex_nibbles, &hex); 1376*60869b22SIan Rogers if (try_parse_uint(hex.start, hex.len, &val)) { 1377*60869b22SIan Rogers if (val == 0) { 1378*60869b22SIan Rogers PRINT_STR(printer, "false"); 1379*60869b22SIan Rogers } else if (val == 1) { 1380*60869b22SIan Rogers PRINT_STR(printer, "true"); 1381*60869b22SIan Rogers } else { 1382*60869b22SIan Rogers INVALID(printer); 1383*60869b22SIan Rogers } 1384*60869b22SIan Rogers } else { 1385*60869b22SIan Rogers INVALID(printer); 1386*60869b22SIan Rogers } 1387*60869b22SIan Rogers break; 1388*60869b22SIan Rogers case 'c': 1389*60869b22SIan Rogers PARSE(printer, parser_hex_nibbles, &hex); 1390*60869b22SIan Rogers if (try_parse_uint(hex.start, hex.len, &val) 1391*60869b22SIan Rogers && val < UINT32_MAX 1392*60869b22SIan Rogers && validate_char((uint32_t)val)) 1393*60869b22SIan Rogers { 1394*60869b22SIan Rogers char escaped_buf[ESCAPED_SIZE]; 1395*60869b22SIan Rogers size_t escaped_size = char_to_string((uint32_t)val, '\'', true, &escaped_buf); 1396*60869b22SIan Rogers 1397*60869b22SIan Rogers PRINT_STR(printer, "'"); 1398*60869b22SIan Rogers PRINT(printer_print_buf(printer, escaped_buf, escaped_size)); 1399*60869b22SIan Rogers PRINT_STR(printer, "'"); 1400*60869b22SIan Rogers } else { 1401*60869b22SIan Rogers INVALID(printer); 1402*60869b22SIan Rogers } 1403*60869b22SIan Rogers break; 1404*60869b22SIan Rogers case 'e': 1405*60869b22SIan Rogers OPEN_BRACE_IF_OUTSIDE_EXPR; 1406*60869b22SIan Rogers PRINT_STR(printer, "*"); 1407*60869b22SIan Rogers PRINT(printer_print_const_str_literal(printer)); 1408*60869b22SIan Rogers break; 1409*60869b22SIan Rogers case 'R': 1410*60869b22SIan Rogers case 'Q': 1411*60869b22SIan Rogers if (tag == 'R' && printer_eat(printer, 'e')) { 1412*60869b22SIan Rogers PRINT(printer_print_const_str_literal(printer)); 1413*60869b22SIan Rogers } else { 1414*60869b22SIan Rogers OPEN_BRACE_IF_OUTSIDE_EXPR; 1415*60869b22SIan Rogers PRINT_STR(printer, "&"); 1416*60869b22SIan Rogers if (tag != 'R') { 1417*60869b22SIan Rogers PRINT_STR(printer, "mut "); 1418*60869b22SIan Rogers } 1419*60869b22SIan Rogers PRINT(printer_print_const(printer, true)); 1420*60869b22SIan Rogers } 1421*60869b22SIan Rogers break; 1422*60869b22SIan Rogers case 'A': 1423*60869b22SIan Rogers OPEN_BRACE_IF_OUTSIDE_EXPR; 1424*60869b22SIan Rogers PRINT_STR(printer, "["); 1425*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_const(printer, true)), ", "); 1426*60869b22SIan Rogers PRINT_STR(printer, "]"); 1427*60869b22SIan Rogers break; 1428*60869b22SIan Rogers case 'T': 1429*60869b22SIan Rogers OPEN_BRACE_IF_OUTSIDE_EXPR; 1430*60869b22SIan Rogers PRINT_STR(printer, "("); 1431*60869b22SIan Rogers PRINT_SEP_LIST_COUNT(printer, count, PRINT(printer_print_const(printer, true)), ", "); 1432*60869b22SIan Rogers if (count == 1) { 1433*60869b22SIan Rogers PRINT_STR(printer, ","); 1434*60869b22SIan Rogers } 1435*60869b22SIan Rogers PRINT_STR(printer, ")"); 1436*60869b22SIan Rogers break; 1437*60869b22SIan Rogers case 'V': 1438*60869b22SIan Rogers OPEN_BRACE_IF_OUTSIDE_EXPR; 1439*60869b22SIan Rogers PRINT(printer_print_path(printer, true)); 1440*60869b22SIan Rogers PARSE(printer, parser_ch, &tag); 1441*60869b22SIan Rogers switch(tag) { 1442*60869b22SIan Rogers case 'U': 1443*60869b22SIan Rogers break; 1444*60869b22SIan Rogers case 'T': 1445*60869b22SIan Rogers PRINT_STR(printer, "("); 1446*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_const(printer, true)), ", "); 1447*60869b22SIan Rogers PRINT_STR(printer, ")"); 1448*60869b22SIan Rogers break; 1449*60869b22SIan Rogers case 'S': 1450*60869b22SIan Rogers PRINT_STR(printer, " { "); 1451*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_const_struct(printer)), ", "); 1452*60869b22SIan Rogers PRINT_STR(printer, " }"); 1453*60869b22SIan Rogers break; 1454*60869b22SIan Rogers default: 1455*60869b22SIan Rogers INVALID(printer); 1456*60869b22SIan Rogers } 1457*60869b22SIan Rogers break; 1458*60869b22SIan Rogers case 'B': 1459*60869b22SIan Rogers PRINT(printer_print_backref(printer, in_value ? printer_print_const_in_value : printer_print_const_out_of_value, NULL)); 1460*60869b22SIan Rogers break; 1461*60869b22SIan Rogers default: 1462*60869b22SIan Rogers INVALID(printer); 1463*60869b22SIan Rogers } 1464*60869b22SIan Rogers #undef OPEN_BRACE_IF_OUTSIDE_EXPR 1465*60869b22SIan Rogers 1466*60869b22SIan Rogers if (opened_brace) { 1467*60869b22SIan Rogers PRINT_STR(printer, "}"); 1468*60869b22SIan Rogers } 1469*60869b22SIan Rogers printer_pop_depth(printer); 1470*60869b22SIan Rogers 1471*60869b22SIan Rogers return OverflowOk; 1472*60869b22SIan Rogers } 1473*60869b22SIan Rogers 1474*60869b22SIan Rogers /// A trait in a trait object may have some "existential projections" 1475*60869b22SIan Rogers /// (i.e. associated type bindings) after it, which should be printed 1476*60869b22SIan Rogers /// in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`. 1477*60869b22SIan Rogers /// To this end, this method will keep the `<...>` of an 'I' path 1478*60869b22SIan Rogers /// open, by omitting the `>`, and return `Ok(true)` in that case. 1479*60869b22SIan Rogers static NODISCARD overflow_status printer_print_maybe_open_generics(struct printer *printer, bool *open) { 1480*60869b22SIan Rogers if (printer_eat(printer, 'B')) { 1481*60869b22SIan Rogers // NOTE(eddyb) the closure may not run if printing is being skipped, 1482*60869b22SIan Rogers // but in that case the returned boolean doesn't matter. 1483*60869b22SIan Rogers *open = false; 1484*60869b22SIan Rogers return printer_print_backref(printer, printer_print_maybe_open_generics, open); 1485*60869b22SIan Rogers } else if(printer_eat(printer, 'I')) { 1486*60869b22SIan Rogers PRINT(printer_print_path(printer, false)); 1487*60869b22SIan Rogers PRINT_STR(printer, "<"); 1488*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_generic_arg(printer)), ", "); 1489*60869b22SIan Rogers *open = true; 1490*60869b22SIan Rogers return OverflowOk; 1491*60869b22SIan Rogers } else { 1492*60869b22SIan Rogers PRINT(printer_print_path(printer, false)); 1493*60869b22SIan Rogers *open = false; 1494*60869b22SIan Rogers return OverflowOk; 1495*60869b22SIan Rogers } 1496*60869b22SIan Rogers } 1497*60869b22SIan Rogers 1498*60869b22SIan Rogers static NODISCARD overflow_status printer_print_dyn_trait(struct printer *printer) { 1499*60869b22SIan Rogers bool open; 1500*60869b22SIan Rogers PRINT(printer_print_maybe_open_generics(printer, &open)); 1501*60869b22SIan Rogers 1502*60869b22SIan Rogers while (printer_eat(printer, 'p')) { 1503*60869b22SIan Rogers if (!open) { 1504*60869b22SIan Rogers PRINT_STR(printer, "<"); 1505*60869b22SIan Rogers open = true; 1506*60869b22SIan Rogers } else { 1507*60869b22SIan Rogers PRINT_STR(printer, ", "); 1508*60869b22SIan Rogers } 1509*60869b22SIan Rogers 1510*60869b22SIan Rogers struct ident name; 1511*60869b22SIan Rogers PARSE(printer, parser_ident, &name); 1512*60869b22SIan Rogers 1513*60869b22SIan Rogers PRINT_IDENT(printer, &name); 1514*60869b22SIan Rogers PRINT_STR(printer, " = "); 1515*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1516*60869b22SIan Rogers } 1517*60869b22SIan Rogers 1518*60869b22SIan Rogers if (open) { 1519*60869b22SIan Rogers PRINT_STR(printer, ">"); 1520*60869b22SIan Rogers } 1521*60869b22SIan Rogers 1522*60869b22SIan Rogers return OverflowOk; 1523*60869b22SIan Rogers } 1524*60869b22SIan Rogers 1525*60869b22SIan Rogers static NODISCARD overflow_status printer_print_object_bounds(struct printer *printer) { 1526*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_dyn_trait(printer)), " + "); 1527*60869b22SIan Rogers return OverflowOk; 1528*60869b22SIan Rogers } 1529*60869b22SIan Rogers 1530*60869b22SIan Rogers static NODISCARD overflow_status printer_print_function_type(struct printer *printer) { 1531*60869b22SIan Rogers bool is_unsafe = printer_eat(printer, 'U'); 1532*60869b22SIan Rogers const char *abi; 1533*60869b22SIan Rogers size_t abi_len; 1534*60869b22SIan Rogers if (printer_eat(printer, 'K')) { 1535*60869b22SIan Rogers if (printer_eat(printer, 'C')) { 1536*60869b22SIan Rogers abi = "C"; 1537*60869b22SIan Rogers abi_len = 1; 1538*60869b22SIan Rogers } else { 1539*60869b22SIan Rogers struct ident abi_ident; 1540*60869b22SIan Rogers PARSE(printer, parser_ident, &abi_ident); 1541*60869b22SIan Rogers if (abi_ident.ascii_len == 0 || abi_ident.punycode_len != 0) { 1542*60869b22SIan Rogers INVALID(printer); 1543*60869b22SIan Rogers } 1544*60869b22SIan Rogers abi = abi_ident.ascii_start; 1545*60869b22SIan Rogers abi_len = abi_ident.ascii_len; 1546*60869b22SIan Rogers } 1547*60869b22SIan Rogers } else { 1548*60869b22SIan Rogers abi = NULL; 1549*60869b22SIan Rogers abi_len = 0; 1550*60869b22SIan Rogers } 1551*60869b22SIan Rogers 1552*60869b22SIan Rogers if (is_unsafe) { 1553*60869b22SIan Rogers PRINT_STR(printer, "unsafe "); 1554*60869b22SIan Rogers } 1555*60869b22SIan Rogers 1556*60869b22SIan Rogers if (abi != NULL) { 1557*60869b22SIan Rogers PRINT_STR(printer, "extern \""); 1558*60869b22SIan Rogers 1559*60869b22SIan Rogers // replace _ with - 1560*60869b22SIan Rogers while (abi_len > 0) { 1561*60869b22SIan Rogers const char *minus = memchr(abi, '_', abi_len); 1562*60869b22SIan Rogers if (minus == NULL) { 1563*60869b22SIan Rogers PRINT(printer_print_buf(printer, (const char*)abi, abi_len)); 1564*60869b22SIan Rogers break; 1565*60869b22SIan Rogers } else { 1566*60869b22SIan Rogers size_t space_to_minus = minus - abi; 1567*60869b22SIan Rogers PRINT(printer_print_buf(printer, (const char*)abi, space_to_minus)); 1568*60869b22SIan Rogers PRINT_STR(printer, "-"); 1569*60869b22SIan Rogers abi = minus + 1; 1570*60869b22SIan Rogers abi_len -= (space_to_minus + 1); 1571*60869b22SIan Rogers } 1572*60869b22SIan Rogers } 1573*60869b22SIan Rogers 1574*60869b22SIan Rogers PRINT_STR(printer, "\" "); 1575*60869b22SIan Rogers } 1576*60869b22SIan Rogers 1577*60869b22SIan Rogers PRINT_STR(printer, "fn("); 1578*60869b22SIan Rogers PRINT_SEP_LIST(printer, PRINT(printer_print_type(printer)), ", "); 1579*60869b22SIan Rogers PRINT_STR(printer, ")"); 1580*60869b22SIan Rogers 1581*60869b22SIan Rogers if (printer_eat(printer, 'u')) { 1582*60869b22SIan Rogers // Skip printing the return type if it's 'u', i.e. `()`. 1583*60869b22SIan Rogers } else { 1584*60869b22SIan Rogers PRINT_STR(printer, " -> "); 1585*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1586*60869b22SIan Rogers } 1587*60869b22SIan Rogers 1588*60869b22SIan Rogers return OverflowOk; 1589*60869b22SIan Rogers } 1590*60869b22SIan Rogers 1591*60869b22SIan Rogers static NODISCARD overflow_status printer_print_type_backref(struct printer *printer, bool *_arg) { 1592*60869b22SIan Rogers (void)_arg; 1593*60869b22SIan Rogers return printer_print_type(printer); 1594*60869b22SIan Rogers } 1595*60869b22SIan Rogers 1596*60869b22SIan Rogers static NODISCARD overflow_status printer_print_type(struct printer *printer) { 1597*60869b22SIan Rogers uint8_t tag; 1598*60869b22SIan Rogers PARSE(printer, parser_ch, &tag); 1599*60869b22SIan Rogers 1600*60869b22SIan Rogers const char *basic_ty = basic_type(tag); 1601*60869b22SIan Rogers if (basic_ty) { 1602*60869b22SIan Rogers return printer_print_str(printer, basic_ty); 1603*60869b22SIan Rogers } 1604*60869b22SIan Rogers 1605*60869b22SIan Rogers uint64_t count; 1606*60869b22SIan Rogers uint64_t lt; 1607*60869b22SIan Rogers 1608*60869b22SIan Rogers PARSE(printer, parser_push_depth); 1609*60869b22SIan Rogers switch (tag) { 1610*60869b22SIan Rogers case 'R': 1611*60869b22SIan Rogers case 'Q': 1612*60869b22SIan Rogers PRINT_STR(printer, "&"); 1613*60869b22SIan Rogers if (printer_eat(printer, 'L')) { 1614*60869b22SIan Rogers PARSE(printer, parser_integer_62, <); 1615*60869b22SIan Rogers if (lt != 0) { 1616*60869b22SIan Rogers PRINT(printer_print_lifetime_from_index(printer, lt)); 1617*60869b22SIan Rogers PRINT_STR(printer, " "); 1618*60869b22SIan Rogers } 1619*60869b22SIan Rogers } 1620*60869b22SIan Rogers if (tag != 'R') { 1621*60869b22SIan Rogers PRINT_STR(printer, "mut "); 1622*60869b22SIan Rogers } 1623*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1624*60869b22SIan Rogers break; 1625*60869b22SIan Rogers case 'P': 1626*60869b22SIan Rogers case 'O': 1627*60869b22SIan Rogers PRINT_STR(printer, "*"); 1628*60869b22SIan Rogers if (tag != 'P') { 1629*60869b22SIan Rogers PRINT_STR(printer, "mut "); 1630*60869b22SIan Rogers } else { 1631*60869b22SIan Rogers PRINT_STR(printer, "const "); 1632*60869b22SIan Rogers } 1633*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1634*60869b22SIan Rogers break; 1635*60869b22SIan Rogers case 'A': 1636*60869b22SIan Rogers case 'S': 1637*60869b22SIan Rogers PRINT_STR(printer, "["); 1638*60869b22SIan Rogers PRINT(printer_print_type(printer)); 1639*60869b22SIan Rogers if (tag == 'A') { 1640*60869b22SIan Rogers PRINT_STR(printer, "; "); 1641*60869b22SIan Rogers PRINT(printer_print_const(printer, true)); 1642*60869b22SIan Rogers } 1643*60869b22SIan Rogers PRINT_STR(printer, "]"); 1644*60869b22SIan Rogers break; 1645*60869b22SIan Rogers case 'T': 1646*60869b22SIan Rogers PRINT_STR(printer, "("); 1647*60869b22SIan Rogers PRINT_SEP_LIST_COUNT(printer, count, PRINT(printer_print_type(printer)), ", "); 1648*60869b22SIan Rogers if (count == 1) { 1649*60869b22SIan Rogers PRINT_STR(printer, ","); 1650*60869b22SIan Rogers } 1651*60869b22SIan Rogers PRINT_STR(printer, ")"); 1652*60869b22SIan Rogers break; 1653*60869b22SIan Rogers case 'F': 1654*60869b22SIan Rogers PRINT(printer_in_binder(printer, printer_print_function_type)); 1655*60869b22SIan Rogers break; 1656*60869b22SIan Rogers case 'D': 1657*60869b22SIan Rogers PRINT_STR(printer, "dyn "); 1658*60869b22SIan Rogers PRINT(printer_in_binder(printer, printer_print_object_bounds)); 1659*60869b22SIan Rogers 1660*60869b22SIan Rogers if (!printer_eat(printer, 'L')) { 1661*60869b22SIan Rogers INVALID(printer); 1662*60869b22SIan Rogers } 1663*60869b22SIan Rogers PARSE(printer, parser_integer_62, <); 1664*60869b22SIan Rogers 1665*60869b22SIan Rogers if (lt != 0) { 1666*60869b22SIan Rogers PRINT_STR(printer, " + "); 1667*60869b22SIan Rogers PRINT(printer_print_lifetime_from_index(printer, lt)); 1668*60869b22SIan Rogers } 1669*60869b22SIan Rogers break; 1670*60869b22SIan Rogers case 'B': 1671*60869b22SIan Rogers PRINT(printer_print_backref(printer, printer_print_type_backref, NULL)); 1672*60869b22SIan Rogers break; 1673*60869b22SIan Rogers default: 1674*60869b22SIan Rogers // Go back to the tag, so `print_path` also sees it. 1675*60869b22SIan Rogers if (printer->status == DemangleOk && /* safety */ printer->parser.next > 0) { 1676*60869b22SIan Rogers printer->parser.next--; 1677*60869b22SIan Rogers } 1678*60869b22SIan Rogers PRINT(printer_print_path(printer, false)); 1679*60869b22SIan Rogers } 1680*60869b22SIan Rogers 1681*60869b22SIan Rogers printer_pop_depth(printer); 1682*60869b22SIan Rogers return OverflowOk; 1683*60869b22SIan Rogers } 1684*60869b22SIan Rogers 1685*60869b22SIan Rogers NODISCARD static demangle_status rust_demangle_legacy_demangle(const char *s, size_t s_len, struct demangle_legacy *res, const char **rest) 1686*60869b22SIan Rogers { 1687*60869b22SIan Rogers if (s_len > strlen(s)) { 1688*60869b22SIan Rogers // s_len only exists to shorten the string, this is not a buffer API 1689*60869b22SIan Rogers return DemangleInvalid; 1690*60869b22SIan Rogers } 1691*60869b22SIan Rogers 1692*60869b22SIan Rogers const char *inner; 1693*60869b22SIan Rogers size_t inner_len; 1694*60869b22SIan Rogers if (s_len >= 3 && !strncmp(s, "_ZN", 3)) { 1695*60869b22SIan Rogers inner = s + 3; 1696*60869b22SIan Rogers inner_len = s_len - 3; 1697*60869b22SIan Rogers } else if (s_len >= 2 && !strncmp(s, "ZN", 2)) { 1698*60869b22SIan Rogers // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" 1699*60869b22SIan Rogers // form too. 1700*60869b22SIan Rogers inner = s + 2; 1701*60869b22SIan Rogers inner_len = s_len - 2; 1702*60869b22SIan Rogers } else if (s_len >= 4 && !strncmp(s, "__ZN", 4)) { 1703*60869b22SIan Rogers // On OSX, symbols are prefixed with an extra _ 1704*60869b22SIan Rogers inner = s + 4; 1705*60869b22SIan Rogers inner_len = s_len - 4; 1706*60869b22SIan Rogers } else { 1707*60869b22SIan Rogers return DemangleInvalid; 1708*60869b22SIan Rogers } 1709*60869b22SIan Rogers 1710*60869b22SIan Rogers if (!str_isascii(inner, inner_len)) { 1711*60869b22SIan Rogers return DemangleInvalid; 1712*60869b22SIan Rogers } 1713*60869b22SIan Rogers 1714*60869b22SIan Rogers size_t elements = 0; 1715*60869b22SIan Rogers const char *chars = inner; 1716*60869b22SIan Rogers size_t chars_len = inner_len; 1717*60869b22SIan Rogers if (chars_len == 0) { 1718*60869b22SIan Rogers return DemangleInvalid; 1719*60869b22SIan Rogers } 1720*60869b22SIan Rogers char c; 1721*60869b22SIan Rogers while ((c = *chars) != 'E') { 1722*60869b22SIan Rogers // Decode an identifier element's length 1723*60869b22SIan Rogers if (c < '0' || c > '9') { 1724*60869b22SIan Rogers return DemangleInvalid; 1725*60869b22SIan Rogers } 1726*60869b22SIan Rogers size_t len = 0; 1727*60869b22SIan Rogers while (c >= '0' && c <= '9') { 1728*60869b22SIan Rogers size_t d = c - '0'; 1729*60869b22SIan Rogers if (len > SIZE_MAX / 10) { 1730*60869b22SIan Rogers return DemangleInvalid; 1731*60869b22SIan Rogers } 1732*60869b22SIan Rogers len *= 10; 1733*60869b22SIan Rogers if (len > SIZE_MAX - d) { 1734*60869b22SIan Rogers return DemangleInvalid; 1735*60869b22SIan Rogers } 1736*60869b22SIan Rogers len += d; 1737*60869b22SIan Rogers 1738*60869b22SIan Rogers chars++; 1739*60869b22SIan Rogers chars_len--; 1740*60869b22SIan Rogers if (chars_len == 0) { 1741*60869b22SIan Rogers return DemangleInvalid; 1742*60869b22SIan Rogers } 1743*60869b22SIan Rogers c = *chars; 1744*60869b22SIan Rogers } 1745*60869b22SIan Rogers 1746*60869b22SIan Rogers // Advance by the length 1747*60869b22SIan Rogers if (chars_len <= len) { 1748*60869b22SIan Rogers return DemangleInvalid; 1749*60869b22SIan Rogers } 1750*60869b22SIan Rogers chars += len; 1751*60869b22SIan Rogers chars_len -= len; 1752*60869b22SIan Rogers elements++; 1753*60869b22SIan Rogers } 1754*60869b22SIan Rogers *res = (struct demangle_legacy) { inner, inner_len, elements }; 1755*60869b22SIan Rogers *rest = chars + 1; 1756*60869b22SIan Rogers return DemangleOk; 1757*60869b22SIan Rogers } 1758*60869b22SIan Rogers 1759*60869b22SIan Rogers static bool is_rust_hash(const char *s, size_t len) { 1760*60869b22SIan Rogers if (len == 0 || s[0] != 'h') { 1761*60869b22SIan Rogers return false; 1762*60869b22SIan Rogers } 1763*60869b22SIan Rogers 1764*60869b22SIan Rogers for (size_t i = 1; i < len; i++) { 1765*60869b22SIan Rogers if (!((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >= 'A' && s[i] <= 'F'))) { 1766*60869b22SIan Rogers return false; 1767*60869b22SIan Rogers } 1768*60869b22SIan Rogers } 1769*60869b22SIan Rogers 1770*60869b22SIan Rogers return true; 1771*60869b22SIan Rogers } 1772*60869b22SIan Rogers 1773*60869b22SIan Rogers NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct demangle_legacy res, char *out, size_t len, bool alternate) 1774*60869b22SIan Rogers { 1775*60869b22SIan Rogers struct printer printer = { 1776*60869b22SIan Rogers // not actually using the parser part of the printer, just keeping it to share the format functions 1777*60869b22SIan Rogers DemangleOk, 1778*60869b22SIan Rogers { NULL }, 1779*60869b22SIan Rogers out, 1780*60869b22SIan Rogers len, 1781*60869b22SIan Rogers 0, 1782*60869b22SIan Rogers alternate 1783*60869b22SIan Rogers }; 1784*60869b22SIan Rogers const char *inner = res.mangled; 1785*60869b22SIan Rogers for (size_t element = 0; element < res.elements; element++) { 1786*60869b22SIan Rogers size_t i = 0; 1787*60869b22SIan Rogers const char *rest; 1788*60869b22SIan Rogers for (rest = inner; rest < res.mangled + res.mangled_len && *rest >= '0' && *rest <= '9'; rest++) { 1789*60869b22SIan Rogers i *= 10; 1790*60869b22SIan Rogers i += *rest - '0'; 1791*60869b22SIan Rogers } 1792*60869b22SIan Rogers if ((size_t)(res.mangled + res.mangled_len - rest) < i) { 1793*60869b22SIan Rogers // safety: shouldn't reach this place if the input string is validated. bail out. 1794*60869b22SIan Rogers // safety: we knwo rest <= res.mangled + res.mangled_len from the for-loop above 1795*60869b22SIan Rogers break; 1796*60869b22SIan Rogers } 1797*60869b22SIan Rogers 1798*60869b22SIan Rogers size_t len = i; 1799*60869b22SIan Rogers inner = rest + len; 1800*60869b22SIan Rogers 1801*60869b22SIan Rogers // From here on, inner contains a pointer to the next element, rest[:len] to the current one 1802*60869b22SIan Rogers if (alternate && element + 1 == res.elements && is_rust_hash(rest, i)) { 1803*60869b22SIan Rogers break; 1804*60869b22SIan Rogers } 1805*60869b22SIan Rogers if (element != 0) { 1806*60869b22SIan Rogers PRINT_STR(&printer, "::"); 1807*60869b22SIan Rogers } 1808*60869b22SIan Rogers 1809*60869b22SIan Rogers if (len >= 2 && !strncmp(rest, "_$", 2)) { 1810*60869b22SIan Rogers rest++; 1811*60869b22SIan Rogers len--; 1812*60869b22SIan Rogers } 1813*60869b22SIan Rogers 1814*60869b22SIan Rogers while (len > 0) { 1815*60869b22SIan Rogers if (rest[0] == '.') { 1816*60869b22SIan Rogers if (len >= 2 && rest[1] == '.') { 1817*60869b22SIan Rogers PRINT_STR(&printer, "::"); 1818*60869b22SIan Rogers rest += 2; 1819*60869b22SIan Rogers len -= 2; 1820*60869b22SIan Rogers } else { 1821*60869b22SIan Rogers PRINT_STR(&printer, "."); 1822*60869b22SIan Rogers rest += 1; 1823*60869b22SIan Rogers len -= 1; 1824*60869b22SIan Rogers } 1825*60869b22SIan Rogers } else if (rest[0] == '$') { 1826*60869b22SIan Rogers const char *escape = memchr(rest + 1, '$', len - 1); 1827*60869b22SIan Rogers if (escape == NULL) { 1828*60869b22SIan Rogers break; 1829*60869b22SIan Rogers } 1830*60869b22SIan Rogers const char *escape_start = rest + 1; 1831*60869b22SIan Rogers size_t escape_len = escape - (rest + 1); 1832*60869b22SIan Rogers 1833*60869b22SIan Rogers size_t next_len = len - (escape + 1 - rest); 1834*60869b22SIan Rogers const char *next_rest = escape + 1; 1835*60869b22SIan Rogers 1836*60869b22SIan Rogers char ch; 1837*60869b22SIan Rogers if ((escape_len == 2 && escape_start[0] == 'S' && escape_start[1] == 'P')) { 1838*60869b22SIan Rogers ch = '@'; 1839*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'B' && escape_start[1] == 'P')) { 1840*60869b22SIan Rogers ch = '*'; 1841*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'R' && escape_start[1] == 'F')) { 1842*60869b22SIan Rogers ch = '&'; 1843*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'L' && escape_start[1] == 'T')) { 1844*60869b22SIan Rogers ch = '<'; 1845*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'G' && escape_start[1] == 'T')) { 1846*60869b22SIan Rogers ch = '>'; 1847*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'L' && escape_start[1] == 'P')) { 1848*60869b22SIan Rogers ch = '('; 1849*60869b22SIan Rogers } else if ((escape_len == 2 && escape_start[0] == 'R' && escape_start[1] == 'P')) { 1850*60869b22SIan Rogers ch = ')'; 1851*60869b22SIan Rogers } else if ((escape_len == 1 && escape_start[0] == 'C')) { 1852*60869b22SIan Rogers ch = ','; 1853*60869b22SIan Rogers } else { 1854*60869b22SIan Rogers if (escape_len > 1 && escape_start[0] == 'u') { 1855*60869b22SIan Rogers escape_start++; 1856*60869b22SIan Rogers escape_len--; 1857*60869b22SIan Rogers uint64_t val; 1858*60869b22SIan Rogers if (try_parse_uint(escape_start, escape_len, &val) 1859*60869b22SIan Rogers && val < UINT32_MAX 1860*60869b22SIan Rogers && validate_char((uint32_t)val)) 1861*60869b22SIan Rogers { 1862*60869b22SIan Rogers if (!unicode_iscontrol(val)) { 1863*60869b22SIan Rogers uint8_t wchr[4]; 1864*60869b22SIan Rogers size_t wchr_len = code_to_utf8(wchr, (uint32_t)val); 1865*60869b22SIan Rogers PRINT(printer_print_buf(&printer, (const char*)wchr, wchr_len)); 1866*60869b22SIan Rogers len = next_len; 1867*60869b22SIan Rogers rest = next_rest; 1868*60869b22SIan Rogers continue; 1869*60869b22SIan Rogers } 1870*60869b22SIan Rogers } 1871*60869b22SIan Rogers } 1872*60869b22SIan Rogers break; // print the rest of this element raw 1873*60869b22SIan Rogers } 1874*60869b22SIan Rogers PRINT_CH(&printer, ch); 1875*60869b22SIan Rogers len = next_len; 1876*60869b22SIan Rogers rest = next_rest; 1877*60869b22SIan Rogers } else { 1878*60869b22SIan Rogers size_t j = 0; 1879*60869b22SIan Rogers for (;j < len && rest[j] != '$' && rest[j] != '.';j++); 1880*60869b22SIan Rogers if (j == len) { 1881*60869b22SIan Rogers break; 1882*60869b22SIan Rogers } 1883*60869b22SIan Rogers PRINT(printer_print_buf(&printer, rest, j)); 1884*60869b22SIan Rogers rest += j; 1885*60869b22SIan Rogers len -= j; 1886*60869b22SIan Rogers } 1887*60869b22SIan Rogers } 1888*60869b22SIan Rogers PRINT(printer_print_buf(&printer, rest, len)); 1889*60869b22SIan Rogers } 1890*60869b22SIan Rogers 1891*60869b22SIan Rogers if (printer.out_len < OVERFLOW_MARGIN) { 1892*60869b22SIan Rogers return OverflowOverflow; 1893*60869b22SIan Rogers } 1894*60869b22SIan Rogers *printer.out = '\0'; 1895*60869b22SIan Rogers return OverflowOk; 1896*60869b22SIan Rogers } 1897*60869b22SIan Rogers 1898*60869b22SIan Rogers static bool is_symbol_like(const char *s, size_t len) { 1899*60869b22SIan Rogers // rust-demangle definition of symbol like: control characters and space are not symbol-like, all else is 1900*60869b22SIan Rogers for (size_t i = 0; i < len; i++) { 1901*60869b22SIan Rogers char ch = s[i]; 1902*60869b22SIan Rogers if (!(ch >= 0x21 && ch <= 0x7e)) { 1903*60869b22SIan Rogers return false; 1904*60869b22SIan Rogers } 1905*60869b22SIan Rogers } 1906*60869b22SIan Rogers return true; 1907*60869b22SIan Rogers } 1908*60869b22SIan Rogers 1909*60869b22SIan Rogers void rust_demangle_demangle(const char *s, struct demangle *res) 1910*60869b22SIan Rogers { 1911*60869b22SIan Rogers // During ThinLTO LLVM may import and rename internal symbols, so strip out 1912*60869b22SIan Rogers // those endings first as they're one of the last manglings applied to symbol 1913*60869b22SIan Rogers // names. 1914*60869b22SIan Rogers const char *llvm = ".llvm."; 1915*60869b22SIan Rogers const char *found_llvm = strstr(s, llvm); 1916*60869b22SIan Rogers size_t s_len = strlen(s); 1917*60869b22SIan Rogers if (found_llvm) { 1918*60869b22SIan Rogers const char *all_hex_ptr = found_llvm + strlen(".llvm."); 1919*60869b22SIan Rogers bool all_hex = true; 1920*60869b22SIan Rogers for (;*all_hex_ptr;all_hex_ptr++) { 1921*60869b22SIan Rogers if (!(('0' <= *all_hex_ptr && *all_hex_ptr <= '9') || 1922*60869b22SIan Rogers ('A' <= *all_hex_ptr && *all_hex_ptr <= 'F') || 1923*60869b22SIan Rogers *all_hex_ptr == '@')) { 1924*60869b22SIan Rogers all_hex = false; 1925*60869b22SIan Rogers break; 1926*60869b22SIan Rogers } 1927*60869b22SIan Rogers } 1928*60869b22SIan Rogers 1929*60869b22SIan Rogers if (all_hex) { 1930*60869b22SIan Rogers s_len = found_llvm - s; 1931*60869b22SIan Rogers } 1932*60869b22SIan Rogers } 1933*60869b22SIan Rogers 1934*60869b22SIan Rogers const char *suffix; 1935*60869b22SIan Rogers struct demangle_legacy legacy; 1936*60869b22SIan Rogers demangle_status st = rust_demangle_legacy_demangle(s, s_len, &legacy, &suffix); 1937*60869b22SIan Rogers if (st == DemangleOk) { 1938*60869b22SIan Rogers *res = (struct demangle) { 1939*60869b22SIan Rogers .style=DemangleStyleLegacy, 1940*60869b22SIan Rogers .mangled=legacy.mangled, 1941*60869b22SIan Rogers .mangled_len=legacy.mangled_len, 1942*60869b22SIan Rogers .elements=legacy.elements, 1943*60869b22SIan Rogers .original=s, 1944*60869b22SIan Rogers .original_len=s_len, 1945*60869b22SIan Rogers .suffix=suffix, 1946*60869b22SIan Rogers .suffix_len=s_len - (suffix - s), 1947*60869b22SIan Rogers }; 1948*60869b22SIan Rogers } else { 1949*60869b22SIan Rogers struct demangle_v0 v0; 1950*60869b22SIan Rogers st = rust_demangle_v0_demangle(s, s_len, &v0, &suffix); 1951*60869b22SIan Rogers if (st == DemangleOk) { 1952*60869b22SIan Rogers *res = (struct demangle) { 1953*60869b22SIan Rogers .style=DemangleStyleV0, 1954*60869b22SIan Rogers .mangled=v0.mangled, 1955*60869b22SIan Rogers .mangled_len=v0.mangled_len, 1956*60869b22SIan Rogers .elements=0, 1957*60869b22SIan Rogers .original=s, 1958*60869b22SIan Rogers .original_len=s_len, 1959*60869b22SIan Rogers .suffix=suffix, 1960*60869b22SIan Rogers .suffix_len=s_len - (suffix - s), 1961*60869b22SIan Rogers }; 1962*60869b22SIan Rogers } else { 1963*60869b22SIan Rogers *res = (struct demangle) { 1964*60869b22SIan Rogers .style=DemangleStyleUnknown, 1965*60869b22SIan Rogers .mangled=NULL, 1966*60869b22SIan Rogers .mangled_len=0, 1967*60869b22SIan Rogers .elements=0, 1968*60869b22SIan Rogers .original=s, 1969*60869b22SIan Rogers .original_len=s_len, 1970*60869b22SIan Rogers .suffix=s, 1971*60869b22SIan Rogers .suffix_len=0, 1972*60869b22SIan Rogers }; 1973*60869b22SIan Rogers } 1974*60869b22SIan Rogers } 1975*60869b22SIan Rogers 1976*60869b22SIan Rogers // Output like LLVM IR adds extra period-delimited words. See if 1977*60869b22SIan Rogers // we are in that case and save the trailing words if so. 1978*60869b22SIan Rogers if (res->suffix_len) { 1979*60869b22SIan Rogers if (res->suffix[0] == '.' && is_symbol_like(res->suffix, res->suffix_len)) { 1980*60869b22SIan Rogers // Keep the suffix 1981*60869b22SIan Rogers } else { 1982*60869b22SIan Rogers // Reset the suffix and invalidate the demangling 1983*60869b22SIan Rogers res->style = DemangleStyleUnknown; 1984*60869b22SIan Rogers res->suffix_len = 0; 1985*60869b22SIan Rogers } 1986*60869b22SIan Rogers } 1987*60869b22SIan Rogers } 1988*60869b22SIan Rogers 1989*60869b22SIan Rogers bool rust_demangle_is_known(struct demangle *res) { 1990*60869b22SIan Rogers return res->style != DemangleStyleUnknown; 1991*60869b22SIan Rogers } 1992*60869b22SIan Rogers 1993*60869b22SIan Rogers overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate) { 1994*60869b22SIan Rogers size_t original_len = res->original_len; 1995*60869b22SIan Rogers size_t out_len; 1996*60869b22SIan Rogers switch (res->style) { 1997*60869b22SIan Rogers case DemangleStyleUnknown: 1998*60869b22SIan Rogers if (len < original_len) { 1999*60869b22SIan Rogers return OverflowOverflow; 2000*60869b22SIan Rogers } else { 2001*60869b22SIan Rogers memcpy(out, res->original, original_len); 2002*60869b22SIan Rogers out += original_len; 2003*60869b22SIan Rogers len -= original_len; 2004*60869b22SIan Rogers break; 2005*60869b22SIan Rogers } 2006*60869b22SIan Rogers break; 2007*60869b22SIan Rogers case DemangleStyleLegacy: { 2008*60869b22SIan Rogers struct demangle_legacy legacy = { 2009*60869b22SIan Rogers res->mangled, 2010*60869b22SIan Rogers res->mangled_len, 2011*60869b22SIan Rogers res->elements 2012*60869b22SIan Rogers }; 2013*60869b22SIan Rogers if (rust_demangle_legacy_display_demangle(legacy, out, len, alternate) == OverflowOverflow) { 2014*60869b22SIan Rogers return OverflowOverflow; 2015*60869b22SIan Rogers } 2016*60869b22SIan Rogers out_len = strlen(out); 2017*60869b22SIan Rogers out += out_len; 2018*60869b22SIan Rogers len -= out_len; 2019*60869b22SIan Rogers break; 2020*60869b22SIan Rogers } 2021*60869b22SIan Rogers case DemangleStyleV0: { 2022*60869b22SIan Rogers struct demangle_v0 v0 = { 2023*60869b22SIan Rogers res->mangled, 2024*60869b22SIan Rogers res->mangled_len 2025*60869b22SIan Rogers }; 2026*60869b22SIan Rogers if (rust_demangle_v0_display_demangle(v0, out, len, alternate) == OverflowOverflow) { 2027*60869b22SIan Rogers return OverflowOverflow; 2028*60869b22SIan Rogers } 2029*60869b22SIan Rogers out_len = strlen(out); 2030*60869b22SIan Rogers out += out_len; 2031*60869b22SIan Rogers len -= out_len; 2032*60869b22SIan Rogers break; 2033*60869b22SIan Rogers } 2034*60869b22SIan Rogers } 2035*60869b22SIan Rogers size_t suffix_len = res->suffix_len; 2036*60869b22SIan Rogers if (len < suffix_len || len - suffix_len < OVERFLOW_MARGIN) { 2037*60869b22SIan Rogers return OverflowOverflow; 2038*60869b22SIan Rogers } 2039*60869b22SIan Rogers memcpy(out, res->suffix, suffix_len); 2040*60869b22SIan Rogers out[suffix_len] = 0; 2041*60869b22SIan Rogers return OverflowOk; 2042*60869b22SIan Rogers } 2043