112334Sgabeblack@google.com/* 214004Stiago.muck@arm.com * Copyright (c) 2014, 2017, 2019 ARM Limited 312334Sgabeblack@google.com * All rights reserved 412334Sgabeblack@google.com * 512334Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612334Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712334Sgabeblack@google.com * property including but not limited to intellectual property relating 812334Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912334Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012334Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112334Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212334Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312334Sgabeblack@google.com * 1412334Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 1512334Sgabeblack@google.com * All rights reserved. 1612334Sgabeblack@google.com * 1712334Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1812334Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1912334Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2012334Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2112334Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2212334Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2312334Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2412334Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2512334Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2612334Sgabeblack@google.com * this software without specific prior written permission. 2712334Sgabeblack@google.com * 2812334Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912334Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012334Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112334Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212334Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312334Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412334Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512334Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612334Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712334Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812334Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912334Sgabeblack@google.com * 4012334Sgabeblack@google.com * Authors: Nathan Binkert 4112334Sgabeblack@google.com * Dave Greene 4212334Sgabeblack@google.com * Andreas Sandberg 4312334Sgabeblack@google.com */ 4412334Sgabeblack@google.com 4512334Sgabeblack@google.com#ifndef __BASE_LOGGING_HH__ 4612334Sgabeblack@google.com#define __BASE_LOGGING_HH__ 4712334Sgabeblack@google.com 4812334Sgabeblack@google.com#include <cassert> 4912375Sgabeblack@google.com#include <sstream> 5012334Sgabeblack@google.com#include <utility> 5112334Sgabeblack@google.com 5212334Sgabeblack@google.com#include "base/compiler.hh" 5312334Sgabeblack@google.com#include "base/cprintf.hh" 5412334Sgabeblack@google.com 5512334Sgabeblack@google.comclass Logger 5612334Sgabeblack@google.com{ 5712334Sgabeblack@google.com public: 5812375Sgabeblack@google.com 5912375Sgabeblack@google.com // Get a Logger for the specified type of message. 6012375Sgabeblack@google.com static Logger &getPanic(); 6112375Sgabeblack@google.com static Logger &getFatal(); 6212375Sgabeblack@google.com static Logger &getWarn(); 6312375Sgabeblack@google.com static Logger &getInfo(); 6412375Sgabeblack@google.com static Logger &getHack(); 6512375Sgabeblack@google.com 6612334Sgabeblack@google.com enum LogLevel { 6712375Sgabeblack@google.com PANIC, FATAL, WARN, INFO, HACK, 6812334Sgabeblack@google.com NUM_LOG_LEVELS, 6912334Sgabeblack@google.com }; 7012334Sgabeblack@google.com 7112375Sgabeblack@google.com static void 7212375Sgabeblack@google.com setLevel(LogLevel ll) 7312375Sgabeblack@google.com { 7412375Sgabeblack@google.com getPanic().enabled = (ll >= PANIC); 7512375Sgabeblack@google.com getFatal().enabled = (ll >= FATAL); 7612375Sgabeblack@google.com getWarn().enabled = (ll >= WARN); 7712375Sgabeblack@google.com getInfo().enabled = (ll >= INFO); 7812375Sgabeblack@google.com getHack().enabled = (ll >= HACK); 7912375Sgabeblack@google.com } 8012334Sgabeblack@google.com 8112375Sgabeblack@google.com struct Loc 8212375Sgabeblack@google.com { 8312375Sgabeblack@google.com Loc(const char *file, int line) : file(file), line(line) {} 8412375Sgabeblack@google.com const char *file; 8512375Sgabeblack@google.com int line; 8612375Sgabeblack@google.com }; 8712334Sgabeblack@google.com 8812375Sgabeblack@google.com Logger(const char *prefix) : enabled(true), prefix(prefix) 8912375Sgabeblack@google.com { 9012375Sgabeblack@google.com assert(prefix); 9112375Sgabeblack@google.com } 9212375Sgabeblack@google.com 9312334Sgabeblack@google.com virtual ~Logger() {}; 9412334Sgabeblack@google.com 9512375Sgabeblack@google.com void 9612375Sgabeblack@google.com print(const Loc &loc, const std::string &str) 9712334Sgabeblack@google.com { 9812375Sgabeblack@google.com std::stringstream ss; 9912375Sgabeblack@google.com ss << prefix << str; 10012375Sgabeblack@google.com if (str.length() && str.back() != '\n' && str.back() != '\r') 10112375Sgabeblack@google.com ss << std::endl; 10212334Sgabeblack@google.com if (!enabled) 10312334Sgabeblack@google.com return; 10412375Sgabeblack@google.com log(loc, ss.str()); 10512334Sgabeblack@google.com } 10612334Sgabeblack@google.com 10712334Sgabeblack@google.com template<typename ...Args> void 10812375Sgabeblack@google.com print(const Loc &loc, const char *format, const Args &...args) 10912334Sgabeblack@google.com { 11012375Sgabeblack@google.com std::stringstream ss; 11112375Sgabeblack@google.com ccprintf(ss, format, args...); 11212375Sgabeblack@google.com print(loc, ss.str()); 11312334Sgabeblack@google.com } 11412334Sgabeblack@google.com 11512375Sgabeblack@google.com template<typename ...Args> void 11612375Sgabeblack@google.com print(const Loc &loc, const std::string &format, const Args &...args) 11712375Sgabeblack@google.com { 11812375Sgabeblack@google.com print(loc, format.c_str(), args...); 11912375Sgabeblack@google.com } 12012334Sgabeblack@google.com 12112375Sgabeblack@google.com // This helper is necessary since noreturn isn't inherited by virtual 12212375Sgabeblack@google.com // functions, and gcc will get mad if a function calls panic and then 12312375Sgabeblack@google.com // doesn't return. 12412375Sgabeblack@google.com void exit_helper() M5_ATTR_NORETURN { exit(); ::abort(); } 12512334Sgabeblack@google.com 12612334Sgabeblack@google.com protected: 12712375Sgabeblack@google.com bool enabled; 12812375Sgabeblack@google.com 12912375Sgabeblack@google.com virtual void log(const Loc &loc, std::string s) = 0; 13012375Sgabeblack@google.com virtual void exit() { /* Fall through to the abort in exit_helper. */ } 13112375Sgabeblack@google.com 13212334Sgabeblack@google.com const char *prefix; 13312334Sgabeblack@google.com}; 13412334Sgabeblack@google.com 13512375Sgabeblack@google.com 13612375Sgabeblack@google.com#define base_message(logger, ...) \ 13712375Sgabeblack@google.com logger.print(::Logger::Loc(__FILE__, __LINE__), __VA_ARGS__) 13812375Sgabeblack@google.com 13912375Sgabeblack@google.com/* 14012375Sgabeblack@google.com * Only print the message the first time this expression is 14112375Sgabeblack@google.com * encountered. i.e. This doesn't check the string itself and 14212375Sgabeblack@google.com * prevent duplicate strings, this prevents the statement from 14312375Sgabeblack@google.com * happening more than once. So, even if the arguments change and that 14412375Sgabeblack@google.com * would have resulted in a different message thoes messages would be 14512375Sgabeblack@google.com * supressed. 14612375Sgabeblack@google.com */ 14712375Sgabeblack@google.com#define base_message_once(...) do { \ 14812375Sgabeblack@google.com static bool once = false; \ 14912375Sgabeblack@google.com if (!once) { \ 15012375Sgabeblack@google.com base_message(__VA_ARGS__); \ 15112375Sgabeblack@google.com once = true; \ 15212375Sgabeblack@google.com } \ 15312334Sgabeblack@google.com } while (0) 15412334Sgabeblack@google.com 15512375Sgabeblack@google.com#define exit_message(logger, ...) \ 15612375Sgabeblack@google.com do { \ 15712375Sgabeblack@google.com base_message(logger, __VA_ARGS__); \ 15812375Sgabeblack@google.com logger.exit_helper(); \ 15912375Sgabeblack@google.com } while (0) 16012334Sgabeblack@google.com 16112375Sgabeblack@google.com/** 16212375Sgabeblack@google.com * This implements a cprintf based panic() function. panic() should 16312375Sgabeblack@google.com * be called when something happens that should never ever happen 16412375Sgabeblack@google.com * regardless of what the user does (i.e., an acutal m5 bug). panic() 16512375Sgabeblack@google.com * might call abort which can dump core or enter the debugger. 16612375Sgabeblack@google.com */ 16712375Sgabeblack@google.com#define panic(...) exit_message(::Logger::getPanic(), __VA_ARGS__) 16812375Sgabeblack@google.com 16912375Sgabeblack@google.com/** 17012375Sgabeblack@google.com * This implements a cprintf based fatal() function. fatal() should 17112375Sgabeblack@google.com * be called when the simulation cannot continue due to some condition 17212375Sgabeblack@google.com * that is the user's fault (bad configuration, invalid arguments, 17312375Sgabeblack@google.com * etc.) and not a simulator bug. fatal() might call exit, unlike panic(). 17412375Sgabeblack@google.com */ 17512375Sgabeblack@google.com#define fatal(...) exit_message(::Logger::getFatal(), __VA_ARGS__) 17612334Sgabeblack@google.com 17712334Sgabeblack@google.com/** 17812334Sgabeblack@google.com * Conditional panic macro that checks the supplied condition and only panics 17912334Sgabeblack@google.com * if the condition is true and allows the programmer to specify diagnostic 18012334Sgabeblack@google.com * printout. Useful to replace if + panic, or if + print + assert, etc. 18112334Sgabeblack@google.com * 18212334Sgabeblack@google.com * @param cond Condition that is checked; if true -> panic 18312334Sgabeblack@google.com * @param ... Printf-based format string with arguments, extends printout. 18412334Sgabeblack@google.com */ 18512334Sgabeblack@google.com#define panic_if(cond, ...) \ 18612334Sgabeblack@google.com do { \ 18712334Sgabeblack@google.com if ((cond)) { \ 18812334Sgabeblack@google.com panic("panic condition " # cond " occurred: %s", \ 18912334Sgabeblack@google.com csprintf(__VA_ARGS__)); \ 19012334Sgabeblack@google.com } \ 19112334Sgabeblack@google.com } while (0) 19212334Sgabeblack@google.com 19312334Sgabeblack@google.com 19412334Sgabeblack@google.com/** 19512334Sgabeblack@google.com * Conditional fatal macro that checks the supplied condition and only causes a 19612334Sgabeblack@google.com * fatal error if the condition is true and allows the programmer to specify 19712334Sgabeblack@google.com * diagnostic printout. Useful to replace if + fatal, or if + print + assert, 19812334Sgabeblack@google.com * etc. 19912334Sgabeblack@google.com * 20012334Sgabeblack@google.com * @param cond Condition that is checked; if true -> fatal 20112334Sgabeblack@google.com * @param ... Printf-based format string with arguments, extends printout. 20212334Sgabeblack@google.com */ 20312334Sgabeblack@google.com#define fatal_if(cond, ...) \ 20412334Sgabeblack@google.com do { \ 20512334Sgabeblack@google.com if ((cond)) { \ 20612334Sgabeblack@google.com fatal("fatal condition " # cond " occurred: %s", \ 20712334Sgabeblack@google.com csprintf(__VA_ARGS__)); \ 20812334Sgabeblack@google.com } \ 20912334Sgabeblack@google.com } while (0) 21012334Sgabeblack@google.com 21112334Sgabeblack@google.com 21212375Sgabeblack@google.com#define warn(...) base_message(::Logger::getWarn(), __VA_ARGS__) 21312375Sgabeblack@google.com#define inform(...) base_message(::Logger::getInfo(), __VA_ARGS__) 21412375Sgabeblack@google.com#define hack(...) base_message(::Logger::getHack(), __VA_ARGS__) 21512334Sgabeblack@google.com 21612375Sgabeblack@google.com#define warn_once(...) base_message_once(::Logger::getWarn(), __VA_ARGS__) 21712375Sgabeblack@google.com#define inform_once(...) base_message_once(::Logger::getInfo(), __VA_ARGS__) 21812375Sgabeblack@google.com#define hack_once(...) base_message_once(::Logger::getHack(), __VA_ARGS__) 21912334Sgabeblack@google.com 22012334Sgabeblack@google.com/** 22112334Sgabeblack@google.com * Conditional warning macro that checks the supplied condition and 22212334Sgabeblack@google.com * only prints a warning if the condition is true. Useful to replace 22312334Sgabeblack@google.com * if + warn. 22412334Sgabeblack@google.com * 22512334Sgabeblack@google.com * @param cond Condition that is checked; if true -> warn 22612334Sgabeblack@google.com * @param ... Printf-based format string with arguments, extends printout. 22712334Sgabeblack@google.com */ 22812334Sgabeblack@google.com#define warn_if(cond, ...) \ 22912334Sgabeblack@google.com do { \ 23012334Sgabeblack@google.com if ((cond)) \ 23112334Sgabeblack@google.com warn(__VA_ARGS__); \ 23212334Sgabeblack@google.com } while (0) 23312334Sgabeblack@google.com 23414004Stiago.muck@arm.com#define warn_if_once(cond, ...) \ 23514004Stiago.muck@arm.com do { \ 23614004Stiago.muck@arm.com if ((cond)) \ 23714004Stiago.muck@arm.com warn_once(__VA_ARGS__); \ 23814004Stiago.muck@arm.com } while (0) 23914004Stiago.muck@arm.com 24012334Sgabeblack@google.com/** 24112334Sgabeblack@google.com * The chatty assert macro will function like a normal assert, but will allow 24212334Sgabeblack@google.com * the specification of additional, helpful material to aid debugging why the 24312334Sgabeblack@google.com * assertion actually failed. Like the normal assertion, the chatty_assert 24412334Sgabeblack@google.com * will not be active in fast builds. 24512334Sgabeblack@google.com * 24612334Sgabeblack@google.com * @param cond Condition that is checked; if false -> assert 24712334Sgabeblack@google.com * @param ... Printf-based format string with arguments, extends printout. 24812334Sgabeblack@google.com */ 24912334Sgabeblack@google.com#ifdef NDEBUG 25012334Sgabeblack@google.com#define chatty_assert(cond, ...) 25112334Sgabeblack@google.com#else //!NDEBUG 25212334Sgabeblack@google.com#define chatty_assert(cond, ...) \ 25312334Sgabeblack@google.com do { \ 25412334Sgabeblack@google.com if (!(cond)) \ 25512334Sgabeblack@google.com panic("assert(" # cond ") failed: %s", csprintf(__VA_ARGS__)); \ 25612334Sgabeblack@google.com } while (0) 25712334Sgabeblack@google.com#endif // NDEBUG 25812334Sgabeblack@google.com#endif // __BASE_LOGGING_HH__ 259