| /* |
| * Copyright 2018 Google, Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Gabe Black |
| */ |
| |
| #include <fstream> |
| #include <map> |
| #include <sstream> |
| #include <string> |
| |
| #include "base/cprintf.hh" |
| #include "systemc/core/process.hh" |
| #include "systemc/core/scheduler.hh" |
| #include "systemc/ext/core/sc_main.hh" |
| #include "systemc/ext/utils/messages.hh" |
| #include "systemc/ext/utils/sc_report_handler.hh" |
| #include "systemc/utils/report.hh" |
| |
| namespace sc_core |
| { |
| |
| namespace |
| { |
| |
| std::unique_ptr<std::string> logFileName; |
| std::unique_ptr<std::ofstream> logFile; |
| |
| } // anonymous namespace |
| |
| void |
| sc_report_handler::report(sc_severity severity, const char *msg_type, |
| const char *msg, const char *file, int line) |
| { |
| report(severity, msg_type, msg, SC_MEDIUM, file, line); |
| } |
| |
| void |
| sc_report_handler::report(sc_severity severity, const char *msg_type, |
| const char *msg, int verbosity, const char *file, |
| int line) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| if (severity == SC_INFO && verbosity > sc_gem5::reportVerbosityLevel) |
| return; |
| |
| sc_gem5::ReportSevInfo &sevInfo = sc_gem5::reportSevInfos[severity]; |
| sc_gem5::ReportMsgInfo &msgInfo = sc_gem5::reportMsgInfoMap()[msg_type]; |
| |
| sevInfo.count++; |
| msgInfo.count++; |
| msgInfo.sevCounts[severity]++; |
| |
| sc_actions actions = SC_UNSPECIFIED; |
| if (msgInfo.sevActions[severity] != SC_UNSPECIFIED) |
| actions = msgInfo.sevActions[severity]; |
| else if (msgInfo.actions != SC_UNSPECIFIED) |
| actions = msgInfo.actions; |
| else if (sevInfo.actions != SC_UNSPECIFIED) |
| actions = sevInfo.actions; |
| |
| actions &= ~sc_gem5::reportSuppressedActions; |
| actions |= sc_gem5::reportForcedActions; |
| |
| msgInfo.checkLimits(severity, actions); |
| sevInfo.checkLimit(actions); |
| |
| ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); |
| sc_report report(severity, msg_type, msg, verbosity, file, line, |
| sc_time::from_value(::sc_gem5::scheduler.getCurTick()), |
| current ? current->name() : nullptr, msgInfo.id); |
| |
| if (actions & SC_CACHE_REPORT) { |
| if (current) { |
| current->lastReport(&report); |
| } else { |
| sc_gem5::globalReportCache = |
| std::unique_ptr<sc_report>(new sc_report(report)); |
| } |
| } |
| |
| sc_gem5::reportHandlerProc(report, actions); |
| } |
| |
| void |
| sc_report_handler::report(sc_severity severity, int id, const char *msg, |
| const char *file, int line) |
| { |
| std::string &msg_type = sc_gem5::reportIdToMsgMap()[id]; |
| |
| if (sc_gem5::reportWarningsAsErrors && severity == SC_WARNING) |
| severity = SC_ERROR; |
| |
| report(severity, msg_type.c_str(), msg, file, line); |
| } |
| |
| sc_actions |
| sc_report_handler::set_actions(sc_severity severity, sc_actions actions) |
| { |
| sc_gem5::ReportSevInfo &info = sc_gem5::reportSevInfos[severity]; |
| sc_actions previous = info.actions; |
| info.actions = actions; |
| return previous; |
| } |
| |
| sc_actions |
| sc_report_handler::set_actions(const char *msg_type, sc_actions actions) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; |
| sc_actions previous = info.actions; |
| info.actions = actions; |
| return previous; |
| } |
| |
| sc_actions |
| sc_report_handler::set_actions( |
| const char *msg_type, sc_severity severity, sc_actions actions) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; |
| sc_actions previous = info.sevActions[severity]; |
| info.sevActions[severity] = actions; |
| return previous; |
| } |
| |
| int |
| sc_report_handler::stop_after(sc_severity severity, int limit) |
| { |
| sc_gem5::ReportSevInfo &info = sc_gem5::reportSevInfos[severity]; |
| int previous = info.limit; |
| info.limit = limit; |
| return previous; |
| } |
| |
| int |
| sc_report_handler::stop_after(const char *msg_type, int limit) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; |
| int previous = info.limit; |
| info.limit = limit; |
| return previous; |
| } |
| |
| int |
| sc_report_handler::stop_after( |
| const char *msg_type, sc_severity severity, int limit) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; |
| int previous = info.sevLimits[severity]; |
| info.sevLimits[severity] = limit; |
| return previous; |
| } |
| |
| int |
| sc_report_handler::get_count(sc_severity severity) |
| { |
| return sc_gem5::reportSevInfos[severity].count; |
| } |
| |
| int |
| sc_report_handler::get_count(const char *msg_type) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| return sc_gem5::reportMsgInfoMap()[msg_type].count; |
| } |
| |
| int |
| sc_report_handler::get_count(const char *msg_type, sc_severity severity) |
| { |
| if (!msg_type) |
| msg_type = SC_ID_UNKNOWN_ERROR_; |
| |
| return sc_gem5::reportMsgInfoMap()[msg_type].sevCounts[severity]; |
| } |
| |
| int |
| sc_report_handler::set_verbosity_level(int vl) |
| { |
| int previous = sc_gem5::reportVerbosityLevel; |
| sc_gem5::reportVerbosityLevel = vl; |
| return previous; |
| } |
| |
| int |
| sc_report_handler::get_verbosity_level() |
| { |
| return sc_gem5::reportVerbosityLevel; |
| } |
| |
| |
| sc_actions |
| sc_report_handler::suppress(sc_actions actions) |
| { |
| sc_actions previous = sc_gem5::reportSuppressedActions; |
| sc_gem5::reportSuppressedActions = actions; |
| return previous; |
| } |
| |
| sc_actions |
| sc_report_handler::suppress() |
| { |
| return suppress(SC_UNSPECIFIED); |
| } |
| |
| sc_actions |
| sc_report_handler::force(sc_actions actions) |
| { |
| sc_actions previous = sc_gem5::reportForcedActions; |
| sc_gem5::reportForcedActions = actions; |
| return previous; |
| } |
| |
| sc_actions |
| sc_report_handler::force() |
| { |
| return force(SC_UNSPECIFIED); |
| } |
| |
| |
| sc_actions |
| sc_report_handler::set_catch_actions(sc_actions actions) |
| { |
| sc_actions previous = sc_gem5::reportCatchActions; |
| sc_gem5::reportCatchActions = actions; |
| return previous; |
| } |
| |
| sc_actions |
| sc_report_handler::get_catch_actions() |
| { |
| return sc_gem5::reportCatchActions; |
| } |
| |
| |
| void |
| sc_report_handler::set_handler(sc_report_handler_proc proc) |
| { |
| sc_gem5::reportHandlerProc = proc; |
| } |
| |
| void |
| sc_report_handler::default_handler( |
| const sc_report &report, const sc_actions &actions) |
| { |
| if (actions & SC_DISPLAY) |
| cprintf("\n%s\n", sc_report_compose_message(report)); |
| |
| if ((actions & SC_LOG) && logFile) { |
| ccprintf(*logFile, "%s: %s\n", report.get_time().to_string(), |
| sc_report_compose_message(report)); |
| } |
| if (actions & SC_STOP) { |
| sc_stop_here(report.get_msg_type(), report.get_severity()); |
| sc_stop(); |
| } |
| if (actions & SC_INTERRUPT) |
| sc_interrupt_here(report.get_msg_type(), report.get_severity()); |
| if (actions & SC_ABORT) |
| sc_abort(); |
| if (actions & SC_THROW) { |
| ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); |
| if (current) |
| current->isUnwinding(false); |
| throw report; |
| } |
| } |
| |
| sc_actions |
| sc_report_handler::get_new_action_id() |
| { |
| static sc_actions maxAction = SC_ABORT; |
| maxAction = maxAction << 1; |
| return maxAction; |
| } |
| |
| sc_report * |
| sc_report_handler::get_cached_report() |
| { |
| ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); |
| if (current) |
| return current->lastReport(); |
| return ::sc_gem5::globalReportCache.get(); |
| } |
| |
| void |
| sc_report_handler::clear_cached_report() |
| { |
| ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); |
| if (current) { |
| current->lastReport(nullptr); |
| } else { |
| ::sc_gem5::globalReportCache = nullptr; |
| } |
| } |
| |
| bool |
| sc_report_handler::set_log_file_name(const char *new_name) |
| { |
| if (!new_name) { |
| logFile = nullptr; |
| logFileName = nullptr; |
| return false; |
| } else { |
| if (logFileName) |
| return false; |
| logFileName = std::unique_ptr<std::string>(new std::string(new_name)); |
| logFile = std::unique_ptr<std::ofstream>(new std::ofstream(new_name)); |
| return true; |
| } |
| } |
| |
| const char * |
| sc_report_handler::get_log_file_name() |
| { |
| if (!logFileName) |
| return nullptr; |
| else |
| return logFileName->c_str(); |
| } |
| |
| void |
| sc_interrupt_here(const char *msg_type, sc_severity) |
| { |
| // Purposefully empty, for setting breakpoints supposedly. |
| } |
| |
| void |
| sc_stop_here(const char *msg_type, sc_severity) |
| { |
| // Purposefully empty, for setting breakpoints supposedly. |
| } |
| |
| const std::string |
| sc_report_compose_message(const sc_report &report) |
| { |
| std::ostringstream str; |
| |
| const char *sevName = sc_gem5::reportSeverityNames[report.get_severity()]; |
| int id = report.get_id(); |
| |
| str << sevName << ": "; |
| if (id >= 0) { |
| ccprintf(str, "(%c%d) ", sevName[0], id); |
| } |
| str << report.get_msg_type(); |
| |
| const char *msg = report.get_msg(); |
| if (msg && msg[0]) |
| str << ": " << msg; |
| |
| if (report.get_severity() > SC_INFO) { |
| ccprintf(str, "\nIn file: %s:%d", report.get_file_name(), |
| report.get_line_number()); |
| |
| ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); |
| const char *name = report.get_process_name(); |
| if (current && sc_is_running() && name) { |
| ccprintf(str, "\nIn process: %s @ %s", name, |
| report.get_time().to_string()); |
| } |
| } |
| |
| return str.str(); |
| } |
| |
| bool |
| sc_report_close_default_log() |
| { |
| if (logFile) { |
| logFile = nullptr; |
| logFileName = nullptr; |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace sc_core |