1/* 2 * Copyright (c) 2014, 2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2002-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Nathan Binkert 41 * Dave Greene 42 * Andreas Sandberg 43 */ 44 45#ifndef __BASE_LOGGING_HH__ 46#define __BASE_LOGGING_HH__ 47 48#include <cassert>
|
49#include <cstdlib>
50#include <iostream>
|
49#include <sstream> |
50#include <utility> 51 52#include "base/compiler.hh" 53#include "base/cprintf.hh" 54
|
56#if defined(__SUNPRO_CC)
57#define __FUNCTION__ "how to fix me?"
58#endif
59
|
55class Logger 56{ 57 public:
|
58 59 // Get a Logger for the specified type of message. 60 static Logger &getPanic(); 61 static Logger &getFatal(); 62 static Logger &getWarn(); 63 static Logger &getInfo(); 64 static Logger &getHack(); 65 |
66 enum LogLevel {
|
64 PANIC = 0,
65 FATAL,
66 WARN,
67 INFO,
68 HACK,
|
67 PANIC, FATAL, WARN, INFO, HACK, |
68 NUM_LOG_LEVELS, 69 }; 70
|
72 /**
73 * Set the active log level.
74 *
75 * All levels that are lower or equal to the selected log level
76 * will be activated.
77 *
78 * @param ll Maximum log level to print
79 */
80 static void setLevel(LogLevel ll);
|
71 static void 72 setLevel(LogLevel ll) 73 { 74 getPanic().enabled = (ll >= PANIC); 75 getFatal().enabled = (ll >= FATAL); 76 getWarn().enabled = (ll >= WARN); 77 getInfo().enabled = (ll >= INFO); 78 getHack().enabled = (ll >= HACK); 79 } |
80
|
82 /**
83 * Get a Logger corresponding to a specific log level
84 *
85 * @param ll Log level to access
86 * @return Reference to the requested logger
87 */
88 static Logger &get(LogLevel ll);
|
81 struct Loc 82 { 83 Loc(const char *file, int line) : file(file), line(line) {} 84 const char *file; 85 int line; 86 }; |
87
|
90 public:
91 Logger(std::ostream &stream, const char *prefix);
|
88 Logger(const char *prefix) : enabled(true), prefix(prefix) 89 { 90 assert(prefix); 91 } 92 |
93 virtual ~Logger() {}; 94
|
94 template<typename ...Args> void
95 print(const char *func, const char *file, int line,
96 const char *format, const Args &...args)
|
95 void 96 print(const Loc &loc, const std::string &str) |
97 {
|
98 std::stringstream ss; 99 ss << prefix << str; 100 if (str.length() && str.back() != '\n' && str.back() != '\r') 101 ss << std::endl; |
102 if (!enabled) 103 return;
|
104 log(loc, ss.str()); 105 } |
106
|
101 if (prefix)
102 stream << prefix << ": ";
103 ccprintf(stream, format, args...);
104
105 printEpilogue(func, file, line, format);
|
107 template<typename ...Args> void 108 print(const Loc &loc, const char *format, const Args &...args) 109 { 110 std::stringstream ss; 111 ccprintf(ss, format, args...); 112 print(loc, ss.str()); |
113 } 114 115 template<typename ...Args> void
|
109 print(const char *func, const char *file, int line,
110 const std::string &format, const Args &...args)
|
116 print(const Loc &loc, const std::string &format, const Args &...args) |
117 {
|
112 print(func, file, line, format.c_str(), args...);
|
118 print(loc, format.c_str(), args...); |
119 } 120
|
115 protected:
116 virtual void printEpilogue(const char *func, const char *file, int line,
117 const char *format);
|
121 // This helper is necessary since noreturn isn't inherited by virtual 122 // functions, and gcc will get mad if a function calls panic and then 123 // doesn't return. 124 void exit_helper() M5_ATTR_NORETURN { exit(); ::abort(); } |
125
|
119 public:
|
126 protected: |
127 bool enabled;
|
121 bool verbose;
|
128
|
123 protected:
124 std::ostream &stream;
|
129 virtual void log(const Loc &loc, std::string s) = 0; 130 virtual void exit() { /* Fall through to the abort in exit_helper. */ } 131 |
132 const char *prefix; 133}; 134
|
128#define exit_message(logger, code, ...) \
129 do { \
130 logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
131 if (code < 0) \
132 ::abort(); \
133 else \
134 ::exit(code); \
|
135 136#define base_message(logger, ...) \ 137 logger.print(::Logger::Loc(__FILE__, __LINE__), __VA_ARGS__) 138 139/* 140 * Only print the message the first time this expression is 141 * encountered. i.e. This doesn't check the string itself and 142 * prevent duplicate strings, this prevents the statement from 143 * happening more than once. So, even if the arguments change and that 144 * would have resulted in a different message thoes messages would be 145 * supressed. 146 */ 147#define base_message_once(...) do { \ 148 static bool once = false; \ 149 if (!once) { \ 150 base_message(__VA_ARGS__); \ 151 once = true; \ 152 } \ |
153 } while (0) 154
|
137//
138// This implements a cprintf based panic() function. panic() should
139// be called when something happens that should never ever happen
140// regardless of what the user does (i.e., an acutal m5 bug). panic()
141// calls abort which can dump core or enter the debugger.
142//
143//
144#define panic(...) exit_message(::Logger::get(::Logger::PANIC), -1, \
145 __VA_ARGS__)
|
155#define exit_message(logger, ...) \ 156 do { \ 157 base_message(logger, __VA_ARGS__); \ 158 logger.exit_helper(); \ 159 } while (0) |
160
|
147//
148// This implements a cprintf based fatal() function. fatal() should
149// be called when the simulation cannot continue due to some condition
150// that is the user's fault (bad configuration, invalid arguments,
151// etc.) and not a simulator bug. fatal() calls abort() like
152// panic() does.
153//
154#define fatal(...) exit_message(::Logger::get(::Logger::FATAL), 1, \
155 __VA_ARGS__)
|
161/** 162 * This implements a cprintf based panic() function. panic() should 163 * be called when something happens that should never ever happen 164 * regardless of what the user does (i.e., an acutal m5 bug). panic() 165 * might call abort which can dump core or enter the debugger. 166 */ 167#define panic(...) exit_message(::Logger::getPanic(), __VA_ARGS__) |
168 169/**
|
170 * This implements a cprintf based fatal() function. fatal() should 171 * be called when the simulation cannot continue due to some condition 172 * that is the user's fault (bad configuration, invalid arguments, 173 * etc.) and not a simulator bug. fatal() might call exit, unlike panic(). 174 */ 175#define fatal(...) exit_message(::Logger::getFatal(), __VA_ARGS__) 176 177/** |
178 * Conditional panic macro that checks the supplied condition and only panics 179 * if the condition is true and allows the programmer to specify diagnostic 180 * printout. Useful to replace if + panic, or if + print + assert, etc. 181 * 182 * @param cond Condition that is checked; if true -> panic 183 * @param ... Printf-based format string with arguments, extends printout. 184 */ 185#define panic_if(cond, ...) \ 186 do { \ 187 if ((cond)) { \ 188 panic("panic condition " # cond " occurred: %s", \ 189 csprintf(__VA_ARGS__)); \ 190 } \ 191 } while (0) 192 193 194/** 195 * Conditional fatal macro that checks the supplied condition and only causes a 196 * fatal error if the condition is true and allows the programmer to specify 197 * diagnostic printout. Useful to replace if + fatal, or if + print + assert, 198 * etc. 199 * 200 * @param cond Condition that is checked; if true -> fatal 201 * @param ... Printf-based format string with arguments, extends printout. 202 */ 203#define fatal_if(cond, ...) \ 204 do { \ 205 if ((cond)) { \ 206 fatal("fatal condition " # cond " occurred: %s", \ 207 csprintf(__VA_ARGS__)); \ 208 } \ 209 } while (0) 210 211
|
192#define base_message(logger, ...) \
193 logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
|
212#define warn(...) base_message(::Logger::getWarn(), __VA_ARGS__) 213#define inform(...) base_message(::Logger::getInfo(), __VA_ARGS__) 214#define hack(...) base_message(::Logger::getHack(), __VA_ARGS__) |
215
|
195// Only print the message the first time this expression is
196// encountered. i.e. This doesn't check the string itself and
197// prevent duplicate strings, this prevents the statement from
198// happening more than once. So, even if the arguments change and that
199// would have resulted in a different message thoes messages would be
200// supressed.
201#define base_message_once(...) do { \
202 static bool once = false; \
203 if (!once) { \
204 base_message(__VA_ARGS__); \
205 once = true; \
206 } \
207 } while (0)
|
216#define warn_once(...) base_message_once(::Logger::getWarn(), __VA_ARGS__) 217#define inform_once(...) base_message_once(::Logger::getInfo(), __VA_ARGS__) 218#define hack_once(...) base_message_once(::Logger::getHack(), __VA_ARGS__) |
219
|
209
210#define warn(...) \
211 base_message(::Logger::get(::Logger::WARN), __VA_ARGS__)
212#define inform(...) \
213 base_message(::Logger::get(::Logger::INFO), __VA_ARGS__)
214#define hack(...) \
215 base_message(::Logger::get(::Logger::HACK), __VA_ARGS__)
216
217#define warn_once(...) \
218 base_message_once(::Logger::get(::Logger::WARN), __VA_ARGS__)
219#define inform_once(...) \
220 base_message_once(::Logger::get(::Logger::INFO), __VA_ARGS__)
221#define hack_once(...) \
222 base_message_once(::Logger::get(::Logger::HACK), __VA_ARGS__)
223
|
220/** 221 * Conditional warning macro that checks the supplied condition and 222 * only prints a warning if the condition is true. Useful to replace 223 * if + warn. 224 * 225 * @param cond Condition that is checked; if true -> warn 226 * @param ... Printf-based format string with arguments, extends printout. 227 */ 228#define warn_if(cond, ...) \ 229 do { \ 230 if ((cond)) \ 231 warn(__VA_ARGS__); \ 232 } while (0) 233 234/** 235 * The chatty assert macro will function like a normal assert, but will allow 236 * the specification of additional, helpful material to aid debugging why the 237 * assertion actually failed. Like the normal assertion, the chatty_assert 238 * will not be active in fast builds. 239 * 240 * @param cond Condition that is checked; if false -> assert 241 * @param ... Printf-based format string with arguments, extends printout. 242 */ 243#ifdef NDEBUG 244#define chatty_assert(cond, ...) 245#else //!NDEBUG 246#define chatty_assert(cond, ...) \ 247 do { \ 248 if (!(cond)) \ 249 panic("assert(" # cond ") failed: %s", csprintf(__VA_ARGS__)); \ 250 } while (0) 251#endif // NDEBUG 252#endif // __BASE_LOGGING_HH__
|