1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_report_handler.cpp - 23 24 Original Author: Alex Riesen, Synopsys, Inc. 25 see also sc_report.cpp 26 27 CHANGE LOG AT END OF FILE 28 *****************************************************************************/ 29 30#include <cstdio> 31#include <stdlib.h> 32#include <string.h> 33 34#include "sysc/utils/sc_iostream.h" 35#include "sysc/kernel/sc_process.h" 36#include "sysc/kernel/sc_simcontext_int.h" 37#include "sysc/utils/sc_stop_here.h" 38#include "sysc/utils/sc_report_handler.h" 39#include "sysc/utils/sc_report.h" 40 41namespace std {} 42 43namespace sc_core { 44 45int sc_report_handler::verbosity_level = SC_MEDIUM; 46 47// not documented, but available 48const std::string sc_report_compose_message(const sc_report& rep) 49{ 50 static const char * severity_names[] = { 51 "Info", "Warning", "Error", "Fatal" 52 }; 53 std::string str; 54 55 str += severity_names[rep.get_severity()]; 56 str += ": "; 57 58 if ( rep.get_id() >= 0 ) // backward compatibility with 2.0+ 59 { 60 char idstr[64]; 61 std::sprintf(idstr, "(%c%d) ", 62 "IWEF"[rep.get_severity()], rep.get_id()); 63 str += idstr; 64 } 65 str += rep.get_msg_type(); 66 67 if( *rep.get_msg() ) 68 { 69 str += ": "; 70 str += rep.get_msg(); 71 } 72 if( rep.get_severity() > SC_INFO ) 73 { 74 char line_number_str[16]; 75 str += "\nIn file: "; 76 str += rep.get_file_name(); 77 str += ":"; 78 std::sprintf(line_number_str, "%d", rep.get_line_number()); 79 str += line_number_str; 80 sc_simcontext* simc = sc_get_curr_simcontext(); 81 82 if( simc && sc_is_running() ) 83 { 84 const char* proc_name = rep.get_process_name(); 85 86 if( proc_name ) 87 { 88 str += "\nIn process: "; 89 str += proc_name; 90 str += " @ "; 91 str += rep.get_time().to_string(); 92 } 93 } 94 } 95 96 return str; 97} 98bool sc_report_close_default_log(); 99 100static ::std::ofstream* log_stream = 0; 101static 102struct auto_close_log 103{ 104 ~auto_close_log() 105 { 106 sc_report_close_default_log(); 107 } 108} auto_close; 109 110const char* sc_report::get_process_name() const 111{ 112 return process ? process->name() : 0; 113} 114 115 116// 117// The official handler of the exception reporting 118// 119 120void sc_report_handler::default_handler(const sc_report& rep, 121 const sc_actions& actions) 122{ 123 if ( actions & SC_DISPLAY ) 124 ::std::cout << ::std::endl << sc_report_compose_message(rep) << 125 ::std::endl; 126 127 if ( (actions & SC_LOG) && get_log_file_name() ) 128 { 129 if ( !log_stream ) 130 log_stream = new ::std::ofstream(get_log_file_name()); // ios::trunc 131 132 *log_stream << rep.get_time() << ": " 133 << sc_report_compose_message(rep) << ::std::endl; 134 } 135 if ( actions & SC_STOP ) 136 { 137 sc_stop_here(rep.get_msg_type(), rep.get_severity()); 138 sc_stop(); 139 } 140 if ( actions & SC_INTERRUPT ) 141 sc_interrupt_here(rep.get_msg_type(), rep.get_severity()); 142 143 if ( actions & SC_ABORT ) 144 abort(); 145 146 if ( actions & SC_THROW ) { 147 sc_process_b* proc_p = sc_get_current_process_b(); 148 if( proc_p && proc_p->is_unwinding() ) 149 proc_p->clear_unwinding(); 150 throw rep; 151 } 152} 153 154// not documented, but available 155bool sc_report_close_default_log() 156{ 157 delete log_stream; 158 sc_report_handler::set_log_file_name(NULL); 159 160 if ( !log_stream ) 161 return false; 162 163 log_stream = 0; 164 return true; 165} 166 167int sc_report_handler::get_count(sc_severity severity_) 168{ 169 return sev_call_count[severity_]; 170} 171 172int sc_report_handler::get_count(const char* msg_type_) 173{ 174 sc_msg_def * md = mdlookup(msg_type_); 175 176 if ( !md ) 177 md = add_msg_type(msg_type_); 178 179 return md->call_count; 180} 181 182int sc_report_handler::get_count(const char* msg_type_, sc_severity severity_) 183{ 184 sc_msg_def * md = mdlookup(msg_type_); 185 186 if ( !md ) 187 md = add_msg_type(msg_type_); 188 189 return md->sev_call_count[severity_]; 190} 191 192 193// 194// CLASS: sc_report_handler 195// implementation 196// 197 198sc_msg_def * sc_report_handler::mdlookup(const char * msg_type_) 199{ 200 if( !msg_type_ ) // if msg_type is NULL, report unknown error 201 msg_type_ = SC_ID_UNKNOWN_ERROR_; 202 203 for ( msg_def_items * item = messages; item; item = item->next ) 204 { 205 for ( int i = 0; i < item->count; ++i ) 206 if ( !strcmp(msg_type_, item->md[i].msg_type) ) 207 return item->md + i; 208 } 209 return 0; 210} 211 212// The calculation of actions to be executed 213sc_actions sc_report_handler::execute(sc_msg_def* md, sc_severity severity_) 214{ 215 sc_actions actions = md->sev_actions[severity_]; // high prio 216 217 if ( SC_UNSPECIFIED == actions ) // middle prio 218 actions = md->actions; 219 220 if ( SC_UNSPECIFIED == actions ) // the lowest prio 221 actions = sev_actions[severity_]; 222 223 actions &= ~suppress_mask; // higher than the high prio 224 actions |= force_mask; // higher than above, and the limit is the highest 225 226 unsigned * limit = 0; 227 unsigned * call_count = 0; 228 229 // just increment counters and check for overflow 230 if ( md->sev_call_count[severity_] < UINT_MAX ) 231 md->sev_call_count[severity_]++; 232 if ( md->call_count < UINT_MAX ) 233 md->call_count++; 234 if ( sev_call_count[severity_] < UINT_MAX ) 235 sev_call_count[severity_]++; 236 237 if ( md->limit_mask & (1 << (severity_ + 1)) ) 238 { 239 limit = md->sev_limit + severity_; 240 call_count = md->sev_call_count + severity_; 241 } 242 if ( !limit && (md->limit_mask & 1) ) 243 { 244 limit = &md->limit; 245 call_count = &md->call_count; 246 } 247 if ( !limit ) 248 { 249 limit = sev_limit + severity_; 250 call_count = sev_call_count + severity_; 251 } 252 if ( *limit == 0 ) 253 { 254 // stop limit disabled 255 } 256 else if ( *limit != UINT_MAX ) 257 { 258 if ( *call_count >= *limit ) 259 actions |= SC_STOP; // force sc_stop() 260 } 261 return actions; 262} 263 264void sc_report_handler::report( sc_severity severity_, 265 const char* msg_type_, 266 const char* msg_, 267 int verbosity_, 268 const char* file_, 269 int line_ ) 270{ 271 sc_msg_def * md = mdlookup(msg_type_); 272 273 // If the severity of the report is SC_INFO and the specified verbosity 274 // level is greater than the maximum verbosity level of the simulator then 275 // return without any action. 276 277 if ( (severity_ == SC_INFO) && (verbosity_ > verbosity_level) ) return; 278 279 // Process the report: 280 281 if ( !md ) 282 md = add_msg_type(msg_type_); 283 284 sc_actions actions = execute(md, severity_); 285 sc_report rep(severity_, md, msg_, file_, line_, verbosity_); 286 287 if ( actions & SC_CACHE_REPORT ) 288 cache_report(rep); 289 290 handler(rep, actions); 291} 292 293void sc_report_handler::report(sc_severity severity_, 294 const char * msg_type_, 295 const char * msg_, 296 const char * file_, 297 int line_) 298{ 299 sc_msg_def * md = mdlookup(msg_type_); 300 301 // If the severity of the report is SC_INFO and the maximum verbosity 302 // level is less than SC_MEDIUM return without any action. 303 304 if ( (severity_ == SC_INFO) && (SC_MEDIUM > verbosity_level) ) return; 305 306 // Process the report: 307 308 309 if ( !md ) 310 md = add_msg_type(msg_type_); 311 312 sc_actions actions = execute(md, severity_); 313 sc_report rep(severity_, md, msg_, file_, line_); 314 315 if ( actions & SC_CACHE_REPORT ) 316 cache_report(rep); 317 318 handler(rep, actions); 319} 320 321// The following method is never called by the simulator. 322 323void sc_report_handler::initialize() 324{ 325#if 0 // actually, i do not know whether we have to reset these. 326 suppress(); 327 force(); 328 set_actions(SC_INFO, SC_DEFAULT_INFO_ACTIONS); 329 set_actions(SC_WARNING, SC_DEFAULT_WARNING_ACTIONS); 330 set_actions(SC_ERROR, SC_DEFAULT_ERROR_ACTIONS); 331 set_actions(SC_FATAL, SC_DEFAULT_FATAL_ACTIONS); 332#endif 333 334 sev_call_count[SC_INFO] = 0; 335 sev_call_count[SC_WARNING] = 0; 336 sev_call_count[SC_ERROR] = 0; 337 sev_call_count[SC_FATAL] = 0; 338 339 msg_def_items * items = messages; 340 341 while ( items != &msg_terminator ) 342 { 343 for ( int i = 0; i < items->count; ++i ) 344 { 345 items->md[i].call_count = 0; 346 items->md[i].sev_call_count[SC_INFO] = 0; 347 items->md[i].sev_call_count[SC_WARNING] = 0; 348 items->md[i].sev_call_count[SC_ERROR] = 0; 349 items->md[i].sev_call_count[SC_FATAL] = 0; 350 } 351 items = items->next; 352 } 353 354 // PROCESS ANY ENVIRONMENTAL OVERRIDES: 355 356 const char* deprecation_warn = std::getenv("SC_DEPRECATION_WARNINGS"); 357 if ( (deprecation_warn!=0) && !strcmp(deprecation_warn,"DISABLE") ) 358 { 359 set_actions("/IEEE_Std_1666/deprecated", SC_DO_NOTHING); 360 } 361} 362 363// free the sc_msg_def's allocated by add_msg_type 364// (or implicit msg_type registration: set_actions, abort_after) 365// clear last_global_report. 366void sc_report_handler::release() 367{ 368 delete last_global_report; 369 last_global_report = 0; 370 sc_report_close_default_log(); 371 372 msg_def_items * items = messages, * newitems = &msg_terminator; 373 messages = &msg_terminator; 374 375 while ( items != &msg_terminator ) 376 { 377 for ( int i = 0; i < items->count; ++i ) 378 if ( items->md[i].msg_type == items->md[i].msg_type_data ) 379 free(items->md[i].msg_type_data); 380 381 msg_def_items * prev = items; 382 items = items->next; 383 384 if ( prev->allocated ) 385 { 386 delete [] prev->md; 387 delete prev; 388 } 389 else 390 { 391 prev->next = newitems; 392 newitems = prev; 393 } 394 } 395 messages = newitems; 396} 397 398sc_msg_def * sc_report_handler::add_msg_type(const char * msg_type_) 399{ 400 sc_msg_def * md = mdlookup(msg_type_); 401 int msg_type_len; 402 403 if ( md ) 404 return md; 405 406 msg_def_items * items = new msg_def_items; 407 408 if ( !items ) 409 return 0; 410 411 items->count = 1; 412 items->md = new sc_msg_def[items->count]; 413 414 if ( !items->md ) 415 { 416 delete items; 417 return 0; 418 } 419 memset(items->md, 0, sizeof(sc_msg_def) * items->count); 420 msg_type_len = strlen(msg_type_); 421 if ( msg_type_len > 0 ) 422 { 423 items->md->msg_type_data = (char*) malloc(msg_type_len+1); 424 strcpy( items->md->msg_type_data, msg_type_ ); 425 items->md->id = -1; // backward compatibility with 2.0+ 426 } 427 else 428 { 429 delete items->md; 430 delete items; 431 return 0; 432 } 433 items->md->msg_type = items->md->msg_type_data; 434 add_static_msg_types(items); 435 items->allocated = true; 436 437 return items->md; 438} 439 440void sc_report_handler::add_static_msg_types(msg_def_items * items) 441{ 442 items->allocated = false; 443 items->next = messages; 444 messages = items; 445} 446 447sc_actions sc_report_handler::set_actions(sc_severity severity_, 448 sc_actions actions_) 449{ 450 sc_actions old = sev_actions[severity_]; 451 sev_actions[severity_] = actions_; 452 return old; 453} 454 455sc_actions sc_report_handler::set_actions(const char * msg_type_, 456 sc_actions actions_) 457{ 458 sc_msg_def * md = mdlookup(msg_type_); 459 460 if ( !md ) 461 md = add_msg_type(msg_type_); 462 463 sc_actions old = md->actions; 464 md->actions = actions_; 465 466 return old; 467} 468 469sc_actions sc_report_handler::set_actions(const char * msg_type_, 470 sc_severity severity_, 471 sc_actions actions_) 472{ 473 sc_msg_def * md = mdlookup(msg_type_); 474 475 if ( !md ) 476 md = add_msg_type(msg_type_); 477 478 sc_actions old = md->sev_actions[severity_]; 479 md->sev_actions[severity_] = actions_; 480 481 return old; 482} 483 484int sc_report_handler::stop_after(sc_severity severity_, int limit) 485{ 486 int old = sev_limit[severity_]; 487 488 sev_limit[severity_] = limit < 0 ? UINT_MAX: (unsigned) limit; 489 490 return old; 491} 492 493int sc_report_handler::stop_after(const char * msg_type_, int limit) 494{ 495 sc_msg_def * md = mdlookup(msg_type_); 496 497 if ( !md ) 498 md = add_msg_type(msg_type_); 499 500 int old = md->limit_mask & 1 ? md->limit: UINT_MAX; 501 502 if ( limit < 0 ) 503 md->limit_mask &= ~1; 504 else 505 { 506 md->limit_mask |= 1; 507 md->limit = limit; 508 } 509 return old; 510} 511 512int sc_report_handler::stop_after(const char * msg_type_, 513 sc_severity severity_, 514 int limit) 515{ 516 sc_msg_def * md = mdlookup(msg_type_); 517 518 if ( !md ) 519 md = add_msg_type(msg_type_); 520 521 int mask = 1 << (severity_ + 1); 522 int old = md->limit_mask & mask ? md->sev_limit[severity_]: UINT_MAX; 523 524 if ( limit < 0 ) 525 md->limit_mask &= ~mask; 526 else 527 { 528 md->limit_mask |= mask; 529 md->sev_limit[severity_] = limit; 530 } 531 return old; 532} 533 534sc_actions sc_report_handler::suppress(sc_actions mask) 535{ 536 sc_actions old = suppress_mask; 537 suppress_mask = mask; 538 return old; 539} 540 541sc_actions sc_report_handler::suppress() 542{ 543 return suppress(0); 544} 545 546sc_actions sc_report_handler::force(sc_actions mask) 547{ 548 sc_actions old = force_mask; 549 force_mask = mask; 550 return old; 551} 552 553sc_actions sc_report_handler::force() 554{ 555 return force(0); 556} 557 558sc_report_handler_proc 559sc_report_handler::set_handler(sc_report_handler_proc handler_) 560{ 561 sc_report_handler_proc old = handler; 562 handler = handler_ ? handler_: &sc_report_handler::default_handler; 563 return old; 564} 565 566sc_report_handler_proc 567sc_report_handler::get_handler() 568{ 569 return handler; 570} 571 572sc_report* sc_report_handler::get_cached_report() 573{ 574 sc_process_b * proc = sc_get_current_process_b(); 575 576 if ( proc ) 577 return proc->get_last_report(); 578 579 return last_global_report; 580} 581 582void sc_report_handler::clear_cached_report() 583{ 584 sc_process_b * proc = sc_get_current_process_b(); 585 586 if ( proc ) 587 proc->set_last_report(0); 588 else 589 { 590 delete last_global_report; 591 last_global_report = 0; 592 } 593} 594 595sc_actions sc_report_handler::get_new_action_id() 596{ 597 for ( sc_actions p = 1; p; p <<= 1 ) 598 { 599 if ( !(p & available_actions) ) // free 600 { 601 available_actions |= p; 602 return p; 603 } 604 } 605 return SC_UNSPECIFIED; 606} 607 608bool sc_report_handler::set_log_file_name(const char* name_) 609{ 610 if ( !name_ ) 611 { 612 free(log_file_name); 613 log_file_name = 0; 614 return false; 615 } 616 if ( log_file_name ) 617 return false; 618 619 log_file_name = (char*)malloc(strlen(name_)+1); 620 strcpy(log_file_name, name_); 621 return true; 622} 623 624const char * sc_report_handler::get_log_file_name() 625{ 626 return log_file_name; 627} 628 629void sc_report_handler::cache_report(const sc_report& rep) 630{ 631 sc_process_b * proc = sc_get_current_process_b(); 632 if ( proc ) 633 proc->set_last_report(new sc_report(rep)); 634 else 635 { 636 delete last_global_report; 637 last_global_report = new sc_report(rep); 638 } 639} 640 641// 642// backward compatibility with 2.0+ 643// 644 645sc_msg_def * sc_report_handler::mdlookup(int id) 646{ 647 for ( msg_def_items * item = messages; item; item = item->next ) 648 { 649 for ( int i = 0; i < item->count; ++i ) 650 if ( id == item->md[i].id ) 651 return item->md + i; 652 } 653 return 0; 654} 655 656int sc_report_handler::get_verbosity_level() { return verbosity_level; } 657 658int sc_report_handler::set_verbosity_level( int level ) 659{ 660 int result = verbosity_level; 661 verbosity_level = level; 662 return result; 663} 664 665// 666// CLASS: sc_report_handler 667// static variables 668// 669 670sc_actions sc_report_handler::suppress_mask = 0; 671sc_actions sc_report_handler::force_mask = 0; 672 673sc_actions sc_report_handler::sev_actions[SC_MAX_SEVERITY] = 674{ 675 /* info */ SC_DEFAULT_INFO_ACTIONS, 676 /* warn */ SC_DEFAULT_WARNING_ACTIONS, 677 /* error */ SC_DEFAULT_ERROR_ACTIONS, 678 /* fatal */ SC_DEFAULT_FATAL_ACTIONS 679}; 680 681// Note that SC_FATAL has a limit of 1 by default 682 683sc_actions sc_report_handler::sev_limit[SC_MAX_SEVERITY] = 684{ 685 UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX 686}; 687sc_actions sc_report_handler::sev_call_count[SC_MAX_SEVERITY] = { 0, 0, 0, 0 }; 688 689sc_report* sc_report_handler::last_global_report = NULL; 690sc_actions sc_report_handler::available_actions = 691 SC_DO_NOTHING | 692 SC_THROW | 693 SC_LOG | 694 SC_DISPLAY | 695 SC_CACHE_REPORT | 696 SC_INTERRUPT | 697 SC_STOP | 698 SC_ABORT; 699 700sc_report_handler_proc sc_report_handler::handler = 701 &sc_report_handler::default_handler; 702 703char * sc_report_handler::log_file_name = 0; 704 705sc_report_handler::msg_def_items * sc_report_handler::messages = 706 &sc_report_handler::msg_terminator; 707 708 709// 710// predefined messages 711// 712 713const char SC_ID_REGISTER_ID_FAILED_[] = "register_id failed"; 714const char SC_ID_UNKNOWN_ERROR_[] = "unknown error"; 715const char SC_ID_WITHOUT_MESSAGE_[] = ""; 716const char SC_ID_NOT_IMPLEMENTED_[] = "not implemented"; 717const char SC_ID_INTERNAL_ERROR_[] = "internal error"; 718const char SC_ID_ASSERTION_FAILED_[] = "assertion failed"; 719const char SC_ID_OUT_OF_BOUNDS_[] = "out of bounds"; 720 721#define DEFINE_MSG(id,n) \ 722 { \ 723 (id), \ 724 0u, {0u}, /* actions */ \ 725 0u, {0u}, 0u, /* limits */ \ 726 0u, {0u}, NULL, /* call counters */ \ 727 n \ 728 } 729 730static sc_msg_def default_msgs[] = { 731 DEFINE_MSG(SC_ID_REGISTER_ID_FAILED_, 800), 732 DEFINE_MSG(SC_ID_UNKNOWN_ERROR_, 0), 733 DEFINE_MSG(SC_ID_WITHOUT_MESSAGE_, 1), 734 DEFINE_MSG(SC_ID_NOT_IMPLEMENTED_, 2), 735 DEFINE_MSG(SC_ID_INTERNAL_ERROR_, 3), 736 DEFINE_MSG(SC_ID_ASSERTION_FAILED_, 4), 737 DEFINE_MSG(SC_ID_OUT_OF_BOUNDS_, 5) 738}; 739 740sc_report_handler::msg_def_items sc_report_handler::msg_terminator = 741{ 742 default_msgs, 743 sizeof(default_msgs)/sizeof(*default_msgs), 744 false, 745 NULL 746}; 747 748} // namespace sc_core 749 750// $Log: sc_report_handler.cpp,v $ 751// Revision 1.9 2011/08/29 18:04:32 acg 752// Philipp A. Hartmann: miscellaneous clean ups. 753// 754// Revision 1.8 2011/08/26 20:46:19 acg 755// Andy Goodrich: moved the modification log to the end of the file to 756// eliminate source line number skew when check-ins are done. 757// 758// Revision 1.7 2011/08/07 19:08:08 acg 759// Andy Goodrich: moved logs to end of file so line number synching works 760// better between versions. 761// 762// Revision 1.6 2011/08/07 18:56:03 acg 763// Philipp A. Hartmann: added cast to ? : to eliminate clang warning message. 764// 765// Revision 1.5 2011/03/23 16:16:49 acg 766// Andy Goodrich: finish message verbosity support. 767// 768// Revision 1.4 2011/02/18 20:38:44 acg 769// Andy Goodrich: Updated Copyright notice. 770// 771// Revision 1.3 2011/02/11 13:25:55 acg 772// Andy Goodrich: Philipp's changes for sc_unwind_exception. 773// 774// Revision 1.2 2011/02/01 23:02:05 acg 775// Andy Goodrich: IEEE 1666 2011 changes. 776// 777// Revision 1.1.1.1 2006/12/15 20:20:06 acg 778// SystemC 2.3 779// 780// Revision 1.7 2006/05/26 20:35:52 acg 781// Andy Goodrich: removed debug message that should not have been left in. 782// 783// Revision 1.6 2006/03/21 00:00:37 acg 784// Andy Goodrich: changed name of sc_get_current_process_base() to be 785// sc_get_current_process_b() since its returning an sc_process_b instance. 786// 787// Revision 1.5 2006/01/31 21:42:07 acg 788// Andy Goodrich: Added checks for SC_DEPRECATED_WARNINGS being defined as 789// DISABLED. If so, we turn off the /IEEE_Std_1666/deprecated message group. 790// 791// Revision 1.4 2006/01/26 21:08:17 acg 792// Andy Goodrich: conversion to use sc_is_running instead of deprecated 793// sc_simcontext::is_running() 794// 795// Revision 1.3 2006/01/13 18:53:11 acg 796// Andy Goodrich: Added $Log command so that CVS comments are reproduced in 797// the source. 798 799// Taf! 800