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