Print this page
Rich's feedback
   1 /*
   2  * Ported from LLVM's libcxxabi trunk/src/cxa_demangle.cpp
   3  * LICENSE.TXT contents is available as ../THIRDPARTYLICENSE
   4  *
   5  *                     The LLVM Compiler Infrastructure
   6  *
   7  * This file is dual licensed under the MIT and the University of Illinois Open
   8  * Source Licenses. See LICENSE.TXT for details.
   9  *
  10  */
  11 
  12 /*
  13  * Copyright 2017 Jason King.
  14  */
  15 #include <ctype.h>
  16 #include <errno.h>
  17 #include <locale.h>

  18 #include <string.h>
  19 #include <setjmp.h>
  20 #include <stdio.h>
  21 #include <stdlib.h>
  22 #include <sys/isa_defs.h>
  23 #include <sys/debug.h>
  24 #include "sysdemangle.h"
  25 #include "sysdemangle_int.h"
  26 #include "cxx.h"
  27 
  28 #ifndef ARRAY_SIZE
  29 #define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
  30 #endif
  31 
  32 #define CPP_QUAL_CONST          (1U)
  33 #define CPP_QUAL_VOLATILE       (2U)
  34 #define CPP_QUAL_RESTRICT       (4U)
  35 
  36 typedef struct cpp_db_s {
  37         sysdem_ops_t    *cpp_ops;
  38         jmp_buf         cpp_jmp;
  39         name_t          cpp_name;
  40         sub_t           cpp_subs;
  41         templ_t         cpp_templ;
  42         unsigned        cpp_cv;
  43         unsigned        cpp_ref;
  44         unsigned        cpp_depth;
  45         boolean_t       cpp_parsed_ctor_dtor_cv;
  46         boolean_t       cpp_tag_templates;
  47         boolean_t       cpp_fix_forward_references;
  48         boolean_t       cpp_try_to_parse_template_args;
  49         locale_t        cpp_loc;
  50 } cpp_db_t;
  51 
  52 #define CK(x)                                           \
  53         do {                                            \
  54                 if (!(x))                               \
  55                         longjmp(db->cpp_jmp, 1);     \


  56         } while (0)
  57 
  58 #define TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l))
  59 #define RLEN(f, l) ((size_t)((l) - (f)))
  60 #define NAMT(db, n) (nlen(db) - n)
  61 
  62 static inline boolean_t is_xdigit(int);
  63 
  64 static boolean_t nempty(cpp_db_t *);
  65 static size_t nlen(cpp_db_t *);
  66 static void nadd_l(cpp_db_t *, const char *, size_t);
  67 static void njoin(cpp_db_t *, size_t, const char *);
  68 static void nfmt(cpp_db_t *, const char *, const char *);
  69 
  70 static void save_top(cpp_db_t *, size_t);
  71 static void sub(cpp_db_t *, size_t);
  72 
  73 static boolean_t tempty(const cpp_db_t *);
  74 static size_t ttlen(const cpp_db_t *);
  75 


 198         if (errno != 0)
 199                 goto done;
 200 
 201         if (nempty(&db)) {
 202                 errno = EINVAL;
 203                 goto done;
 204         }
 205 
 206         njoin(&db, 1, "");
 207 
 208         if (nlen(&db) > 0) {
 209                 str_t *s = TOP_L(&db);
 210                 result = zalloc(ops, s->str_len + 1);
 211                 if (result == NULL)
 212                         goto done;
 213 
 214                 (void) memcpy(result, s->str_s, s->str_len);
 215         }
 216 
 217 done:
 218         if (getenv("DEMANGLE_DEBUG") != NULL)
 219                 dump(&db, stdout);
 220 
 221         db_fini(&db);
 222         return (result);
 223 }
 224 
 225 static void
 226 demangle(const char *first, const char *last, cpp_db_t *db)
 227 {
 228         const char *t = NULL;
 229 
 230         if (first >= last) {
 231                 errno = EINVAL;
 232                 return;
 233         }
 234 
 235         if (first[0] != '_') {
 236                 t = parse_type(first, last, db);
 237                 if (t == first) {
 238                         errno = EINVAL;


 272 
 273 static const char *
 274 parse_dot_suffix(const char *first, const char *last, cpp_db_t *db)
 275 {
 276         VERIFY3P(first, <=, last);
 277 
 278         if (first == last || first[0] != '.')
 279                 return (first);
 280 
 281         if (nempty(db))
 282                 return (first);
 283 
 284         nadd_l(db, first, RLEN(first, last));
 285         nfmt(db, " ({0})", NULL);
 286 
 287         return (last);
 288 }
 289 
 290 /*
 291  * _block_invoke
 292  * _block_invoke<digit>+  XXX: should it be <digit>* ?
 293  * _block_invoke_<digit>+
 294  */
 295 static const char *
 296 parse_block_invoke(const char *first, const char *last, cpp_db_t *db)
 297 {
 298         VERIFY3P(first, <=, last);
 299 
 300         if (last - first < 13)
 301                 return (first);
 302 
 303         const char test[] = "_block_invoke";
 304         const char *t = first;
 305 
 306         if (strncmp(first, test, sizeof (test) - 1) != 0)
 307                 return (first);
 308 
 309         t += sizeof (test);
 310         if (t == last)
 311                 goto done;
 312 


 361                 goto fail;
 362 
 363         cv = db->cpp_cv;
 364         ref = db->cpp_ref;
 365 
 366         if (t == last || t[0] == 'E' || t[0] == '.')
 367                 goto done;
 368 
 369         db->cpp_tag_templates = B_FALSE;
 370         if (nempty(db) || str_length(TOP_L(db)) == 0)
 371                 goto fail;
 372 
 373         if (!db->cpp_parsed_ctor_dtor_cv && ends_with_template_args) {
 374                 t2 = parse_type(t, last, db);
 375                 if (t2 == t || nlen(db) < 2)
 376                         goto fail;
 377 
 378                 str_pair_t *sp = name_top(&db->cpp_name);
 379 
 380                 if (str_length(&sp->strp_r) == 0)
 381                         str_append(&sp->strp_l, " ", 1);
 382 
 383                 nfmt(db, "{0:L}{1:L}", "{1:R}{0:R}");
 384                 t = t2;
 385         }
 386 
 387         if (t == last || nempty(db))
 388                 goto fail;
 389 
 390         size_t n = nlen(db);
 391 
 392         if (t[0] == 'v') {
 393                 t++;
 394         } else {
 395 
 396                 /*CONSTCOND*/
 397                 while (1) {
 398                         t2 = parse_type(t, last, db);
 399                         if (t2 == t || t == last)
 400                                 break;
 401 
 402                         t = t2;
 403                 }
 404         }
 405 
 406         /*
 407          * a bit of a hack, but a template substitution can apparently be
 408          * an empty string at the end of an argument list, so avoid
 409          * <...., >
 410          */
 411         if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0)
 412                 name_pop(&db->cpp_name, NULL);
 413 
 414         njoin(db, NAMT(db, n), ", ");
 415         nfmt(db, "({0})", NULL);
 416 
 417         str_t *s = TOP_L(db);


1524         if (t1 == first + 2)
1525                 return (first);
1526 
1527         const char *t2 = parse_expression(t1, last, db);
1528         if (t2 == t1 || NAMT(db, n) != 2)
1529                 return (first);
1530 
1531         nfmt(db, "{1}->{0}", NULL);
1532         return (t2);
1533 }
1534 
1535 /* wrap value in () when necessary */
1536 static void
1537 paren(str_pair_t *sp)
1538 {
1539         str_t *l = &sp->strp_l;
1540         str_t *r = &sp->strp_r;
1541 
1542         if (str_length(r) > 1 &&
1543             r->str_s[0] == ' ' && r->str_s[1] == '[') {
1544                 str_append(l, " (", 2);
1545                 str_insert(r, 0, ")", 1);
1546         } else if (str_length(r) > 0 && r->str_s[0] == '(') {
1547                 str_append(l, "(", 1);
1548                 str_insert(r, 0, ")", 1);
1549         }
1550 }
1551 
1552 /* BEGIN CSTYLED */
1553 /*
1554  * <type> ::= <builtin-type>
1555  *        ::= <function-type>
1556  *        ::= <class-enum-type>
1557  *        ::= <array-type>
1558  *        ::= <pointer-to-member-type>
1559  *        ::= <template-param>
1560  *        ::= <template-template-param> <template-args>
1561  *        ::= <decltype>
1562  *        ::= <substitution>
1563  *        ::= <CV-qualifiers> <type>
1564  *        ::= P <type>        # pointer-to
1565  *        ::= R <type>        # reference-to
1566  *        ::= O <type>        # rvalue reference-to (C++0x)
1567  *        ::= C <type>        # complex pair (C 2000)
1568  *        ::= G <type>        # imaginary (C 2000)


1596         size_t n = nlen(db);
1597         size_t amt = 0;
1598 
1599         t = parse_builtin_type(first, last, db);
1600         if (t != first)
1601                 return (t);
1602 
1603         switch (first[0]) {
1604         case 'A':
1605                 t = parse_array_type(first, last, db);
1606                 if (t == first || NAMT(db, n) == 0)
1607                         return (first);
1608                 save_top(db, 1);
1609                 return (t);
1610 
1611         case 'C':
1612                 t = parse_type(first + 1, last, db);
1613                 if (t == first + 1 || NAMT(db, n) == 0)
1614                         return (first);
1615 
1616                 str_append(TOP_L(db), " complex", 8);
1617                 save_top(db, 1);
1618                 return (t);
1619 
1620         case 'F':
1621                 t = parse_function_type(first, last, db);
1622                 if (t == first || NAMT(db, n) == 0)
1623                         return (first);
1624                 save_top(db, 1);
1625                 return (t);
1626 
1627         case 'G':
1628                 t = parse_type(first + 1, last, db);
1629                 if (t == first + 1 || NAMT(db, n) == 0)
1630                         return (first);
1631 
1632                 str_append(TOP_L(db), " imaginary", 10);
1633                 save_top(db, 1);
1634                 return (t);
1635 
1636         case 'M':
1637                 t = parse_pointer_to_member_type(first, last, db);
1638                 if (t == first || NAMT(db, n) == 0)
1639                         return (first);
1640                 save_top(db, 1);
1641                 return (t);
1642 
1643         case 'O':
1644                 t = parse_type(first + 1, last, db);
1645                 amt = NAMT(db, n);
1646                 if (t == first + 1 || amt == 0)
1647                         return (first);
1648 
1649                 sp = name_at(&db->cpp_name, amt - 1);
1650                 for (size_t i = 0; i < amt; i++, sp++) {
1651                         paren(sp);
1652                         if (str_pair_len(sp) > 0)
1653                                 str_append(&sp->strp_l, "&&", 2);
1654                 }
1655 
1656                 save_top(db, amt);
1657                 return (t);
1658 
1659         case 'P':
1660                 t = parse_type(first + 1, last, db);
1661                 amt = NAMT(db, n);
1662                 if (t == first + 1 || amt == 0)
1663                         return (first);
1664 
1665                 sp = name_at(&db->cpp_name, amt - 1);
1666                 for (size_t i = 0; i < amt; i++, sp++) {
1667                         str_t *l = &sp->strp_l;
1668 
1669                         if (str_pair_len(sp) == 0)
1670                                 continue;
1671 
1672                         paren(sp);
1673                         if (first[1] != 'U' ||
1674                             strncmp(l->str_s, "objc_object<", 12) != 0) {
1675                                 str_append(l, "*", 1);
1676                         } else {
1677                                 str_erase(l, 0, 11);
1678                                 str_insert(l, 0, "id", 2);
1679                         }
1680                 }
1681                 save_top(db, amt);
1682                 return (t);
1683 
1684         case 'R':
1685                 t = parse_type(first + 1, last, db);
1686                 amt = NAMT(db, n);
1687                 if (t == first + 1 || amt == 0)
1688                         return (first);
1689 
1690                 sp = name_at(&db->cpp_name, amt - 1);
1691                 for (size_t i = 0; i < amt; i++, sp++) {
1692                         if (str_length(&sp->strp_l) == 0 &&
1693                             str_length(&sp->strp_r) == 0)
1694                                 continue;
1695 
1696                         paren(sp);
1697                         str_append(&sp->strp_l, "&", 1);
1698                 }
1699 
1700                 save_top(db, amt);
1701                 return (t);
1702 
1703         case 'T':
1704                 t = parse_template_param(first, last, db);
1705                 if (t == first)
1706                         return (first);
1707 
1708                 amt = NAMT(db, n);
1709                 save_top(db, amt);
1710                 if (!db->cpp_try_to_parse_template_args || amt != 1)
1711                         return (t);
1712 
1713                 t1 = parse_template_args(t, last, db);
1714                 if (t1 == t)
1715                         return (t);
1716 
1717                 nfmt(db, "{1:L}{0}", "{1:R}");


1859         t1 = parse_type(t, last, db);
1860         size_t amt = NAMT(db, n);
1861         if (t == t1 || amt == 0)
1862                 return (first);
1863 
1864         if (is_func)
1865                 sub_pop(&db->cpp_subs);
1866 
1867         str_pair_t *sp = name_at(&db->cpp_name, amt - 1);
1868 
1869         for (size_t i = 0; i < amt; i++, sp++) {
1870                 str_t *s = NULL;
1871 
1872                 if (!is_func) {
1873                         s = &sp->strp_l;
1874 
1875                         if (str_length(s) == 0)
1876                                 continue;
1877 
1878                         if (cv & 1)
1879                                 str_append(s, " const", 6);
1880                         if (cv & 2)
1881                                 str_append(s, " volatile", 9);
1882                         if (cv & 4)
1883                                 str_append(s, " restrict", 9);
1884 
1885                         continue;
1886                 }
1887 
1888                 s = &sp->strp_r;
1889                 size_t pos = str_length(s);
1890 
1891                 if (pos > 0 && s->str_s[pos - 1] == '&') {
1892                         pos--;
1893                         if (s->str_s[pos - 1] == '&')
1894                                 pos--;
1895                 }
1896 
1897                 if (cv & 1) {
1898                         str_insert(s, pos, " const", 6);
1899                         pos += 6;
1900                 }
1901                 if (cv & 2) {
1902                         str_insert(s, pos, " volatile", 9);
1903                         pos += 9;
1904                 }
1905                 if (cv & 4) {
1906                         str_insert(s, pos, " restrict", 9);
1907                 }
1908         }
1909 
1910         save_top(db, amt);
1911         return (t1);
1912 }
1913 
1914 /*
1915  * at <type>              # alignof (a type)
1916  * az <expression>        # alignof (a expression)
1917  */
1918 static const char *
1919 parse_alignof(const char *first, const char *last, cpp_db_t *db)
1920 {
1921         VERIFY3P(first, <=, last);
1922 
1923         if (last - first < 2)
1924                 return (first);
1925 
1926         const char *(*fn)(const char *, const char *, cpp_db_t *);


2615         switch (first[0]) {
2616         case 'C':
2617                 switch (first[1]) {
2618                 case '1':
2619                 case '2':
2620                 case '3':
2621                 case '5':
2622                         basename(db);
2623                         break;
2624                 default:
2625                         return (first);
2626                 }
2627                 break;
2628         case 'D':
2629                 switch (first[1]) {
2630                 case '0':
2631                 case '1':
2632                 case '2':
2633                 case '5':
2634                         basename(db);
2635                         str_insert(TOP_L(db), 0, "~", 1);
2636                         break;
2637                 default:
2638                         return (first);
2639                 }
2640                 break;
2641         default:
2642                 return (first);
2643         }
2644 
2645         db->cpp_parsed_ctor_dtor_cv = B_TRUE;
2646         return (first + 2);
2647 }
2648 
2649 static const char *
2650 parse_integer_literal(const char *first, const char *last, const char *fmt,
2651     cpp_db_t *db)
2652 {
2653         VERIFY3P(first, <=, last);
2654 
2655         const char *t = parse_number(first, last, db->cpp_loc);


2772         switch (first[0]) {
2773         case 'f':
2774                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2775                     conv.f.v);
2776                 break;
2777         case 'd':
2778                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2779                     conv.d.v);
2780                 break;
2781         case 'e':
2782                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2783                     conv.ld.v);
2784         }
2785 
2786         if (n >= fd->max_demangled_size || n <= 0) {
2787                 str_fini(&num);
2788                 return (first);
2789         }
2790 
2791         num.str_len = n;
2792         name_add_str(&db->cpp_name, &num, NULL);
2793 
2794         return (t + 1);
2795 }
2796 
2797 /*
2798  * <expr-primary> ::= L <type> <value number> E       # integer literal
2799  *                ::= L <type> <value float> E      # floating literal
2800  *                ::= L <string type> E           # string literal
2801  *                ::= L <nullptr type> E  # nullptr literal (i.e., "LDnE")
2802  *
2803  *                ::= L <type> <real-part float> _ <imag-part float> E
2804  *                                              # complex floating point
2805  *                                              # literal (C 2000)
2806  *
2807  *                ::= L <mangled-name> E  # external name
2808  */
2809 static struct {
2810         int             c;
2811         const char      *fmt;
2812 } int_lits[] = {


3386                 if (t1[0] != '_')
3387                         return (first);
3388 
3389                 t = t1;
3390         } else {
3391                 nadd_l(db, "", 0);
3392         }
3393 
3394         VERIFY3U(t[0], ==, '_');
3395 
3396         t1 = parse_type(t + 1, last, db);
3397         if (t1 == t + 1 || NAMT(db, n) != 2)
3398                 return (first);
3399 
3400         /*
3401          * if we have  " [xxx]" already, want new result to be
3402          * " [yyy][xxx]"
3403          */
3404         str_t *r = &name_top(&db->cpp_name)->strp_r;
3405         if (r->str_len > 1 && r->str_s[0] == ' ' && r->str_s[1] == '[')
3406                 str_erase(r, 0, 1);
3407 
3408         nfmt(db, "{0:L}", " [{1}]{0:R}");
3409         return (t1);
3410 }
3411 
3412 /* <pointer-to-member-type> ::= M <class type> <member type> */
3413 static const char *
3414 parse_pointer_to_member_type(const char *first, const char *last, cpp_db_t *db)
3415 {
3416         VERIFY3P(first, <=, last);
3417 
3418         if (last - first < 3)
3419                 return (first);
3420 
3421         VERIFY3U(first[0], ==, 'M');
3422 
3423         const char *t1 = first + 1;
3424         const char *t2 = NULL;
3425         size_t n = nlen(db);
3426 


3468                 return (first);
3469 
3470         const char *t = first;
3471         const char *t2 = NULL;
3472         boolean_t global = B_FALSE;
3473         size_t n;
3474 
3475         if (t[0] == 'g' && t[1] == 's') {
3476                 global = B_TRUE;
3477                 t += 2;
3478         }
3479         if (t == last)
3480                 return (first);
3481 
3482         t2 = parse_base_unresolved_name(t, last, db);
3483         if (t != t2) {
3484                 if (global) {
3485                         if (nempty(db))
3486                                 return (first);
3487 
3488                         str_insert(TOP_L(db), 0, "::", 2);
3489                 }
3490                 return (t2);
3491         }
3492 
3493         if (t[0] != 's' || t[1] != 'r' || last - t < 2)
3494                 return (first);
3495 
3496         n = nlen(db);
3497         if (t[2] == 'N') {
3498                 t += 3;
3499                 t2 = parse_unresolved_type(t, last, db);
3500                 if (t2 == t || t2 == last)
3501                         return (first);
3502                 t = t2;
3503 
3504                 t2 = parse_template_args(t, last, db);
3505                 if (t2 != t) {
3506                         if (NAMT(db, n) < 2 || t2 == last)
3507                                 return (first);
3508 


   1 /*
   2  * Ported from LLVM's libcxxabi trunk/src/cxa_demangle.cpp
   3  * LICENSE.TXT contents is available as ../THIRDPARTYLICENSE
   4  *
   5  *                     The LLVM Compiler Infrastructure
   6  *
   7  * This file is dual licensed under the MIT and the University of Illinois Open
   8  * Source Licenses. See LICENSE.TXT for details.
   9  *
  10  */
  11 
  12 /*
  13  * Copyright 2018 Jason King.
  14  */
  15 #include <ctype.h>
  16 #include <errno.h>
  17 #include <locale.h>
  18 #include <note.h>
  19 #include <string.h>
  20 #include <setjmp.h>
  21 #include <stdio.h>
  22 #include <stdlib.h>
  23 #include <sys/isa_defs.h>
  24 #include <sys/debug.h>
  25 #include "demangle-sys.h"
  26 #include "demangle_int.h"
  27 #include "cxx.h"
  28 
  29 #ifndef ARRAY_SIZE
  30 #define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
  31 #endif
  32 
  33 #define CPP_QUAL_CONST          (1U)
  34 #define CPP_QUAL_VOLATILE       (2U)
  35 #define CPP_QUAL_RESTRICT       (4U)
  36 
  37 typedef struct cpp_db_s {
  38         sysdem_ops_t    *cpp_ops;
  39         jmp_buf         cpp_jmp;
  40         name_t          cpp_name;
  41         sub_t           cpp_subs;
  42         templ_t         cpp_templ;
  43         unsigned        cpp_cv;
  44         unsigned        cpp_ref;
  45         unsigned        cpp_depth;
  46         boolean_t       cpp_parsed_ctor_dtor_cv;
  47         boolean_t       cpp_tag_templates;
  48         boolean_t       cpp_fix_forward_references;
  49         boolean_t       cpp_try_to_parse_template_args;
  50         locale_t        cpp_loc;
  51 } cpp_db_t;
  52 
  53 #define CK(x)                                           \
  54         do {                                            \
  55                 if (!(x)) {                             \
  56                         longjmp(db->cpp_jmp, 1);     \
  57                 }                                       \
  58         NOTE(CONSTCOND)                                 \
  59         } while (0)
  60 
  61 #define TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l))
  62 #define RLEN(f, l) ((size_t)((l) - (f)))
  63 #define NAMT(db, n) (nlen(db) - n)
  64 
  65 static inline boolean_t is_xdigit(int);
  66 
  67 static boolean_t nempty(cpp_db_t *);
  68 static size_t nlen(cpp_db_t *);
  69 static void nadd_l(cpp_db_t *, const char *, size_t);
  70 static void njoin(cpp_db_t *, size_t, const char *);
  71 static void nfmt(cpp_db_t *, const char *, const char *);
  72 
  73 static void save_top(cpp_db_t *, size_t);
  74 static void sub(cpp_db_t *, size_t);
  75 
  76 static boolean_t tempty(const cpp_db_t *);
  77 static size_t ttlen(const cpp_db_t *);
  78 


 201         if (errno != 0)
 202                 goto done;
 203 
 204         if (nempty(&db)) {
 205                 errno = EINVAL;
 206                 goto done;
 207         }
 208 
 209         njoin(&db, 1, "");
 210 
 211         if (nlen(&db) > 0) {
 212                 str_t *s = TOP_L(&db);
 213                 result = zalloc(ops, s->str_len + 1);
 214                 if (result == NULL)
 215                         goto done;
 216 
 217                 (void) memcpy(result, s->str_s, s->str_len);
 218         }
 219 
 220 done:
 221         if (demangle_debug)
 222                 dump(&db, stdout);
 223 
 224         db_fini(&db);
 225         return (result);
 226 }
 227 
 228 static void
 229 demangle(const char *first, const char *last, cpp_db_t *db)
 230 {
 231         const char *t = NULL;
 232 
 233         if (first >= last) {
 234                 errno = EINVAL;
 235                 return;
 236         }
 237 
 238         if (first[0] != '_') {
 239                 t = parse_type(first, last, db);
 240                 if (t == first) {
 241                         errno = EINVAL;


 275 
 276 static const char *
 277 parse_dot_suffix(const char *first, const char *last, cpp_db_t *db)
 278 {
 279         VERIFY3P(first, <=, last);
 280 
 281         if (first == last || first[0] != '.')
 282                 return (first);
 283 
 284         if (nempty(db))
 285                 return (first);
 286 
 287         nadd_l(db, first, RLEN(first, last));
 288         nfmt(db, " ({0})", NULL);
 289 
 290         return (last);
 291 }
 292 
 293 /*
 294  * _block_invoke
 295  * _block_invoke<digit>*
 296  * _block_invoke_<digit>+
 297  */
 298 static const char *
 299 parse_block_invoke(const char *first, const char *last, cpp_db_t *db)
 300 {
 301         VERIFY3P(first, <=, last);
 302 
 303         if (last - first < 13)
 304                 return (first);
 305 
 306         const char test[] = "_block_invoke";
 307         const char *t = first;
 308 
 309         if (strncmp(first, test, sizeof (test) - 1) != 0)
 310                 return (first);
 311 
 312         t += sizeof (test);
 313         if (t == last)
 314                 goto done;
 315 


 364                 goto fail;
 365 
 366         cv = db->cpp_cv;
 367         ref = db->cpp_ref;
 368 
 369         if (t == last || t[0] == 'E' || t[0] == '.')
 370                 goto done;
 371 
 372         db->cpp_tag_templates = B_FALSE;
 373         if (nempty(db) || str_length(TOP_L(db)) == 0)
 374                 goto fail;
 375 
 376         if (!db->cpp_parsed_ctor_dtor_cv && ends_with_template_args) {
 377                 t2 = parse_type(t, last, db);
 378                 if (t2 == t || nlen(db) < 2)
 379                         goto fail;
 380 
 381                 str_pair_t *sp = name_top(&db->cpp_name);
 382 
 383                 if (str_length(&sp->strp_r) == 0)
 384                         (void) str_append(&sp->strp_l, " ", 1);
 385 
 386                 nfmt(db, "{0:L}{1:L}", "{1:R}{0:R}");
 387                 t = t2;
 388         }
 389 
 390         if (t == last || nempty(db))
 391                 goto fail;
 392 
 393         size_t n = nlen(db);
 394 
 395         if (t[0] == 'v') {
 396                 t++;
 397         } else {
 398                 for (;;) {


 399                         t2 = parse_type(t, last, db);
 400                         if (t2 == t || t == last)
 401                                 break;
 402 
 403                         t = t2;
 404                 }
 405         }
 406 
 407         /*
 408          * a bit of a hack, but a template substitution can apparently be
 409          * an empty string at the end of an argument list, so avoid
 410          * <...., >
 411          */
 412         if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0)
 413                 name_pop(&db->cpp_name, NULL);
 414 
 415         njoin(db, NAMT(db, n), ", ");
 416         nfmt(db, "({0})", NULL);
 417 
 418         str_t *s = TOP_L(db);


1525         if (t1 == first + 2)
1526                 return (first);
1527 
1528         const char *t2 = parse_expression(t1, last, db);
1529         if (t2 == t1 || NAMT(db, n) != 2)
1530                 return (first);
1531 
1532         nfmt(db, "{1}->{0}", NULL);
1533         return (t2);
1534 }
1535 
1536 /* wrap value in () when necessary */
1537 static void
1538 paren(str_pair_t *sp)
1539 {
1540         str_t *l = &sp->strp_l;
1541         str_t *r = &sp->strp_r;
1542 
1543         if (str_length(r) > 1 &&
1544             r->str_s[0] == ' ' && r->str_s[1] == '[') {
1545                 (void) str_append(l, " (", 2);
1546                 (void) str_insert(r, 0, ")", 1);
1547         } else if (str_length(r) > 0 && r->str_s[0] == '(') {
1548                 (void) str_append(l, "(", 1);
1549                 (void) str_insert(r, 0, ")", 1);
1550         }
1551 }
1552 
1553 /* BEGIN CSTYLED */
1554 /*
1555  * <type> ::= <builtin-type>
1556  *        ::= <function-type>
1557  *        ::= <class-enum-type>
1558  *        ::= <array-type>
1559  *        ::= <pointer-to-member-type>
1560  *        ::= <template-param>
1561  *        ::= <template-template-param> <template-args>
1562  *        ::= <decltype>
1563  *        ::= <substitution>
1564  *        ::= <CV-qualifiers> <type>
1565  *        ::= P <type>        # pointer-to
1566  *        ::= R <type>        # reference-to
1567  *        ::= O <type>        # rvalue reference-to (C++0x)
1568  *        ::= C <type>        # complex pair (C 2000)
1569  *        ::= G <type>        # imaginary (C 2000)


1597         size_t n = nlen(db);
1598         size_t amt = 0;
1599 
1600         t = parse_builtin_type(first, last, db);
1601         if (t != first)
1602                 return (t);
1603 
1604         switch (first[0]) {
1605         case 'A':
1606                 t = parse_array_type(first, last, db);
1607                 if (t == first || NAMT(db, n) == 0)
1608                         return (first);
1609                 save_top(db, 1);
1610                 return (t);
1611 
1612         case 'C':
1613                 t = parse_type(first + 1, last, db);
1614                 if (t == first + 1 || NAMT(db, n) == 0)
1615                         return (first);
1616 
1617                 (void) str_append(TOP_L(db), " complex", 8);
1618                 save_top(db, 1);
1619                 return (t);
1620 
1621         case 'F':
1622                 t = parse_function_type(first, last, db);
1623                 if (t == first || NAMT(db, n) == 0)
1624                         return (first);
1625                 save_top(db, 1);
1626                 return (t);
1627 
1628         case 'G':
1629                 t = parse_type(first + 1, last, db);
1630                 if (t == first + 1 || NAMT(db, n) == 0)
1631                         return (first);
1632 
1633                 (void) str_append(TOP_L(db), " imaginary", 10);
1634                 save_top(db, 1);
1635                 return (t);
1636 
1637         case 'M':
1638                 t = parse_pointer_to_member_type(first, last, db);
1639                 if (t == first || NAMT(db, n) == 0)
1640                         return (first);
1641                 save_top(db, 1);
1642                 return (t);
1643 
1644         case 'O':
1645                 t = parse_type(first + 1, last, db);
1646                 amt = NAMT(db, n);
1647                 if (t == first + 1 || amt == 0)
1648                         return (first);
1649 
1650                 sp = name_at(&db->cpp_name, amt - 1);
1651                 for (size_t i = 0; i < amt; i++, sp++) {
1652                         paren(sp);
1653                         if (str_pair_len(sp) > 0)
1654                                 (void) str_append(&sp->strp_l, "&&", 2);
1655                 }
1656 
1657                 save_top(db, amt);
1658                 return (t);
1659 
1660         case 'P':
1661                 t = parse_type(first + 1, last, db);
1662                 amt = NAMT(db, n);
1663                 if (t == first + 1 || amt == 0)
1664                         return (first);
1665 
1666                 sp = name_at(&db->cpp_name, amt - 1);
1667                 for (size_t i = 0; i < amt; i++, sp++) {
1668                         str_t *l = &sp->strp_l;
1669 
1670                         if (str_pair_len(sp) == 0)
1671                                 continue;
1672 
1673                         paren(sp);
1674                         if (first[1] != 'U' ||
1675                             strncmp(l->str_s, "objc_object<", 12) != 0) {
1676                                 (void) str_append(l, "*", 1);
1677                         } else {
1678                                 (void) str_erase(l, 0, 11);
1679                                 (void) str_insert(l, 0, "id", 2);
1680                         }
1681                 }
1682                 save_top(db, amt);
1683                 return (t);
1684 
1685         case 'R':
1686                 t = parse_type(first + 1, last, db);
1687                 amt = NAMT(db, n);
1688                 if (t == first + 1 || amt == 0)
1689                         return (first);
1690 
1691                 sp = name_at(&db->cpp_name, amt - 1);
1692                 for (size_t i = 0; i < amt; i++, sp++) {
1693                         if (str_length(&sp->strp_l) == 0 &&
1694                             str_length(&sp->strp_r) == 0)
1695                                 continue;
1696 
1697                         paren(sp);
1698                         (void) str_append(&sp->strp_l, "&", 1);
1699                 }
1700 
1701                 save_top(db, amt);
1702                 return (t);
1703 
1704         case 'T':
1705                 t = parse_template_param(first, last, db);
1706                 if (t == first)
1707                         return (first);
1708 
1709                 amt = NAMT(db, n);
1710                 save_top(db, amt);
1711                 if (!db->cpp_try_to_parse_template_args || amt != 1)
1712                         return (t);
1713 
1714                 t1 = parse_template_args(t, last, db);
1715                 if (t1 == t)
1716                         return (t);
1717 
1718                 nfmt(db, "{1:L}{0}", "{1:R}");


1860         t1 = parse_type(t, last, db);
1861         size_t amt = NAMT(db, n);
1862         if (t == t1 || amt == 0)
1863                 return (first);
1864 
1865         if (is_func)
1866                 sub_pop(&db->cpp_subs);
1867 
1868         str_pair_t *sp = name_at(&db->cpp_name, amt - 1);
1869 
1870         for (size_t i = 0; i < amt; i++, sp++) {
1871                 str_t *s = NULL;
1872 
1873                 if (!is_func) {
1874                         s = &sp->strp_l;
1875 
1876                         if (str_length(s) == 0)
1877                                 continue;
1878 
1879                         if (cv & 1)
1880                                 (void) str_append(s, " const", 6);
1881                         if (cv & 2)
1882                                 (void) str_append(s, " volatile", 9);
1883                         if (cv & 4)
1884                                 (void) str_append(s, " restrict", 9);
1885 
1886                         continue;
1887                 }
1888 
1889                 s = &sp->strp_r;
1890                 size_t pos = str_length(s);
1891 
1892                 if (pos > 0 && s->str_s[pos - 1] == '&') {
1893                         pos--;
1894                         if (s->str_s[pos - 1] == '&')
1895                                 pos--;
1896                 }
1897 
1898                 if (cv & 1) {
1899                         (void) str_insert(s, pos, " const", 6);
1900                         pos += 6;
1901                 }
1902                 if (cv & 2) {
1903                         (void) str_insert(s, pos, " volatile", 9);
1904                         pos += 9;
1905                 }
1906                 if (cv & 4) {
1907                         (void) str_insert(s, pos, " restrict", 9);
1908                 }
1909         }
1910 
1911         save_top(db, amt);
1912         return (t1);
1913 }
1914 
1915 /*
1916  * at <type>              # alignof (a type)
1917  * az <expression>        # alignof (a expression)
1918  */
1919 static const char *
1920 parse_alignof(const char *first, const char *last, cpp_db_t *db)
1921 {
1922         VERIFY3P(first, <=, last);
1923 
1924         if (last - first < 2)
1925                 return (first);
1926 
1927         const char *(*fn)(const char *, const char *, cpp_db_t *);


2616         switch (first[0]) {
2617         case 'C':
2618                 switch (first[1]) {
2619                 case '1':
2620                 case '2':
2621                 case '3':
2622                 case '5':
2623                         basename(db);
2624                         break;
2625                 default:
2626                         return (first);
2627                 }
2628                 break;
2629         case 'D':
2630                 switch (first[1]) {
2631                 case '0':
2632                 case '1':
2633                 case '2':
2634                 case '5':
2635                         basename(db);
2636                         (void) str_insert(TOP_L(db), 0, "~", 1);
2637                         break;
2638                 default:
2639                         return (first);
2640                 }
2641                 break;
2642         default:
2643                 return (first);
2644         }
2645 
2646         db->cpp_parsed_ctor_dtor_cv = B_TRUE;
2647         return (first + 2);
2648 }
2649 
2650 static const char *
2651 parse_integer_literal(const char *first, const char *last, const char *fmt,
2652     cpp_db_t *db)
2653 {
2654         VERIFY3P(first, <=, last);
2655 
2656         const char *t = parse_number(first, last, db->cpp_loc);


2773         switch (first[0]) {
2774         case 'f':
2775                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2776                     conv.f.v);
2777                 break;
2778         case 'd':
2779                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2780                     conv.d.v);
2781                 break;
2782         case 'e':
2783                 n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
2784                     conv.ld.v);
2785         }
2786 
2787         if (n >= fd->max_demangled_size || n <= 0) {
2788                 str_fini(&num);
2789                 return (first);
2790         }
2791 
2792         num.str_len = n;
2793         (void) name_add_str(&db->cpp_name, &num, NULL);
2794 
2795         return (t + 1);
2796 }
2797 
2798 /*
2799  * <expr-primary> ::= L <type> <value number> E       # integer literal
2800  *                ::= L <type> <value float> E      # floating literal
2801  *                ::= L <string type> E           # string literal
2802  *                ::= L <nullptr type> E  # nullptr literal (i.e., "LDnE")
2803  *
2804  *                ::= L <type> <real-part float> _ <imag-part float> E
2805  *                                              # complex floating point
2806  *                                              # literal (C 2000)
2807  *
2808  *                ::= L <mangled-name> E  # external name
2809  */
2810 static struct {
2811         int             c;
2812         const char      *fmt;
2813 } int_lits[] = {


3387                 if (t1[0] != '_')
3388                         return (first);
3389 
3390                 t = t1;
3391         } else {
3392                 nadd_l(db, "", 0);
3393         }
3394 
3395         VERIFY3U(t[0], ==, '_');
3396 
3397         t1 = parse_type(t + 1, last, db);
3398         if (t1 == t + 1 || NAMT(db, n) != 2)
3399                 return (first);
3400 
3401         /*
3402          * if we have  " [xxx]" already, want new result to be
3403          * " [yyy][xxx]"
3404          */
3405         str_t *r = &name_top(&db->cpp_name)->strp_r;
3406         if (r->str_len > 1 && r->str_s[0] == ' ' && r->str_s[1] == '[')
3407                 (void) str_erase(r, 0, 1);
3408 
3409         nfmt(db, "{0:L}", " [{1}]{0:R}");
3410         return (t1);
3411 }
3412 
3413 /* <pointer-to-member-type> ::= M <class type> <member type> */
3414 static const char *
3415 parse_pointer_to_member_type(const char *first, const char *last, cpp_db_t *db)
3416 {
3417         VERIFY3P(first, <=, last);
3418 
3419         if (last - first < 3)
3420                 return (first);
3421 
3422         VERIFY3U(first[0], ==, 'M');
3423 
3424         const char *t1 = first + 1;
3425         const char *t2 = NULL;
3426         size_t n = nlen(db);
3427 


3469                 return (first);
3470 
3471         const char *t = first;
3472         const char *t2 = NULL;
3473         boolean_t global = B_FALSE;
3474         size_t n;
3475 
3476         if (t[0] == 'g' && t[1] == 's') {
3477                 global = B_TRUE;
3478                 t += 2;
3479         }
3480         if (t == last)
3481                 return (first);
3482 
3483         t2 = parse_base_unresolved_name(t, last, db);
3484         if (t != t2) {
3485                 if (global) {
3486                         if (nempty(db))
3487                                 return (first);
3488 
3489                         (void) str_insert(TOP_L(db), 0, "::", 2);
3490                 }
3491                 return (t2);
3492         }
3493 
3494         if (t[0] != 's' || t[1] != 'r' || last - t < 2)
3495                 return (first);
3496 
3497         n = nlen(db);
3498         if (t[2] == 'N') {
3499                 t += 3;
3500                 t2 = parse_unresolved_type(t, last, db);
3501                 if (t2 == t || t2 == last)
3502                         return (first);
3503                 t = t2;
3504 
3505                 t2 = parse_template_args(t, last, db);
3506                 if (t2 != t) {
3507                         if (NAMT(db, n) < 2 || t2 == last)
3508                                 return (first);
3509