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(©, n->nm_ops);
434 if (!str_pair_copy(src_sp, ©)) {
435 str_pair_fini(©);
436 name_fini(dest);
437 return (B_FALSE);
438 }
439
440 VERIFY(name_add_str(dest, ©.strp_l, ©.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(©, n->nm_ops);
434 if (!str_pair_copy(src_sp, ©)) {
435 str_pair_fini(©);
436 name_fini(dest);
437 return (B_FALSE);
438 }
439
440 VERIFY(name_add_str(dest, ©.strp_l, ©.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;
|