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