1 /* $NetBSD: debug.c,v 1.83 2025/02/20 20:33:10 rillig Exp $ */
2 
3 /*-
4  * Copyright (c) 2021 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Roland Illig <rillig@NetBSD.org>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35 
36 #include <sys/cdefs.h>
37 #if defined(__RCSID)
38 __RCSID("$NetBSD: debug.c,v 1.83 2025/02/20 20:33:10 rillig Exp $");
39 #endif
40 
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "lint1.h"
45 #include "cgram.h"
46 
47 
48 #ifdef DEBUG
49 
50 bool debug_enabled;
51 static int debug_indentation = 0;
52 static bool did_indentation;
53 
54 
55 static FILE *
debug_file(void)56 debug_file(void)
57 {
58           /*
59            * Using stdout preserves the order between the debug messages and
60            * lint's diagnostics.
61            */
62           return yflag ? stderr : stdout;
63 }
64 
65 static void
debug_vprintf(const char * fmt,va_list va)66 debug_vprintf(const char *fmt, va_list va)
67 {
68 
69           if (!debug_enabled)
70                     return;
71 
72           if (!did_indentation) {
73                     did_indentation = true;
74                     fprintf(debug_file(), "%s%*s",
75                         yflag ? "| " : "", 2 * debug_indentation, "");
76           }
77 
78           (void)vfprintf(debug_file(), fmt, va);
79 
80           did_indentation = strchr(fmt, '\n') == NULL;
81 }
82 
83 void
debug_printf(const char * fmt,...)84 debug_printf(const char *fmt, ...)
85 {
86           va_list va;
87 
88           va_start(va, fmt);
89           debug_vprintf(fmt, va);
90           va_end(va);
91 }
92 
93 void
debug_skip_indent(void)94 debug_skip_indent(void)
95 {
96 
97           did_indentation = true;
98 }
99 
100 void
debug_indent_inc(void)101 debug_indent_inc(void)
102 {
103 
104           debug_indentation++;
105 }
106 
107 void
debug_indent_dec(void)108 debug_indent_dec(void)
109 {
110 
111           lint_assert(debug_indentation > 0);
112           debug_indentation--;
113 }
114 
115 bool
debug_push_indented(bool indented)116 debug_push_indented(bool indented)
117 {
118           bool prev = did_indentation;
119           did_indentation = indented;
120           return prev;
121 }
122 
123 void
debug_pop_indented(bool indented)124 debug_pop_indented(bool indented)
125 {
126           did_indentation = indented;
127 }
128 
129 void
debug_step(const char * fmt,...)130 debug_step(const char *fmt, ...)
131 {
132           va_list va;
133 
134           va_start(va, fmt);
135           debug_vprintf(fmt, va);
136           va_end(va);
137           debug_printf("\n");
138 }
139 
140 void
debug_enter_func(const char * func)141 debug_enter_func(const char *func)
142 {
143 
144           debug_step("+ %s", func);
145           debug_indent_inc();
146 }
147 
148 void
debug_leave_func(const char * func)149 debug_leave_func(const char *func)
150 {
151 
152           debug_indent_dec();
153           debug_step("- %s", func);
154 }
155 
156 static void
debug_type_details(const type_t * tp)157 debug_type_details(const type_t *tp)
158 {
159 
160           if (is_struct_or_union(tp->t_tspec)) {
161                     debug_indent_inc();
162                     unsigned int size_in_bits = tp->u.sou->sou_size_in_bits;
163                     debug_printf("size %u", size_in_bits / CHAR_SIZE);
164                     if (size_in_bits % CHAR_SIZE > 0)
165                               debug_printf("+%u", size_in_bits % CHAR_SIZE);
166                     debug_step(", align %u, %s",
167                         tp->u.sou->sou_align,
168                         tp->u.sou->sou_incomplete ? "incomplete" : "complete");
169 
170                     for (const sym_t *mem = tp->u.sou->sou_first_member;
171                         mem != NULL; mem = mem->s_next) {
172                               debug_sym("", mem, "\n");
173                               debug_type_details(mem->s_type);
174                     }
175                     debug_indent_dec();
176           }
177           if (tp->t_is_enum) {
178                     debug_indent_inc();
179                     for (const sym_t *en = tp->u.enumer->en_first_enumerator;
180                         en != NULL; en = en->s_next) {
181                               debug_sym("", en, "\n");
182                     }
183                     debug_indent_dec();
184           }
185 }
186 
187 void
debug_type(const type_t * tp)188 debug_type(const type_t *tp)
189 {
190 
191           debug_step("type details for '%s':", type_name(tp));
192           debug_type_details(tp);
193 }
194 
195 void
debug_node(const tnode_t * tn)196 debug_node(const tnode_t *tn) // NOLINT(misc-no-recursion)
197 {
198 
199           if (tn == NULL) {
200                     debug_step("null");
201                     return;
202           }
203 
204           op_t op = tn->tn_op;
205           debug_printf("'%s'",
206               op == CVT && tn->tn_cast ? "cast" : op_name(op));
207           if (op == NAME)
208                     debug_printf(" '%s' with %s",
209                         tn->u.sym->s_name,
210                         scl_name(tn->u.sym->s_scl));
211           else
212                     debug_printf(" type");
213           debug_printf(" '%s'", type_name(tn->tn_type));
214           if (tn->tn_lvalue)
215                     debug_printf(", lvalue");
216           if (tn->tn_parenthesized)
217                     debug_printf(", parenthesized");
218           if (tn->tn_sys)
219                     debug_printf(", sys");
220 
221           switch (op) {
222           case NAME:
223                     debug_printf("\n");
224                     break;
225           case CON:
226                     if (is_floating(tn->tn_type->t_tspec))
227                               debug_printf(", value %Lg", tn->u.value.u.floating);
228                     else if (is_uinteger(tn->tn_type->t_tspec))
229                               debug_printf(", value %llu",
230                                   (unsigned long long)tn->u.value.u.integer);
231                     else if (is_integer(tn->tn_type->t_tspec))
232                               debug_printf(", value %lld",
233                                   (long long)tn->u.value.u.integer);
234                     else {
235                               lint_assert(tn->tn_type->t_tspec == BOOL);
236                               debug_printf(", value %s",
237                                   tn->u.value.u.integer != 0 ? "true" : "false");
238                     }
239                     if (tn->u.value.v_unsigned_since_c90)
240                               debug_printf(", unsigned_since_c90");
241                     if (tn->u.value.v_char_constant)
242                               debug_printf(", char_constant");
243                     debug_printf("\n");
244                     break;
245           case STRING:
246                     if (tn->u.str_literals->data != NULL)
247                               debug_printf(", %s\n", tn->u.str_literals->data);
248                     else
249                               debug_printf(", length %zu\n", tn->u.str_literals->len);
250                     break;
251           case CALL:
252                     debug_printf("\n");
253 
254                     debug_indent_inc();
255                     const function_call *call = tn->u.call;
256                     debug_node(call->func);
257                     for (size_t i = 0, n = call->args_len; i < n; i++)
258                               debug_node(call->args[i]);
259                     debug_indent_dec();
260                     break;
261           default:
262                     debug_printf("\n");
263 
264                     debug_indent_inc();
265                     lint_assert(has_operands(tn));
266                     lint_assert(tn->u.ops.left != NULL);
267                     debug_node(tn->u.ops.left);
268                     if (op != INCBEF && op != INCAFT
269                         && op != DECBEF && op != DECAFT)
270                               lint_assert(is_binary(tn) == (tn->u.ops.right != NULL));
271                     if (tn->u.ops.right != NULL)
272                               debug_node(tn->u.ops.right);
273                     debug_indent_dec();
274           }
275 }
276 
277 static const char *
def_name(def_t def)278 def_name(def_t def)
279 {
280           static const char *const name[] = {
281                     "not-declared",
282                     "declared",
283                     "tentative-defined",
284                     "defined",
285           };
286 
287           return name[def];
288 }
289 
290 const char *
decl_level_kind_name(decl_level_kind kind)291 decl_level_kind_name(decl_level_kind kind)
292 {
293           static const char *const name[] = {
294                     "extern",
295                     "struct",
296                     "union",
297                     "enum",
298                     "old-style-function-parameters",
299                     "prototype-parameters",
300                     "auto",
301                     "abstract",
302           };
303 
304           return name[kind];
305 }
306 
307 const char *
scl_name(scl_t scl)308 scl_name(scl_t scl)
309 {
310           static const char *const name[] = {
311                     "none",
312                     "extern",
313                     "static",
314                     "auto",
315                     "register",
316                     "typedef",
317                     "thread_local",
318                     "struct",
319                     "union",
320                     "enum",
321                     "member-of-struct",
322                     "member-of-union",
323                     "abstract",
324                     "old-style-function-parameter",
325                     "prototype-parameter",
326           };
327 
328           return name[scl];
329 }
330 
331 const char *
symbol_kind_name(symbol_kind kind)332 symbol_kind_name(symbol_kind kind)
333 {
334           static const char *const name[] = {
335                     "var-func-type",
336                     "member",
337                     "tag",
338                     "label",
339           };
340 
341           return name[kind];
342 }
343 
344 const char *
type_qualifiers_string(type_qualifiers tq)345 type_qualifiers_string(type_qualifiers tq)
346 {
347           static char buf[32];
348 
349           snprintf(buf, sizeof(buf), "%s%s%s%s",
350               tq.tq_const ? " const" : "",
351               tq.tq_restrict ? " restrict" : "",
352               tq.tq_volatile ? " volatile" : "",
353               tq.tq_atomic ? " atomic" : "");
354           return buf[0] != '\0' ? buf + 1 : "none";
355 }
356 
357 const char *
type_attributes_string(type_attributes attrs)358 type_attributes_string(type_attributes attrs)
359 {
360           static char buf[32];
361 
362           snprintf(buf, sizeof(buf), "%s%s%s",
363               attrs.used ? " used" : "",
364               attrs.noreturn ? " noreturn" : "",
365               attrs.bit_width == 128 ? " 128bit" :
366               attrs.bit_width == 64 ? " 64bit" : "");
367           return buf[0] != '\0' ? buf + 1 : "none";
368 }
369 
370 const char *
function_specifier_name(function_specifier spec)371 function_specifier_name(function_specifier spec)
372 {
373           static const char *const name[] = {
374                     "inline",
375                     "_Noreturn",
376           };
377 
378           return name[spec];
379 }
380 
381 const char *
named_constant_name(named_constant nc)382 named_constant_name(named_constant nc)
383 {
384           static const char *const name[] = {
385               "false",
386               "true",
387               "nullptr",
388           };
389 
390           return name[nc];
391 }
392 
393 static void
debug_word(bool flag,const char * name)394 debug_word(bool flag, const char *name)
395 {
396 
397           if (flag)
398                     debug_printf(" %s", name);
399 }
400 
401 void
debug_sym(const char * prefix,const sym_t * sym,const char * suffix)402 debug_sym(const char *prefix, const sym_t *sym, const char *suffix)
403 {
404 
405           debug_printf("%s%s", prefix, sym->s_name);
406           if (sym->s_type != NULL)
407                     debug_printf(" type='%s'", type_name(sym->s_type));
408           if (sym->s_rename != NULL)
409                     debug_printf(" rename=%s", sym->s_rename);
410           debug_printf(" %s", symbol_kind_name(sym->s_kind));
411           debug_word(sym->s_keyword != NULL, "keyword");
412           debug_word(sym->s_bitfield, "bit-field");
413           debug_word(sym->s_set, "set");
414           debug_word(sym->s_used, "used");
415           debug_word(sym->s_param, "parameter");
416           debug_word(sym->s_register, "register");
417           debug_word(sym->s_defparam, "old-style-undefined");
418           debug_word(sym->s_return_type_implicit_int, "return-int");
419           debug_word(sym->s_osdef, "old-style");
420           debug_word(sym->s_inline, "inline");
421           debug_word(sym->s_ext_sym != NULL, "has-external");
422           debug_word(sym->s_scl != NO_SCL, scl_name(sym->s_scl));
423           debug_word(sym->s_keyword == NULL, def_name(sym->s_def));
424 
425           if (sym->s_def_pos.p_file != NULL)
426                     debug_printf(" defined-at=%s:%d",
427                         sym->s_def_pos.p_file, sym->s_def_pos.p_line);
428           if (sym->s_set_pos.p_file != NULL)
429                     debug_printf(" set-at=%s:%d",
430                         sym->s_set_pos.p_file, sym->s_set_pos.p_line);
431           if (sym->s_use_pos.p_file != NULL)
432                     debug_printf(" used-at=%s:%d",
433                         sym->s_use_pos.p_file, sym->s_use_pos.p_line);
434 
435           if (sym->s_type != NULL && sym->s_type->t_is_enum)
436                     debug_printf(" value=%d", sym->u.s_enum_constant);
437           if (sym->s_type != NULL && sym->s_type->t_tspec == BOOL)
438                     debug_printf(" value=%s",
439                         sym->u.s_bool_constant ? "true" : "false");
440 
441           if (is_member(sym)) {
442                     struct_or_union *sou = sym->u.s_member.sm_containing_type;
443                     const char *tag = sou->sou_tag->s_name;
444                     const sym_t *def = sou->sou_first_typedef;
445                     if (tag == unnamed && def != NULL)
446                               debug_printf(" sou='typedef %s'", def->s_name);
447                     else
448                               debug_printf(" sou='%s'", tag);
449           }
450 
451           if (sym->s_keyword != NULL) {
452                     int t = sym->u.s_keyword.sk_token;
453                     if (t == T_TYPE || t == T_STRUCT_OR_UNION)
454                               debug_printf(" %s",
455                                   tspec_name(sym->u.s_keyword.u.sk_tspec));
456                     if (t == T_QUAL)
457                               debug_printf(" %s", type_qualifiers_string(
458                                   sym->u.s_keyword.u.sk_type_qualifier));
459                     if (t == T_FUNCTION_SPECIFIER)
460                               debug_printf(" %s", function_specifier_name(
461                                   sym->u.s_keyword.u.function_specifier));
462           }
463 
464           debug_word(sym->s_osdef && sym->u.s_old_style_params != NULL,
465               "old-style-params");
466 
467           if (strcmp(suffix, "\n") == 0)
468                     debug_printf("\n");
469           else
470                     debug_printf("%s", suffix);
471 }
472 
473 static void
debug_decl_level(const decl_level * dl)474 debug_decl_level(const decl_level *dl)
475 {
476 
477           debug_printf("kind=%s", decl_level_kind_name(dl->d_kind));
478           if (dl->d_scl != NO_SCL)
479                     debug_printf(" %s", scl_name(dl->d_scl));
480           if (dl->d_type != NULL)
481                     debug_printf(" '%s'", type_name(dl->d_type));
482           else {
483                     if (dl->d_abstract_type != NO_TSPEC)
484                               debug_printf(" %s", tspec_name(dl->d_abstract_type));
485                     if (dl->d_complex_mod != NO_TSPEC)
486                               debug_printf(" %s", tspec_name(dl->d_complex_mod));
487                     if (dl->d_sign_mod != NO_TSPEC)
488                               debug_printf(" %s", tspec_name(dl->d_sign_mod));
489                     if (dl->d_rank_mod != NO_TSPEC)
490                               debug_printf(" %s", tspec_name(dl->d_rank_mod));
491           }
492           if (dl->d_redeclared_symbol != NULL)
493                     debug_sym(" redeclared=(", dl->d_redeclared_symbol, ")");
494           if (dl->d_sou_size_in_bits > 0)
495                     debug_printf(" size=%u", dl->d_sou_size_in_bits / CHAR_SIZE);
496           if (dl->d_sou_size_in_bits % CHAR_SIZE > 0)
497                     debug_printf("+%u", dl->d_sou_size_in_bits % CHAR_SIZE);
498           if (dl->d_sou_align > 0)
499                     debug_printf(" sou_align=%u", dl->d_sou_align);
500           if (dl->d_mem_align > 0)
501                     debug_printf(" mem_align=%u", dl->d_mem_align);
502 
503           debug_word(dl->d_qual.tq_const, "const");
504           debug_word(dl->d_qual.tq_restrict, "restrict");
505           debug_word(dl->d_qual.tq_volatile, "volatile");
506           debug_word(dl->d_qual.tq_atomic, "atomic");
507           debug_word(dl->d_inline, "inline");
508           debug_word(dl->d_multiple_storage_classes, "multiple_storage_classes");
509           debug_word(dl->d_invalid_type_combination, "invalid_type_combination");
510           debug_word(dl->d_nonempty_decl, "nonempty_decl");
511           debug_word(dl->d_no_type_specifier, "no_type_specifier");
512           debug_word(dl->d_asm, "asm");
513           debug_word(dl->d_packed, "packed");
514           debug_word(dl->d_used, "used");
515           debug_word(dl->d_noreturn, "noreturn");
516 
517           if (dl->d_tag_type != NULL)
518                     debug_printf(" tag_type='%s'", type_name(dl->d_tag_type));
519           for (const sym_t *p = dl->d_func_params; p != NULL; p = p->s_next)
520                     debug_sym(" param(", p, ")");
521           if (dl->d_func_def_pos.p_file != NULL)
522                     debug_printf(" func_def_pos=%s:%d:%d",
523                         dl->d_func_def_pos.p_file, dl->d_func_def_pos.p_line,
524                         dl->d_func_def_pos.p_uniq);
525           for (const sym_t *sym = dl->d_func_proto_syms;
526               sym != NULL; sym = sym->s_next)
527                     debug_sym(" func_proto_sym(", sym, ")");
528           debug_printf("\n");
529 }
530 
531 void
debug_dcs(void)532 debug_dcs(void)
533 {
534           debug_printf("dcs ");
535           debug_decl_level(dcs);
536 }
537 
538 void
debug_dcs_all(void)539 debug_dcs_all(void)
540 {
541           size_t i = 0;
542           for (const decl_level *dl = dcs; dl != NULL; dl = dl->d_enclosing) {
543                     debug_printf("dcs[%zu] ", i++);
544                     debug_decl_level(dl);
545           }
546 }
547 
548 static void
debug_token(const token * tok)549 debug_token(const token *tok)
550 {
551           switch (tok->kind) {
552           case TK_IDENTIFIER:
553                     debug_printf("%s", tok->u.identifier);
554                     break;
555           case TK_CONSTANT:;
556                     val_t c = tok->u.constant;
557                     tspec_t t = c.v_tspec;
558                     if (is_floating(t))
559                               debug_printf("%Lg", c.u.floating);
560                     else if (is_uinteger(t))
561                               debug_printf("%llu", (unsigned long long)c.u.integer);
562                     else if (is_integer(t))
563                               debug_printf("%lld", (long long)c.u.integer);
564                     else {
565                               lint_assert(t == BOOL);
566                               debug_printf("%s",
567                                   c.u.integer != 0 ? "true" : "false");
568                     }
569                     break;
570           case TK_STRING_LITERALS:
571                     debug_printf("%s", tok->u.string_literals.data);
572                     break;
573           case TK_PUNCTUATOR:
574                     debug_printf("%s", tok->u.punctuator);
575                     break;
576           }
577 }
578 
579 static void
debug_balanced_token_sequence(const balanced_token_sequence * seq)580 debug_balanced_token_sequence(const balanced_token_sequence *seq)
581 {
582           const char *sep = "";
583           for (size_t i = 0, n = seq->len; i < n; i++) {
584                     const balanced_token *tok = seq->tokens + i;
585                     if (tok->kind != '\0') {
586                               debug_printf("%s%c", sep, tok->kind);
587                               debug_balanced_token_sequence(&tok->u.tokens);
588                               debug_printf("%c", tok->kind == '(' ? ')'
589                                   : tok->kind == '[' ? ']' : '}');
590                     } else {
591                               debug_printf("%s", sep);
592                               debug_token(&tok->u.token);
593                     }
594                     sep = " ";
595           }
596 }
597 
598 void
debug_attribute_list(const attribute_list * list)599 debug_attribute_list(const attribute_list *list)
600 {
601           for (size_t i = 0, n = list->len; i < n; i++) {
602                     const attribute *attr = list->attrs + i;
603                     debug_printf("attribute [[");
604                     if (attr->prefix != NULL)
605                               debug_printf("%s::", attr->prefix);
606                     debug_printf("%s", attr->name);
607                     if (attr->arg != NULL) {
608                               debug_printf("(");
609                               debug_balanced_token_sequence(attr->arg);
610                               debug_printf(")");
611                     }
612                     debug_step("]]");
613           }
614 }
615 
616 #endif
617