Print this page
Address Robert's feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libsysdemangle/common/cpp_util.c
+++ new/usr/src/lib/libsysdemangle/common/cxx_util.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 /*
13 13 * Copyright 2017 Jason King
14 14 */
15 15
16 16 #include <sys/debug.h>
17 17 #include <sys/sysmacros.h>
18 18 #include <string.h>
19 19 #include <errno.h>
20 20 #include <stdlib.h>
21 21 #include "sysdemangle_int.h"
22 -#include "cpp.h"
22 +#include "cxx.h"
23 23
24 24 #define CHUNK_SIZE (8U)
25 25
26 26 /*
27 27 * A name_t is essentially a stack of str_pair_t's. Generally, the parsing
28 28 * code will push (via name_add() or the like) portions of the demangled
29 29 * name into a name_t, and periodically combine them via name_join().
30 30 *
31 31 * As such it should be noted that since items are added at the end of
32 32 * name_t->nm_items, the numbering of name_at() starts at the end
33 33 * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
34 34 *
35 35 * It should also be noted that for name_t's, adding is a move operation in
36 36 * that it takes ownership of the passed in string/str_t/etc
37 37 */
38 38
39 39 void
40 40 name_init(name_t *n, sysdem_ops_t *ops)
41 41 {
42 42 (void) memset(n, 0, sizeof (*n));
43 43 n->nm_ops = (ops != NULL) ? ops : sysdem_ops_default;
44 44 }
45 45
46 46 void
47 47 name_fini(name_t *n)
48 48 {
49 49 if (n == NULL)
50 50 return;
51 51
52 52 name_clear(n);
53 53 xfree(n->nm_ops, n->nm_items, n->nm_size);
54 54 n->nm_items = NULL;
55 55 n->nm_size = 0;
56 56 }
57 57
58 58 size_t
59 59 name_len(const name_t *n)
60 60 {
61 61 return (n->nm_len);
62 62 }
63 63
64 64 boolean_t
65 65 name_empty(const name_t *n)
66 66 {
67 67 return (name_len(n) == 0 ? B_TRUE : B_FALSE);
68 68 }
69 69
70 70 void
71 71 name_clear(name_t *n)
72 72 {
73 73 if (n == NULL)
74 74 return;
75 75
76 76 for (size_t i = 0; i < n->nm_len; i++) {
77 77 str_pair_t *sp = &n->nm_items[i];
78 78 sysdem_ops_t *ops = sp->strp_l.str_ops;
79 79
80 80 str_pair_fini(sp);
81 81 str_pair_init(sp, ops);
82 82 }
83 83
84 84 n->nm_len = 0;
85 85 }
86 86
87 87 static boolean_t
88 88 name_reserve(name_t *n, size_t amt)
89 89 {
90 90 size_t newlen = n->nm_len + amt;
91 91
92 92 if (newlen == cpp_name_max_depth) {
93 93 errno = ENAMETOOLONG;
94 94 return (B_FALSE);
95 95 }
96 96
97 97 if (newlen < n->nm_size)
98 98 return (B_TRUE);
99 99
100 100 size_t newsize = roundup(newlen, CHUNK_SIZE);
101 101 if (newsize > cpp_name_max_depth)
102 102 newsize = cpp_name_max_depth;
103 103
104 104 void *temp = xrealloc(n->nm_ops, n->nm_items,
105 105 n->nm_size * sizeof (str_pair_t), newsize * sizeof (str_pair_t));
106 106
107 107 if (temp == NULL)
108 108 return (B_FALSE);
109 109
110 110 n->nm_items = temp;
111 111 n->nm_size = newsize;
112 112 return (B_TRUE);
113 113 }
114 114
115 115 boolean_t
116 116 name_add(name_t *n, const char *l, size_t l_len, const char *r, size_t r_len)
117 117 {
118 118 str_t sl = { 0 };
119 119 str_t sr = { 0 };
120 120
121 121 str_init(&sl, n->nm_ops);
122 122 str_init(&sr, n->nm_ops);
123 123 str_set(&sl, l, l_len);
124 124 str_set(&sr, r, r_len);
125 125 return (name_add_str(n, &sl, &sr));
126 126 }
127 127
128 128 boolean_t
129 129 name_add_str(name_t *n, str_t *l, str_t *r)
130 130 {
131 131 str_pair_t sp;
132 132
133 133 str_pair_init(&sp, n->nm_ops);
134 134
135 135 if (!name_reserve(n, 1))
136 136 return (B_FALSE);
137 137
138 138 if (l != NULL) {
139 139 sp.strp_l = *l;
140 140 (void) memset(l, 0, sizeof (*l));
141 141 }
142 142
143 143 if (r != NULL) {
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
144 144 sp.strp_r = *r;
145 145 (void) memset(r, 0, sizeof (*r));
146 146 }
147 147
148 148 n->nm_items[n->nm_len++] = sp;
149 149
150 150 return (B_TRUE);
151 151 }
152 152
153 153 str_pair_t *
154 -name_at(name_t *n, size_t idx)
154 +name_at(const name_t *n, size_t idx)
155 155 {
156 - if (n->nm_len == 0)
157 - return (NULL);
158 -
159 - ASSERT3U(idx, <=, n->nm_len);
156 + VERIFY(!name_empty(n));
157 + VERIFY3U(idx, <, n->nm_len);
160 158 return (&n->nm_items[n->nm_len - idx - 1]);
161 159 }
162 160
163 161 str_pair_t *
164 162 name_top(name_t *n)
165 163 {
166 164 return (name_at(n, 0));
167 165 }
168 166
169 -str_pair_t *
167 +void
170 168 name_pop(name_t *n, str_pair_t *sp)
171 169 {
172 170 if (n->nm_len == 0)
173 - return (NULL);
171 + return;
174 172
175 173 str_pair_t *top = name_top(n);
176 174
177 175 if (sp != NULL) {
178 176 *sp = *top;
179 177 (void) memset(top, 0, sizeof (*top));
180 178 } else {
181 179 str_pair_fini(top);
182 180 }
183 181
184 182 n->nm_len--;
185 - return (sp);
186 183 }
187 184
188 185 boolean_t
189 186 name_join(name_t *n, size_t amt, const char *sep)
190 187 {
191 188 str_pair_t *sp = NULL;
192 189 str_t res = { 0 };
193 190 size_t seplen = strlen(sep);
194 191
195 - ASSERT3U(amt, <=, n->nm_len);
192 + VERIFY3U(amt, <=, n->nm_len);
196 193
197 194 /*
198 195 * A join of 0 elements places an empty string on the stack. This
199 196 * simplifies code that wants to do things like:
200 197 * name_join(...); name_fmt(.., "({0})", ...)
201 198 */
202 199 if (amt == 0) {
203 200 name_add(n, "", 0, "", 0);
204 201 return (B_TRUE);
205 202 }
206 -
203 +
207 204 /* A join of 1 element just implies merging the top str_pair_t */
208 205 if (amt == 1) {
209 - ASSERT3U(name_len(n), >, 0);
206 + VERIFY3U(name_len(n), >, 0);
210 207 return (str_pair_merge(name_top(n)));
211 208 }
212 209
213 210 (void) str_init(&res, n->nm_ops);
214 211
215 212 sp = name_at(n, amt - 1);
216 213 for (size_t i = 0; i < amt; i++) {
217 214 if (i > 0) {
218 215 if (!str_append(&res, sep, seplen))
219 216 goto error;
220 217 }
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
221 218
222 219 if (!str_append_str(&res, &sp->strp_l))
223 220 goto error;
224 221 if (!str_append_str(&res, &sp->strp_r))
225 222 goto error;
226 223
227 224 sp++;
228 225 }
229 226
230 227 for (size_t i = 0; i < amt; i++)
231 - (void) name_pop(n, NULL);
228 + name_pop(n, NULL);
232 229
233 230 /* since we've removed at least 1 entry, this should always succeed */
234 231 VERIFY(name_add_str(n, &res, NULL));
235 232 return (B_TRUE);
236 233
237 234 error:
238 235 str_fini(&res);
239 236 return (B_FALSE);
240 237 }
241 238
242 239 static boolean_t
243 240 name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
244 241 {
245 242 const char *p;
246 243 long max = -1;
247 244
248 245 if (fmt == NULL)
249 246 return (B_TRUE);
250 247
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
251 248 for (p = fmt; *p != '\0'; p++) {
252 249 if (*p != '{') {
253 250 str_append_c(s, *p);
254 251 continue;
255 252 }
256 253
257 254 errno = 0;
258 255 char *q = NULL;
259 256 long val = strtol(p + 1, &q, 10);
260 257
261 - ASSERT(val != 0 || errno == 0);
262 - ASSERT3U(val, <, n->nm_len);
258 + VERIFY(val != 0 || errno == 0);
259 + VERIFY3U(val, <, n->nm_len);
263 260
264 261 str_pair_t *sp = name_at(n, val);
265 262
266 263 if (val > max)
267 264 max = val;
268 265
269 266 switch (q[0]) {
270 267 case '}':
271 268 if (!str_append_str(s, &sp->strp_l))
272 269 return (B_FALSE);
273 270 if (!str_append_str(s, &sp->strp_r))
274 271 return (B_FALSE);
275 272 p = q;
276 273 continue;
277 274 case ':':
278 275 switch (q[1]) {
279 276 case 'L':
280 277 if (!str_append_str(s, &sp->strp_l))
281 278 return (B_FALSE);
282 279 break;
283 280 case 'R':
284 281 if (!str_append_str(s, &sp->strp_r))
285 282 return (B_FALSE);
286 283 break;
287 284 }
288 285
289 286 p = q + 2;
290 287 VERIFY(*p == '}');
291 288 break;
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
292 289 }
293 290 }
294 291
295 292 if (*maxp < max)
296 293 *maxp = max;
297 294
298 295 return (B_TRUE);
299 296 }
300 297
301 298 /*
302 - * replace a number of elements in the name stack with a formatted string
299 + * Replace a number of elements in the name stack with a formatted string
303 300 * for format is a plain string with optional {nnn} or {nnn:L|R} substitutions
304 301 * where nnn is the stack position of an element and it's contents (both
305 302 * left and right pieces) are inserted. Optionally, only the left or
306 303 * right piece can specified using :L|R e.g. {2:L}{3}{2:R} would insert
307 304 * the left piece of element 2, all of element 3, then the right piece of
308 305 * element 2.
309 306 *
310 307 * Once complete, all elements up to the deepest one references are popped
311 308 * off the stack, and the resulting formatted string is pushed into n.
312 309 *
313 310 * This could be done as a sequence of push & pops, but this makes the
314 311 * intended output far clearer to see.
315 312 */
316 313 boolean_t
317 314 name_fmt(name_t *n, const char *fmt_l, const char *fmt_r)
318 315 {
319 316 str_pair_t res;
320 317 long max = -1;
321 318
322 319 (void) str_pair_init(&res, n->nm_ops);
323 320
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
324 321 if (!name_reserve(n, 1))
325 322 return (B_FALSE);
326 323
327 324 if (!name_fmt_s(n, &res.strp_l, fmt_l, &max))
328 325 goto error;
329 326 if (!name_fmt_s(n, &res.strp_r, fmt_r, &max))
330 327 goto error;
331 328
332 329 if (max >= 0) {
333 330 for (size_t i = 0; i <= max; i++)
334 - (void) name_pop(n, NULL);
331 + name_pop(n, NULL);
335 332 }
336 333
337 334 n->nm_items[n->nm_len++] = res;
338 335 return (B_TRUE);
339 336
340 337 error:
341 338 str_pair_fini(&res);
342 339 return (B_FALSE);
343 340 }
344 341
345 342 /*
346 343 * The substitution list is a list of name_t's that get added as the
347 344 * demangled name is parsed. Adding a name_t to the substitution list
348 345 * is a copy operation, and likewise inserting a substitution into a name_t
349 346 * is also a copy operation.
350 347 */
351 348 void
352 349 sub_init(sub_t *sub, sysdem_ops_t *ops)
353 350 {
354 351 (void) memset(sub, 0, sizeof (*sub));
355 352 sub->sub_ops = (ops != NULL) ? ops : sysdem_ops_default;
356 353 }
357 354
358 355 void
359 356 sub_fini(sub_t *sub)
360 357 {
361 358 if (sub == NULL)
362 359 return;
363 360
364 361 sub_clear(sub);
365 362 xfree(sub->sub_ops, sub->sub_items, sub->sub_size);
366 363 sub->sub_items = NULL;
367 364 sub->sub_size = 0;
368 365 }
369 366
370 367 void
371 368 sub_clear(sub_t *sub)
372 369 {
373 370 if (sub == NULL)
374 371 return;
375 372
376 373 for (size_t i = 0; i < sub->sub_len; i++)
377 374 name_fini(&sub->sub_items[i]);
378 375
379 376 sub->sub_len = 0;
380 377 }
381 378
382 379 boolean_t
383 380 sub_empty(const sub_t *sub)
384 381 {
385 382 return ((sub->sub_len == 0) ? B_TRUE : B_FALSE);
386 383 }
387 384
388 385 size_t
389 386 sub_len(const sub_t *sub)
390 387 {
391 388 return (sub->sub_len);
392 389 }
393 390
394 391 static boolean_t
395 392 sub_reserve(sub_t *sub, size_t amt)
396 393 {
397 394 if (sub->sub_len + amt < sub->sub_size)
398 395 return (B_TRUE);
399 396
400 397 size_t newsize = roundup(sub->sub_size + amt, CHUNK_SIZE);
401 398 void *temp = xrealloc(sub->sub_ops, sub->sub_items,
402 399 sub->sub_size * sizeof (name_t), newsize * sizeof (name_t));
403 400
404 401 if (temp == NULL)
405 402 return (B_FALSE);
406 403
407 404 sub->sub_items = temp;
408 405 sub->sub_size = newsize;
409 406
410 407 return (B_TRUE);
411 408 }
412 409
413 410 /* save the element of n (up to depth elements deep) as a substitution */
414 411 boolean_t
415 412 sub_save(sub_t *sub, const name_t *n, size_t depth)
416 413 {
417 414 if (depth == 0)
418 415 return (B_TRUE);
419 416
420 417 if (!sub_reserve(sub, 1))
421 418 return (B_FALSE);
↓ open down ↓ |
77 lines elided |
↑ open up ↑ |
422 419
423 420 name_t *dest = &sub->sub_items[sub->sub_len++];
424 421 name_init(dest, sub->sub_ops);
425 422
426 423 if (!name_reserve(dest, depth)) {
427 424 name_fini(dest);
428 425 sub->sub_len--;
429 426 return (B_FALSE);
430 427 }
431 428
432 - const str_pair_t *src_sp = name_at((name_t *)n, depth - 1);
429 + const str_pair_t *src_sp = name_at(n, depth - 1);
433 430
434 431 for (size_t i = 0; i < depth; i++, src_sp++) {
435 432 str_pair_t copy = { 0 };
436 433 str_pair_init(©, n->nm_ops);
437 434 if (!str_pair_copy(src_sp, ©)) {
438 435 str_pair_fini(©);
439 436 name_fini(dest);
440 437 return (B_FALSE);
441 438 }
442 439
443 440 VERIFY(name_add_str(dest, ©.strp_l, ©.strp_r));
444 441 }
445 442
446 443 return (B_TRUE);
447 444 }
448 445
449 446 /* push substitution idx onto n */
450 447 boolean_t
451 448 sub_substitute(const sub_t *sub, size_t idx, name_t *n)
452 449 {
453 - ASSERT3U(idx, <, sub->sub_len);
450 + VERIFY3U(idx, <, sub->sub_len);
454 451
455 452 const name_t *src = &sub->sub_items[idx];
456 453 const str_pair_t *sp = src->nm_items;
457 454 size_t save = name_len(n);
458 455
459 456 for (size_t i = 0; i < src->nm_len; i++, sp++) {
460 457 str_pair_t copy = { 0 };
461 458
462 459 if (!str_pair_copy(sp, ©))
463 460 goto fail;
464 461
465 462 if (!name_add_str(n, ©.strp_l, ©.strp_r))
466 463 goto fail;
467 464 }
468 465
469 466 return (B_TRUE);
470 467
471 468 fail:
472 469 for (size_t i = 0; i < name_len(n) - save; i++)
473 - (void) name_pop(n, NULL);
470 + name_pop(n, NULL);
474 471 return (B_FALSE);
475 472 }
476 473
477 474 void
478 475 sub_pop(sub_t *sub)
479 476 {
480 477 name_t *top = &sub->sub_items[--sub->sub_len];
481 478 name_fini(top);
482 479 }
483 480
484 481 /*
485 482 * Templates can use substitutions for it's arguments (using T instead of
486 483 * S). Since templates can nest however, each nesting requires a new
487 484 * set of substitutions. As such a new, empty list of template substitutions
488 485 * is pushed onto cpp_templ each time templates are nested, and popped at
489 486 * the end of the current template argument list.
490 487 */
491 488 static boolean_t
492 489 templ_reserve(templ_t *tpl, size_t n)
493 490 {
494 491 if (tpl->tpl_len + n < tpl->tpl_size)
495 492 return (B_TRUE);
496 493
497 494 size_t newsize = tpl->tpl_size + CHUNK_SIZE;
498 495 void *temp = xrealloc(tpl->tpl_ops, tpl->tpl_items,
499 496 tpl->tpl_size * sizeof (sub_t), newsize * sizeof (sub_t));
500 497
501 498 if (temp == NULL)
502 499 return (B_FALSE);
503 500
504 501 tpl->tpl_items = temp;
505 502 tpl->tpl_size = newsize;
506 503 return (B_TRUE);
507 504 }
508 505
509 506 void
510 507 templ_init(templ_t *tpl, sysdem_ops_t *ops)
511 508 {
512 509 (void) memset(tpl, 0, sizeof (*tpl));
513 510 tpl->tpl_ops = ops;
514 511 }
515 512
516 513 void
517 514 templ_fini(templ_t *tpl)
518 515 {
519 516 if (tpl == NULL)
520 517 return;
521 518
522 519 for (size_t i = 0; i < tpl->tpl_len; i++)
523 520 sub_fini(&tpl->tpl_items[i]);
524 521
525 522 xfree(tpl->tpl_ops, tpl->tpl_items, tpl->tpl_size * sizeof (sub_t));
526 523 sysdem_ops_t *ops = tpl->tpl_ops;
527 524 (void) memset(tpl, 0, sizeof (*tpl));
528 525 tpl->tpl_ops = ops;
529 526 }
530 527
531 528 boolean_t
532 529 templ_push(templ_t *tpl)
533 530 {
534 531 if (!templ_reserve(tpl, 1))
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
535 532 return (B_FALSE);
536 533
537 534 sub_t *sub = &tpl->tpl_items[tpl->tpl_len++];
538 535 sub_init(sub, tpl->tpl_ops);
539 536 return (B_TRUE);
540 537 }
541 538
542 539 void
543 540 templ_pop(templ_t *tpl)
544 541 {
545 - ASSERT(!templ_empty(tpl));
542 + VERIFY(!templ_empty(tpl));
546 543
547 544 sub_t *sub = &tpl->tpl_items[--tpl->tpl_len];
548 545 sub_fini(sub);
549 546 }
550 547
551 548 sub_t *
552 549 templ_top(templ_t *tpl)
553 550 {
554 551 if (tpl->tpl_len == 0)
555 552 return (NULL);
556 553 return (&tpl->tpl_items[tpl->tpl_len - 1]);
557 554 }
558 555
559 556 boolean_t
560 557 templ_empty(const templ_t *tpl)
561 558 {
562 559 return ((tpl->tpl_len == 0) ? B_TRUE : B_FALSE);
563 560 }
564 561
565 562 size_t
566 563 templ_top_len(const templ_t *tpl)
567 564 {
568 565 const sub_t *sub = templ_top((templ_t *)tpl);
569 566
570 567 return (sub->sub_len);
571 568 }
572 569
573 570 boolean_t
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
574 571 templ_sub(const templ_t *tpl, size_t idx, name_t *n)
575 572 {
576 573 const sub_t *sub = templ_top((templ_t *)tpl);
577 574
578 575 return (sub_substitute(sub, idx, n));
579 576 }
580 577
581 578 boolean_t
582 579 templ_save(const name_t *n, size_t amt, templ_t *tpl)
583 580 {
584 - ASSERT3U(tpl->tpl_len, >, 0);
581 + VERIFY3U(tpl->tpl_len, >, 0);
585 582
586 583 sub_t *s = templ_top(tpl);
587 584 boolean_t res = B_TRUE;
588 585
589 586 /* a bit of a hack -- want an 'empty' entry when saving 0 params */
590 587 if (amt == 0) {
591 588 name_t name = { 0 };
592 589
593 590 name_init(&name, tpl->tpl_ops);
594 591 res &= name_add(&name, "", 0, "", 0);
595 592 if (res)
596 593 res &= sub_save(s, &name, 1);
597 594 name_fini(&name);
598 595 } else {
599 596 res &= sub_save(s, n, amt);
600 597 }
601 598
602 599 return (res);
603 600 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX