1 /* Hierarchical log messages for the analyzer. 2 Copyright (C) 2014-2020 Free Software Foundation, Inc. 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 /* Adapted from jit-logging.h. */ 22 23 #ifndef ANALYZER_LOGGING_H 24 #define ANALYZER_LOGGING_H 25 26 namespace ana { 27 28 /* A logger encapsulates a logging stream: a way to send 29 lines of pertinent information to a FILE *. */ 30 31 class logger 32 { 33 public: 34 logger (FILE *f_out, int flags, int verbosity, const pretty_printer &reference_pp); 35 ~logger (); 36 37 void incref (const char *reason); 38 void decref (const char *reason); 39 40 void log (const char *fmt, ...) 41 ATTRIBUTE_GCC_DIAG(2, 3); 42 void log_va (const char *fmt, va_list *ap) 43 ATTRIBUTE_GCC_DIAG(2, 0); 44 void start_log_line (); 45 void log_partial (const char *fmt, ...) 46 ATTRIBUTE_GCC_DIAG(2, 3); 47 void log_va_partial (const char *fmt, va_list *ap) 48 ATTRIBUTE_GCC_DIAG(2, 0); 49 void end_log_line (); 50 51 void enter_scope (const char *scope_name); 52 void enter_scope (const char *scope_name, const char *fmt, va_list *ap) 53 ATTRIBUTE_GCC_DIAG(3, 0); 54 void exit_scope (const char *scope_name); 55 56 pretty_printer *get_printer () const { return m_pp; } 57 FILE *get_file () const { return m_f_out; } 58 59 private: 60 DISABLE_COPY_AND_ASSIGN (logger); 61 62 int m_refcount; 63 FILE *m_f_out; 64 int m_indent_level; 65 bool m_log_refcount_changes; 66 pretty_printer *m_pp; 67 }; 68 69 /* The class log_scope is an RAII-style class intended to make 70 it easy to notify a logger about entering and exiting the body of a 71 given function. */ 72 73 class log_scope 74 { 75 public: 76 log_scope (logger *logger, const char *name); 77 log_scope (logger *logger, const char *name, const char *fmt, ...) 78 ATTRIBUTE_GCC_DIAG(4, 5); 79 ~log_scope (); 80 81 private: 82 DISABLE_COPY_AND_ASSIGN (log_scope); 83 84 logger *m_logger; 85 const char *m_name; 86 }; 87 88 /* The constructor for log_scope. 89 90 The normal case is that the logger is NULL, in which case this should 91 be largely a no-op. 92 93 If we do have a logger, notify it that we're entering the given scope. 94 We also need to hold a reference on it, to avoid a use-after-free 95 when logging the cleanup of the owner of the logger. */ 96 97 inline 98 log_scope::log_scope (logger *logger, const char *name) : 99 m_logger (logger), 100 m_name (name) 101 { 102 if (m_logger) 103 { 104 m_logger->incref ("log_scope ctor"); 105 m_logger->enter_scope (m_name); 106 } 107 } 108 109 inline 110 log_scope::log_scope (logger *logger, const char *name, const char *fmt, ...): 111 m_logger (logger), 112 m_name (name) 113 { 114 if (m_logger) 115 { 116 m_logger->incref ("log_scope ctor"); 117 va_list ap; 118 va_start (ap, fmt); 119 m_logger->enter_scope (m_name, fmt, &ap); 120 va_end (ap); 121 } 122 } 123 124 125 /* The destructor for log_scope; essentially the opposite of 126 the constructor. */ 127 128 inline 129 log_scope::~log_scope () 130 { 131 if (m_logger) 132 { 133 m_logger->exit_scope (m_name); 134 m_logger->decref ("log_scope dtor"); 135 } 136 } 137 138 /* A log_user is something that potentially uses a logger (which could be NULL). 139 140 The log_user class keeps the reference-count of a logger up-to-date. */ 141 142 class log_user 143 { 144 public: 145 log_user (logger *logger); 146 ~log_user (); 147 148 logger * get_logger () const { return m_logger; } 149 void set_logger (logger * logger); 150 151 void log (const char *fmt, ...) const 152 ATTRIBUTE_GCC_DIAG(2, 3); 153 154 void start_log_line () const; 155 void end_log_line () const; 156 157 void enter_scope (const char *scope_name); 158 void exit_scope (const char *scope_name); 159 160 pretty_printer *get_logger_pp () const 161 { 162 gcc_assert (m_logger); 163 return m_logger->get_printer (); 164 } 165 166 FILE *get_logger_file () const 167 { 168 if (m_logger == NULL) 169 return NULL; 170 return m_logger->get_file (); 171 } 172 173 private: 174 DISABLE_COPY_AND_ASSIGN (log_user); 175 176 logger *m_logger; 177 }; 178 179 /* A shortcut for calling log from a log_user, handling the common 180 case where the underlying logger is NULL via a no-op. */ 181 182 inline void 183 log_user::log (const char *fmt, ...) const 184 { 185 if (m_logger) 186 { 187 va_list ap; 188 va_start (ap, fmt); 189 m_logger->log_va (fmt, &ap); 190 va_end (ap); 191 } 192 } 193 194 /* A shortcut for starting a log line from a log_user, 195 handling the common case where the underlying logger is NULL via 196 a no-op. */ 197 198 inline void 199 log_user::start_log_line () const 200 { 201 if (m_logger) 202 m_logger->start_log_line (); 203 } 204 205 /* A shortcut for ending a log line from a log_user, 206 handling the common case where the underlying logger is NULL via 207 a no-op. */ 208 209 inline void 210 log_user::end_log_line () const 211 { 212 if (m_logger) 213 m_logger->end_log_line (); 214 } 215 216 /* A shortcut for recording entry into a scope from a log_user, 217 handling the common case where the underlying logger is NULL via 218 a no-op. */ 219 220 inline void 221 log_user::enter_scope (const char *scope_name) 222 { 223 if (m_logger) 224 m_logger->enter_scope (scope_name); 225 } 226 227 /* A shortcut for recording exit from a scope from a log_user, 228 handling the common case where the underlying logger is NULL via 229 a no-op. */ 230 231 inline void 232 log_user::exit_scope (const char *scope_name) 233 { 234 if (m_logger) 235 m_logger->exit_scope (scope_name); 236 } 237 238 /* If the given logger is non-NULL, log entry/exit of this scope to 239 it, identifying it using __PRETTY_FUNCTION__. */ 240 241 #define LOG_SCOPE(LOGGER) \ 242 log_scope s (LOGGER, __PRETTY_FUNCTION__) 243 244 /* If the given logger is non-NULL, log entry/exit of this scope to 245 it, identifying it using __func__. */ 246 247 #define LOG_FUNC(LOGGER) \ 248 log_scope s (LOGGER, __func__) 249 250 #define LOG_FUNC_1(LOGGER, FMT, A0) \ 251 log_scope s (LOGGER, __func__, FMT, A0) 252 253 #define LOG_FUNC_2(LOGGER, FMT, A0, A1) \ 254 log_scope s (LOGGER, __func__, FMT, A0, A1) 255 256 #define LOG_FUNC_3(LOGGER, FMT, A0, A1, A2) \ 257 log_scope s (LOGGER, __func__, FMT, A0, A1, A2) 258 259 #define LOG_FUNC_4(LOGGER, FMT, A0, A1, A2, A3) \ 260 log_scope s (LOGGER, __func__, FMT, A0, A1, A2, A3) 261 262 } // namespace ana 263 264 #endif /* ANALYZER_LOGGING_H */ 265