1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include <fstream> 31#include <map> 32#include <sstream> 33#include <string> 34 35#include "base/cprintf.hh" 36#include "systemc/core/process.hh" 37#include "systemc/core/scheduler.hh" 38#include "systemc/ext/core/sc_main.hh" 39#include "systemc/ext/utils/messages.hh" 40#include "systemc/ext/utils/sc_report_handler.hh" 41#include "systemc/utils/report.hh" 42 43namespace sc_core 44{ 45 46namespace 47{ 48 49std::unique_ptr<std::string> logFileName; 50std::unique_ptr<std::ofstream> logFile; 51 52} // anonymous namespace 53 54void 55sc_report_handler::report(sc_severity severity, const char *msg_type, 56 const char *msg, const char *file, int line) 57{ 58 report(severity, msg_type, msg, SC_MEDIUM, file, line); 59} 60 61void 62sc_report_handler::report(sc_severity severity, const char *msg_type, 63 const char *msg, int verbosity, const char *file, 64 int line) 65{ 66 if (!msg_type) 67 msg_type = SC_ID_UNKNOWN_ERROR_; 68 69 if (severity == SC_INFO && verbosity > sc_gem5::reportVerbosityLevel) 70 return; 71 72 sc_gem5::ReportSevInfo &sevInfo = sc_gem5::reportSevInfos[severity]; 73 sc_gem5::ReportMsgInfo &msgInfo = sc_gem5::reportMsgInfoMap()[msg_type]; 74 75 sevInfo.count++; 76 msgInfo.count++; 77 msgInfo.sevCounts[severity]++; 78 79 sc_actions actions = SC_UNSPECIFIED; 80 if (msgInfo.sevActions[severity] != SC_UNSPECIFIED) 81 actions = msgInfo.sevActions[severity]; 82 else if (msgInfo.actions != SC_UNSPECIFIED) 83 actions = msgInfo.actions; 84 else if (sevInfo.actions != SC_UNSPECIFIED) 85 actions = sevInfo.actions; 86 87 actions &= ~sc_gem5::reportSuppressedActions; 88 actions |= sc_gem5::reportForcedActions; 89 90 msgInfo.checkLimits(severity, actions); 91 sevInfo.checkLimit(actions); 92 93 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 94 sc_report report(severity, msg_type, msg, verbosity, file, line, 95 sc_time::from_value(::sc_gem5::scheduler.getCurTick()), 96 current ? current->name() : nullptr, msgInfo.id); 97 98 if (actions & SC_CACHE_REPORT) { 99 if (current) { 100 current->lastReport(&report); 101 } else { 102 sc_gem5::globalReportCache = 103 std::unique_ptr<sc_report>(new sc_report(report)); 104 } 105 } 106 107 sc_gem5::reportHandlerProc(report, actions); 108} 109 110void 111sc_report_handler::report(sc_severity severity, int id, const char *msg, 112 const char *file, int line) 113{ 114 std::string &msg_type = sc_gem5::reportIdToMsgMap()[id]; 115 116 if (sc_gem5::reportWarningsAsErrors && severity == SC_WARNING) 117 severity = SC_ERROR; 118 119 report(severity, msg_type.c_str(), msg, file, line); 120} 121 122sc_actions 123sc_report_handler::set_actions(sc_severity severity, sc_actions actions) 124{ 125 sc_gem5::ReportSevInfo &info = sc_gem5::reportSevInfos[severity]; 126 sc_actions previous = info.actions; 127 info.actions = actions; 128 return previous; 129} 130 131sc_actions 132sc_report_handler::set_actions(const char *msg_type, sc_actions actions) 133{ 134 if (!msg_type) 135 msg_type = SC_ID_UNKNOWN_ERROR_; 136 137 sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; 138 sc_actions previous = info.actions; 139 info.actions = actions; 140 return previous; 141} 142 143sc_actions 144sc_report_handler::set_actions( 145 const char *msg_type, sc_severity severity, sc_actions actions) 146{ 147 if (!msg_type) 148 msg_type = SC_ID_UNKNOWN_ERROR_; 149 150 sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; 151 sc_actions previous = info.sevActions[severity]; 152 info.sevActions[severity] = actions; 153 return previous; 154} 155 156int 157sc_report_handler::stop_after(sc_severity severity, int limit) 158{ 159 sc_gem5::ReportSevInfo &info = sc_gem5::reportSevInfos[severity]; 160 int previous = info.limit; 161 info.limit = limit; 162 return previous; 163} 164 165int 166sc_report_handler::stop_after(const char *msg_type, int limit) 167{ 168 if (!msg_type) 169 msg_type = SC_ID_UNKNOWN_ERROR_; 170 171 sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; 172 int previous = info.limit; 173 info.limit = limit; 174 return previous; 175} 176 177int 178sc_report_handler::stop_after( 179 const char *msg_type, sc_severity severity, int limit) 180{ 181 if (!msg_type) 182 msg_type = SC_ID_UNKNOWN_ERROR_; 183 184 sc_gem5::ReportMsgInfo &info = sc_gem5::reportMsgInfoMap()[msg_type]; 185 int previous = info.sevLimits[severity]; 186 info.sevLimits[severity] = limit; 187 return previous; 188} 189 190int 191sc_report_handler::get_count(sc_severity severity) 192{ 193 return sc_gem5::reportSevInfos[severity].count; 194} 195 196int 197sc_report_handler::get_count(const char *msg_type) 198{ 199 if (!msg_type) 200 msg_type = SC_ID_UNKNOWN_ERROR_; 201 202 return sc_gem5::reportMsgInfoMap()[msg_type].count; 203} 204 205int 206sc_report_handler::get_count(const char *msg_type, sc_severity severity) 207{ 208 if (!msg_type) 209 msg_type = SC_ID_UNKNOWN_ERROR_; 210 211 return sc_gem5::reportMsgInfoMap()[msg_type].sevCounts[severity]; 212} 213 214int 215sc_report_handler::set_verbosity_level(int vl) 216{ 217 int previous = sc_gem5::reportVerbosityLevel; 218 sc_gem5::reportVerbosityLevel = vl; 219 return previous; 220} 221 222int 223sc_report_handler::get_verbosity_level() 224{ 225 return sc_gem5::reportVerbosityLevel; 226} 227 228 229sc_actions 230sc_report_handler::suppress(sc_actions actions) 231{ 232 sc_actions previous = sc_gem5::reportSuppressedActions; 233 sc_gem5::reportSuppressedActions = actions; 234 return previous; 235} 236 237sc_actions 238sc_report_handler::suppress() 239{ 240 return suppress(SC_UNSPECIFIED); 241} 242 243sc_actions 244sc_report_handler::force(sc_actions actions) 245{ 246 sc_actions previous = sc_gem5::reportForcedActions; 247 sc_gem5::reportForcedActions = actions; 248 return previous; 249} 250 251sc_actions 252sc_report_handler::force() 253{ 254 return force(SC_UNSPECIFIED); 255} 256 257 258sc_actions 259sc_report_handler::set_catch_actions(sc_actions actions) 260{ 261 sc_actions previous = sc_gem5::reportCatchActions; 262 sc_gem5::reportCatchActions = actions; 263 return previous; 264} 265 266sc_actions 267sc_report_handler::get_catch_actions() 268{ 269 return sc_gem5::reportCatchActions; 270} 271 272 273void 274sc_report_handler::set_handler(sc_report_handler_proc proc) 275{ 276 sc_gem5::reportHandlerProc = proc; 277} 278 279void 280sc_report_handler::default_handler( 281 const sc_report &report, const sc_actions &actions) 282{ 283 if (actions & SC_DISPLAY) 284 cprintf("\n%s\n", sc_report_compose_message(report)); 285 286 if ((actions & SC_LOG) && logFile) { 287 ccprintf(*logFile, "%s: %s\n", report.get_time().to_string(), 288 sc_report_compose_message(report)); 289 } 290 if (actions & SC_STOP) { 291 sc_stop_here(report.get_msg_type(), report.get_severity()); 292 sc_stop(); 293 } 294 if (actions & SC_INTERRUPT) 295 sc_interrupt_here(report.get_msg_type(), report.get_severity()); 296 if (actions & SC_ABORT) 297 sc_abort(); 298 if (actions & SC_THROW) { 299 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 300 if (current) 301 current->isUnwinding(false); 302 throw report; 303 } 304} 305 306sc_actions 307sc_report_handler::get_new_action_id() 308{ 309 static sc_actions maxAction = SC_ABORT; 310 maxAction = maxAction << 1; 311 return maxAction; 312} 313 314sc_report * 315sc_report_handler::get_cached_report() 316{ 317 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 318 if (current) 319 return current->lastReport(); 320 return ::sc_gem5::globalReportCache.get(); 321} 322 323void 324sc_report_handler::clear_cached_report() 325{ 326 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 327 if (current) { 328 current->lastReport(nullptr); 329 } else { 330 ::sc_gem5::globalReportCache = nullptr; 331 } 332} 333 334bool 335sc_report_handler::set_log_file_name(const char *new_name) 336{ 337 if (!new_name) { 338 logFile = nullptr; 339 logFileName = nullptr; 340 return false; 341 } else { 342 if (logFileName) 343 return false; 344 logFileName = std::unique_ptr<std::string>(new std::string(new_name)); 345 logFile = std::unique_ptr<std::ofstream>(new std::ofstream(new_name)); 346 return true; 347 } 348} 349 350const char * 351sc_report_handler::get_log_file_name() 352{ 353 if (!logFileName) 354 return nullptr; 355 else 356 return logFileName->c_str(); 357} 358 359void 360sc_interrupt_here(const char *msg_type, sc_severity) 361{ 362 // Purposefully empty, for setting breakpoints supposedly. 363} 364 365void 366sc_stop_here(const char *msg_type, sc_severity) 367{ 368 // Purposefully empty, for setting breakpoints supposedly. 369} 370 371const std::string 372sc_report_compose_message(const sc_report &report) 373{ 374 std::ostringstream str; 375 376 const char *sevName = sc_gem5::reportSeverityNames[report.get_severity()]; 377 int id = report.get_id(); 378 379 str << sevName << ": "; 380 if (id >= 0) { 381 ccprintf(str, "(%c%d) ", sevName[0], id); 382 } 383 str << report.get_msg_type(); 384 385 const char *msg = report.get_msg(); 386 if (msg && msg[0]) 387 str << ": " << msg; 388 389 if (report.get_severity() > SC_INFO) { 390 ccprintf(str, "\nIn file: %s:%d", report.get_file_name(), 391 report.get_line_number()); 392 393 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 394 const char *name = report.get_process_name(); 395 if (current && sc_is_running() && name) { 396 ccprintf(str, "\nIn process: %s @ %s", name, 397 report.get_time().to_string()); 398 } 399 } 400 401 return str.str(); 402} 403 404bool 405sc_report_close_default_log() 406{ 407 if (logFile) { 408 logFile = nullptr; 409 logFileName = nullptr; 410 return false; 411 } 412 return true; 413} 414 415} // namespace sc_core 416