Print this page
Rich's feedback
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Jason King
  14  */
  15 
  16 #include <sys/debug.h>
  17 #include <sys/sysmacros.h>
  18 #include <string.h>
  19 #include <errno.h>
  20 #include <stdlib.h>
  21 #include "sysdemangle_int.h"
  22 #include "cxx.h"
  23 
  24 #define CHUNK_SIZE  (8U)
  25 
  26 /*
  27  * A name_t is essentially a stack of str_pair_t's.  Generally, the parsing
  28  * code will push (via name_add() or the like) portions of the demangled
  29  * name into a name_t, and periodically combine them via name_join().
  30  *
  31  * As such it should be noted that since items are added at the end of
  32  * name_t->nm_items, the numbering of name_at() starts at the end
  33  * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
  34  *
  35  * It should also be noted that for name_t's, adding is a move operation in
  36  * that it takes ownership of the passed in string/str_t/etc
  37  */
  38 
  39 void
  40 name_init(name_t *n, sysdem_ops_t *ops)
  41 {


  61         return (n->nm_len);
  62 }
  63 
  64 boolean_t
  65 name_empty(const name_t *n)
  66 {
  67         return (name_len(n) == 0 ? B_TRUE : B_FALSE);
  68 }
  69 
  70 void
  71 name_clear(name_t *n)
  72 {
  73         if (n == NULL)
  74                 return;
  75 
  76         for (size_t i = 0; i < n->nm_len; i++) {
  77                 str_pair_t *sp = &n->nm_items[i];
  78                 sysdem_ops_t *ops = sp->strp_l.str_ops;
  79 
  80                 str_pair_fini(sp);
  81                 str_pair_init(sp, ops);
  82         }
  83 
  84         n->nm_len = 0;
  85 }
  86 
  87 static boolean_t
  88 name_reserve(name_t *n, size_t amt)
  89 {
  90         size_t newlen = n->nm_len + amt;
  91 
  92         if (newlen == cpp_name_max_depth) {
  93                 errno = ENAMETOOLONG;
  94                 return (B_FALSE);
  95         }
  96 
  97         if (newlen < n->nm_size)
  98                 return (B_TRUE);
  99 
 100         size_t newsize = roundup(newlen, CHUNK_SIZE);
 101         if (newsize > cpp_name_max_depth)


 113 }
 114 
 115 boolean_t
 116 name_add(name_t *n, const char *l, size_t l_len, const char *r, size_t r_len)
 117 {
 118         str_t sl = { 0 };
 119         str_t sr = { 0 };
 120 
 121         str_init(&sl, n->nm_ops);
 122         str_init(&sr, n->nm_ops);
 123         str_set(&sl, l, l_len);
 124         str_set(&sr, r, r_len);
 125         return (name_add_str(n, &sl, &sr));
 126 }
 127 
 128 boolean_t
 129 name_add_str(name_t *n, str_t *l, str_t *r)
 130 {
 131         str_pair_t sp;
 132 
 133         str_pair_init(&sp, n->nm_ops);
 134 
 135         if (!name_reserve(n, 1))
 136                 return (B_FALSE);
 137 
 138         if (l != NULL) {
 139                 sp.strp_l = *l;
 140                 (void) memset(l, 0, sizeof (*l));
 141         }
 142 
 143         if (r != NULL) {
 144                 sp.strp_r = *r;
 145                 (void) memset(r, 0, sizeof (*r));
 146         }
 147 
 148         n->nm_items[n->nm_len++] = sp;
 149 
 150         return (B_TRUE);
 151 }
 152 
 153 str_pair_t *


 180         }
 181 
 182         n->nm_len--;
 183 }
 184 
 185 boolean_t
 186 name_join(name_t *n, size_t amt, const char *sep)
 187 {
 188         str_pair_t *sp = NULL;
 189         str_t res = { 0 };
 190         size_t seplen = strlen(sep);
 191 
 192         VERIFY3U(amt, <=, n->nm_len);
 193 
 194         /*
 195          * A join of 0 elements places an empty string on the stack.  This
 196          * simplifies code that wants to do things like:
 197          *   name_join(...); name_fmt(.., "({0})", ...)
 198          */
 199         if (amt == 0) {
 200                 name_add(n, "", 0, "", 0);
 201                 return (B_TRUE);
 202         }
 203 
 204         /* A join of 1 element just implies merging the top str_pair_t */
 205         if (amt == 1) {
 206                 VERIFY3U(name_len(n), >, 0);
 207                 return (str_pair_merge(name_top(n)));
 208         }
 209 
 210         (void) str_init(&res, n->nm_ops);
 211 
 212         sp = name_at(n, amt - 1);
 213         for (size_t i = 0; i < amt; i++) {
 214                 if (i > 0) {
 215                         if (!str_append(&res, sep, seplen))
 216                                 goto error;
 217                 }
 218 
 219                 if (!str_append_str(&res, &sp->strp_l))
 220                         goto error;


 230         /* since we've removed at least 1 entry, this should always succeed */
 231         VERIFY(name_add_str(n, &res, NULL));
 232         return (B_TRUE);
 233 
 234 error:
 235         str_fini(&res);
 236         return (B_FALSE);
 237 }
 238 
 239 static boolean_t
 240 name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
 241 {
 242         const char *p;
 243         long max = -1;
 244 
 245         if (fmt == NULL)
 246                 return (B_TRUE);
 247 
 248         for (p = fmt; *p != '\0'; p++) {
 249                 if (*p != '{') {
 250                         str_append_c(s, *p);
 251                         continue;
 252                 }
 253 
 254                 errno = 0;
 255                 char *q = NULL;
 256                 long val = strtol(p + 1, &q, 10);
 257 
 258                 VERIFY(val != 0 || errno == 0);
 259                 VERIFY3U(val, <, n->nm_len);
 260 
 261                 str_pair_t *sp = name_at(n, val);
 262 
 263                 if (val > max)
 264                         max = val;
 265 
 266                 switch (q[0]) {
 267                 case '}':
 268                         if (!str_append_str(s, &sp->strp_l))
 269                                 return (B_FALSE);
 270                         if (!str_append_str(s, &sp->strp_r))


 413 {
 414         if (depth == 0)
 415                 return (B_TRUE);
 416 
 417         if (!sub_reserve(sub, 1))
 418                 return (B_FALSE);
 419 
 420         name_t *dest = &sub->sub_items[sub->sub_len++];
 421         name_init(dest, sub->sub_ops);
 422 
 423         if (!name_reserve(dest, depth)) {
 424                 name_fini(dest);
 425                 sub->sub_len--;
 426                 return (B_FALSE);
 427         }
 428 
 429         const str_pair_t *src_sp = name_at(n, depth - 1);
 430 
 431         for (size_t i = 0; i < depth; i++, src_sp++) {
 432                 str_pair_t copy = { 0 };
 433                 str_pair_init(&copy, n->nm_ops);
 434                 if (!str_pair_copy(src_sp, &copy)) {
 435                         str_pair_fini(&copy);
 436                         name_fini(dest);
 437                         return (B_FALSE);
 438                 }
 439 
 440                 VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
 441         }
 442 
 443         return (B_TRUE);
 444 }
 445 
 446 /* push substitution idx onto n */
 447 boolean_t
 448 sub_substitute(const sub_t *sub, size_t idx, name_t *n)
 449 {
 450         VERIFY3U(idx, <, sub->sub_len);
 451 
 452         const name_t *src = &sub->sub_items[idx];
 453         const str_pair_t *sp = src->nm_items;


   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Jason King
  14  */
  15 
  16 #include <sys/debug.h>
  17 #include <sys/sysmacros.h>
  18 #include <string.h>
  19 #include <errno.h>
  20 #include <stdlib.h>
  21 #include "demangle_int.h"
  22 #include "cxx.h"
  23 
  24 #define CHUNK_SIZE  (8U)
  25 
  26 /*
  27  * A name_t is essentially a stack of str_pair_t's.  Generally, the parsing
  28  * code will push (via name_add() or the like) portions of the demangled
  29  * name into a name_t, and periodically combine them via name_join().
  30  *
  31  * As such it should be noted that since items are added at the end of
  32  * name_t->nm_items, the numbering of name_at() starts at the end
  33  * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
  34  *
  35  * It should also be noted that for name_t's, adding is a move operation in
  36  * that it takes ownership of the passed in string/str_t/etc
  37  */
  38 
  39 void
  40 name_init(name_t *n, sysdem_ops_t *ops)
  41 {


  61         return (n->nm_len);
  62 }
  63 
  64 boolean_t
  65 name_empty(const name_t *n)
  66 {
  67         return (name_len(n) == 0 ? B_TRUE : B_FALSE);
  68 }
  69 
  70 void
  71 name_clear(name_t *n)
  72 {
  73         if (n == NULL)
  74                 return;
  75 
  76         for (size_t i = 0; i < n->nm_len; i++) {
  77                 str_pair_t *sp = &n->nm_items[i];
  78                 sysdem_ops_t *ops = sp->strp_l.str_ops;
  79 
  80                 str_pair_fini(sp);
  81                 (void) str_pair_init(sp, ops);
  82         }
  83 
  84         n->nm_len = 0;
  85 }
  86 
  87 static boolean_t
  88 name_reserve(name_t *n, size_t amt)
  89 {
  90         size_t newlen = n->nm_len + amt;
  91 
  92         if (newlen == cpp_name_max_depth) {
  93                 errno = ENAMETOOLONG;
  94                 return (B_FALSE);
  95         }
  96 
  97         if (newlen < n->nm_size)
  98                 return (B_TRUE);
  99 
 100         size_t newsize = roundup(newlen, CHUNK_SIZE);
 101         if (newsize > cpp_name_max_depth)


 113 }
 114 
 115 boolean_t
 116 name_add(name_t *n, const char *l, size_t l_len, const char *r, size_t r_len)
 117 {
 118         str_t sl = { 0 };
 119         str_t sr = { 0 };
 120 
 121         str_init(&sl, n->nm_ops);
 122         str_init(&sr, n->nm_ops);
 123         str_set(&sl, l, l_len);
 124         str_set(&sr, r, r_len);
 125         return (name_add_str(n, &sl, &sr));
 126 }
 127 
 128 boolean_t
 129 name_add_str(name_t *n, str_t *l, str_t *r)
 130 {
 131         str_pair_t sp;
 132 
 133         (void) str_pair_init(&sp, n->nm_ops);
 134 
 135         if (!name_reserve(n, 1))
 136                 return (B_FALSE);
 137 
 138         if (l != NULL) {
 139                 sp.strp_l = *l;
 140                 (void) memset(l, 0, sizeof (*l));
 141         }
 142 
 143         if (r != NULL) {
 144                 sp.strp_r = *r;
 145                 (void) memset(r, 0, sizeof (*r));
 146         }
 147 
 148         n->nm_items[n->nm_len++] = sp;
 149 
 150         return (B_TRUE);
 151 }
 152 
 153 str_pair_t *


 180         }
 181 
 182         n->nm_len--;
 183 }
 184 
 185 boolean_t
 186 name_join(name_t *n, size_t amt, const char *sep)
 187 {
 188         str_pair_t *sp = NULL;
 189         str_t res = { 0 };
 190         size_t seplen = strlen(sep);
 191 
 192         VERIFY3U(amt, <=, n->nm_len);
 193 
 194         /*
 195          * A join of 0 elements places an empty string on the stack.  This
 196          * simplifies code that wants to do things like:
 197          *   name_join(...); name_fmt(.., "({0})", ...)
 198          */
 199         if (amt == 0) {
 200                 (void) name_add(n, "", 0, "", 0);
 201                 return (B_TRUE);
 202         }
 203 
 204         /* A join of 1 element just implies merging the top str_pair_t */
 205         if (amt == 1) {
 206                 VERIFY3U(name_len(n), >, 0);
 207                 return (str_pair_merge(name_top(n)));
 208         }
 209 
 210         (void) str_init(&res, n->nm_ops);
 211 
 212         sp = name_at(n, amt - 1);
 213         for (size_t i = 0; i < amt; i++) {
 214                 if (i > 0) {
 215                         if (!str_append(&res, sep, seplen))
 216                                 goto error;
 217                 }
 218 
 219                 if (!str_append_str(&res, &sp->strp_l))
 220                         goto error;


 230         /* since we've removed at least 1 entry, this should always succeed */
 231         VERIFY(name_add_str(n, &res, NULL));
 232         return (B_TRUE);
 233 
 234 error:
 235         str_fini(&res);
 236         return (B_FALSE);
 237 }
 238 
 239 static boolean_t
 240 name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
 241 {
 242         const char *p;
 243         long max = -1;
 244 
 245         if (fmt == NULL)
 246                 return (B_TRUE);
 247 
 248         for (p = fmt; *p != '\0'; p++) {
 249                 if (*p != '{') {
 250                         (void) str_append_c(s, *p);
 251                         continue;
 252                 }
 253 
 254                 errno = 0;
 255                 char *q = NULL;
 256                 long val = strtol(p + 1, &q, 10);
 257 
 258                 VERIFY(val != 0 || errno == 0);
 259                 VERIFY3U(val, <, n->nm_len);
 260 
 261                 str_pair_t *sp = name_at(n, val);
 262 
 263                 if (val > max)
 264                         max = val;
 265 
 266                 switch (q[0]) {
 267                 case '}':
 268                         if (!str_append_str(s, &sp->strp_l))
 269                                 return (B_FALSE);
 270                         if (!str_append_str(s, &sp->strp_r))


 413 {
 414         if (depth == 0)
 415                 return (B_TRUE);
 416 
 417         if (!sub_reserve(sub, 1))
 418                 return (B_FALSE);
 419 
 420         name_t *dest = &sub->sub_items[sub->sub_len++];
 421         name_init(dest, sub->sub_ops);
 422 
 423         if (!name_reserve(dest, depth)) {
 424                 name_fini(dest);
 425                 sub->sub_len--;
 426                 return (B_FALSE);
 427         }
 428 
 429         const str_pair_t *src_sp = name_at(n, depth - 1);
 430 
 431         for (size_t i = 0; i < depth; i++, src_sp++) {
 432                 str_pair_t copy = { 0 };
 433                 (void) str_pair_init(&copy, n->nm_ops);
 434                 if (!str_pair_copy(src_sp, &copy)) {
 435                         str_pair_fini(&copy);
 436                         name_fini(dest);
 437                         return (B_FALSE);
 438                 }
 439 
 440                 VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
 441         }
 442 
 443         return (B_TRUE);
 444 }
 445 
 446 /* push substitution idx onto n */
 447 boolean_t
 448 sub_substitute(const sub_t *sub, size_t idx, name_t *n)
 449 {
 450         VERIFY3U(idx, <, sub->sub_len);
 451 
 452         const name_t *src = &sub->sub_items[idx];
 453         const str_pair_t *sp = src->nm_items;