]>
Commit | Line | Data |
---|---|---|
757bf1df | 1 | /* Hierarchical log messages for the analyzer. |
a945c346 | 2 | Copyright (C) 2014-2024 Free Software Foundation, Inc. |
757bf1df DM |
3 | Contributed by David Malcolm <dmalcolm@redhat.com>. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
24 | #include "toplev.h" /* for print_version */ | |
25 | #include "pretty-print.h" /* for print_version */ | |
26 | #include "diagnostic.h" | |
27 | #include "tree-diagnostic.h" | |
28 | ||
29 | #include "analyzer/analyzer-logging.h" | |
30 | ||
31 | #if ENABLE_ANALYZER | |
32 | ||
5253b3e6 | 33 | #if __GNUC__ >= 10 |
808f4dfe | 34 | #pragma GCC diagnostic ignored "-Wformat-diag" |
5253b3e6 | 35 | #endif |
808f4dfe | 36 | |
75038aa6 DM |
37 | namespace ana { |
38 | ||
757bf1df DM |
39 | /* Implementation of class logger. */ |
40 | ||
41 | /* ctor for logger. */ | |
42 | ||
43 | logger::logger (FILE *f_out, | |
44 | int, /* flags */ | |
45 | int /* verbosity */, | |
46 | const pretty_printer &reference_pp) : | |
47 | m_refcount (0), | |
48 | m_f_out (f_out), | |
49 | m_indent_level (0), | |
50 | m_log_refcount_changes (false), | |
51 | m_pp (reference_pp.clone ()) | |
52 | { | |
53 | pp_show_color (m_pp) = 0; | |
54 | pp_buffer (m_pp)->stream = f_out; | |
55 | ||
56 | /* %qE in logs for SSA_NAMEs should show the ssa names, rather than | |
57 | trying to prettify things by showing the underlying var. */ | |
58 | pp_format_decoder (m_pp) = default_tree_printer; | |
59 | ||
60 | /* Begin the log by writing the GCC version. */ | |
61 | print_version (f_out, "", false); | |
62 | } | |
63 | ||
64 | /* The destructor for logger, invoked via | |
65 | the decref method when the refcount hits zero. | |
66 | Note that we do not close the underlying FILE * (m_f_out). */ | |
67 | ||
68 | logger::~logger () | |
69 | { | |
70 | /* This should be the last message emitted. */ | |
71 | log ("%s", __PRETTY_FUNCTION__); | |
72 | gcc_assert (m_refcount == 0); | |
73 | delete m_pp; | |
74 | } | |
75 | ||
76 | /* Increment the reference count of the logger. */ | |
77 | ||
78 | void | |
79 | logger::incref (const char *reason) | |
80 | { | |
81 | m_refcount++; | |
82 | if (m_log_refcount_changes) | |
83 | log ("%s: reason: %s refcount now %i ", | |
84 | __PRETTY_FUNCTION__, reason, m_refcount); | |
85 | } | |
86 | ||
87 | /* Decrement the reference count of the logger, | |
88 | deleting it if nothing is referring to it. */ | |
89 | ||
90 | void | |
91 | logger::decref (const char *reason) | |
92 | { | |
93 | gcc_assert (m_refcount > 0); | |
94 | --m_refcount; | |
95 | if (m_log_refcount_changes) | |
96 | log ("%s: reason: %s refcount now %i", | |
97 | __PRETTY_FUNCTION__, reason, m_refcount); | |
98 | if (m_refcount == 0) | |
99 | delete this; | |
100 | } | |
101 | ||
102 | /* Write a formatted message to the log, by calling the log_va method. */ | |
103 | ||
104 | void | |
105 | logger::log (const char *fmt, ...) | |
106 | { | |
107 | va_list ap; | |
108 | va_start (ap, fmt); | |
109 | log_va (fmt, &ap); | |
110 | va_end (ap); | |
111 | } | |
112 | ||
113 | /* Write an indented line to the log file. | |
114 | ||
115 | We explicitly flush after each line: if something crashes the process, | |
116 | we want the logfile/stream to contain the most up-to-date hint about the | |
117 | last thing that was happening, without it being hidden in an in-process | |
118 | buffer. */ | |
119 | ||
120 | void | |
121 | logger::log_va (const char *fmt, va_list *ap) | |
122 | { | |
123 | start_log_line (); | |
124 | log_va_partial (fmt, ap); | |
125 | end_log_line (); | |
126 | } | |
127 | ||
128 | void | |
129 | logger::start_log_line () | |
130 | { | |
131 | for (int i = 0; i < m_indent_level; i++) | |
132 | fputc (' ', m_f_out); | |
133 | } | |
134 | ||
135 | void | |
136 | logger::log_partial (const char *fmt, ...) | |
137 | { | |
138 | va_list ap; | |
139 | va_start (ap, fmt); | |
140 | log_va_partial (fmt, &ap); | |
141 | va_end (ap); | |
142 | } | |
143 | ||
144 | void | |
145 | logger::log_va_partial (const char *fmt, va_list *ap) | |
146 | { | |
c44ca7c0 | 147 | text_info text (fmt, ap, 0); |
757bf1df DM |
148 | pp_format (m_pp, &text); |
149 | pp_output_formatted_text (m_pp); | |
150 | } | |
151 | ||
152 | void | |
153 | logger::end_log_line () | |
154 | { | |
155 | pp_flush (m_pp); | |
156 | pp_clear_output_area (m_pp); | |
157 | fprintf (m_f_out, "\n"); | |
158 | fflush (m_f_out); | |
159 | } | |
160 | ||
161 | /* Record the entry within a particular scope, indenting subsequent | |
162 | log lines accordingly. */ | |
163 | ||
164 | void | |
165 | logger::enter_scope (const char *scope_name) | |
166 | { | |
167 | log ("entering: %s", scope_name); | |
808f4dfe | 168 | inc_indent (); |
757bf1df DM |
169 | } |
170 | ||
171 | void | |
172 | logger::enter_scope (const char *scope_name, const char *fmt, va_list *ap) | |
173 | { | |
174 | start_log_line (); | |
175 | log_partial ("entering: %s: ", scope_name); | |
176 | log_va_partial (fmt, ap); | |
177 | end_log_line (); | |
178 | ||
808f4dfe | 179 | inc_indent (); |
757bf1df DM |
180 | } |
181 | ||
182 | ||
183 | /* Record the exit from a particular scope, restoring the indent level to | |
184 | before the scope was entered. */ | |
185 | ||
186 | void | |
187 | logger::exit_scope (const char *scope_name) | |
188 | { | |
189 | if (m_indent_level) | |
808f4dfe | 190 | dec_indent (); |
757bf1df DM |
191 | else |
192 | log ("(mismatching indentation)"); | |
193 | log ("exiting: %s", scope_name); | |
194 | } | |
195 | ||
196 | /* Implementation of class log_user. */ | |
197 | ||
198 | /* The constructor for log_user. */ | |
199 | ||
200 | log_user::log_user (logger *logger) : m_logger (logger) | |
201 | { | |
202 | if (m_logger) | |
203 | m_logger->incref("log_user ctor"); | |
204 | } | |
205 | ||
206 | /* The destructor for log_user. */ | |
207 | ||
208 | log_user::~log_user () | |
209 | { | |
210 | if (m_logger) | |
211 | m_logger->decref("log_user dtor"); | |
212 | } | |
213 | ||
214 | /* Set the logger for a log_user, managing the reference counts | |
215 | of the old and new logger (either of which might be NULL). */ | |
216 | ||
217 | void | |
218 | log_user::set_logger (logger *logger) | |
219 | { | |
220 | if (logger) | |
221 | logger->incref ("log_user::set_logger"); | |
222 | if (m_logger) | |
223 | m_logger->decref ("log_user::set_logger"); | |
224 | m_logger = logger; | |
225 | } | |
226 | ||
75038aa6 DM |
227 | } // namespace ana |
228 | ||
757bf1df | 229 | #endif /* #if ENABLE_ANALYZER */ |