Add "yosys -e regex" for turning warnings into errors
[yosys.git] / kernel / log.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "libs/sha1/sha1.h"
22 #include "backends/ilang/ilang_backend.h"
23
24 #if !defined(_WIN32) || defined(__MINGW32__)
25 # include <sys/time.h>
26 #endif
27
28 #ifdef __linux__
29 # include <dlfcn.h>
30 #endif
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdarg.h>
36 #include <vector>
37 #include <list>
38
39 YOSYS_NAMESPACE_BEGIN
40
41 std::vector<FILE*> log_files;
42 std::vector<std::ostream*> log_streams;
43 std::map<std::string, std::set<std::string>> log_hdump;
44 std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
45 std::set<std::string> log_warnings;
46 int log_warnings_count = 0;
47 bool log_hdump_all = false;
48 FILE *log_errfile = NULL;
49 SHA1 *log_hasher = NULL;
50
51 bool log_time = false;
52 bool log_error_stderr = false;
53 bool log_cmd_error_throw = false;
54 bool log_quiet_warnings = false;
55 int log_verbose_level;
56 string log_last_error;
57 void (*log_error_atexit)() = NULL;
58
59 vector<int> header_count;
60 pool<RTLIL::IdString> log_id_cache;
61 vector<shared_str> string_buf;
62 int string_buf_index = -1;
63
64 static struct timeval initial_tv = { 0, 0 };
65 static bool next_print_log = false;
66 static int log_newline_count = 0;
67
68 #if defined(_WIN32) && !defined(__MINGW32__)
69 // this will get time information and return it in timeval, simulating gettimeofday()
70 int gettimeofday(struct timeval *tv, struct timezone *tz)
71 {
72 LARGE_INTEGER counter;
73 LARGE_INTEGER freq;
74
75 QueryPerformanceFrequency(&freq);
76 QueryPerformanceCounter(&counter);
77
78 counter.QuadPart *= 1000000;
79 counter.QuadPart /= freq.QuadPart;
80
81 tv->tv_sec = long(counter.QuadPart / 1000000);
82 tv->tv_usec = counter.QuadPart % 1000000;
83
84 return 0;
85 }
86 #endif
87
88 void logv(const char *format, va_list ap)
89 {
90 while (format[0] == '\n' && format[1] != 0) {
91 log("\n");
92 format++;
93 }
94
95 std::string str = vstringf(format, ap);
96
97 if (str.empty())
98 return;
99
100 size_t nnl_pos = str.find_last_not_of('\n');
101 if (nnl_pos == std::string::npos)
102 log_newline_count += GetSize(str);
103 else
104 log_newline_count = GetSize(str) - nnl_pos - 1;
105
106 if (log_hasher)
107 log_hasher->update(str);
108
109 if (log_time)
110 {
111 std::string time_str;
112
113 if (next_print_log || initial_tv.tv_sec == 0) {
114 next_print_log = false;
115 struct timeval tv;
116 gettimeofday(&tv, NULL);
117 if (initial_tv.tv_sec == 0)
118 initial_tv = tv;
119 if (tv.tv_usec < initial_tv.tv_usec) {
120 tv.tv_sec--;
121 tv.tv_usec += 1000000;
122 }
123 tv.tv_sec -= initial_tv.tv_sec;
124 tv.tv_usec -= initial_tv.tv_usec;
125 time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
126 }
127
128 if (format[0] && format[strlen(format)-1] == '\n')
129 next_print_log = true;
130
131 for (auto f : log_files)
132 fputs(time_str.c_str(), f);
133
134 for (auto f : log_streams)
135 *f << time_str;
136 }
137
138 for (auto f : log_files)
139 fputs(str.c_str(), f);
140
141 for (auto f : log_streams)
142 *f << str;
143
144 static std::string linebuffer;
145 static bool log_warn_regex_recusion_guard = false;
146
147 if (!log_warn_regex_recusion_guard)
148 {
149 log_warn_regex_recusion_guard = true;
150
151 if (log_warn_regexes.empty())
152 {
153 linebuffer.clear();
154 }
155 else
156 {
157 linebuffer += str;
158
159 if (!linebuffer.empty() && linebuffer.back() == '\n') {
160 for (auto &re : log_warn_regexes)
161 if (std::regex_search(linebuffer, re))
162 log_warning("Found log message matching -W regex:\n%s", str.c_str());
163 linebuffer.clear();
164 }
165 }
166
167 log_warn_regex_recusion_guard = false;
168 }
169 }
170
171 void logv_header(RTLIL::Design *design, const char *format, va_list ap)
172 {
173 bool pop_errfile = false;
174
175 log_spacer();
176 if (header_count.size() > 0)
177 header_count.back()++;
178
179 if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
180 log_files.push_back(log_errfile);
181 pop_errfile = true;
182 }
183
184 std::string header_id;
185
186 for (int c : header_count)
187 header_id += stringf("%s%d", header_id.empty() ? "" : ".", c);
188
189 log("%s. ", header_id.c_str());
190 logv(format, ap);
191 log_flush();
192
193 if (log_hdump_all)
194 log_hdump[header_id].insert("yosys_dump_" + header_id + ".il");
195
196 if (log_hdump.count(header_id) && design != nullptr)
197 for (auto &filename : log_hdump.at(header_id)) {
198 log("Dumping current design to '%s'.\n", filename.c_str());
199 Pass::call(design, {"dump", "-o", filename});
200 }
201
202 if (pop_errfile)
203 log_files.pop_back();
204 }
205
206 void logv_warning(const char *format, va_list ap)
207 {
208 std::string message = vstringf(format, ap);
209 bool suppressed = false;
210
211 for (auto &re : log_nowarn_regexes)
212 if (std::regex_search(message, re))
213 suppressed = true;
214
215 if (suppressed)
216 {
217 log("Suppressed warning: %s", message.c_str());
218 }
219 else
220 {
221 for (auto &re : log_werror_regexes)
222 if (std::regex_search(message, re))
223 log_error("%s", message.c_str());
224
225 if (log_warnings.count(message))
226 {
227 log("Warning: %s", message.c_str());
228 log_flush();
229 }
230 else
231 {
232 if (log_errfile != NULL && !log_quiet_warnings)
233 log_files.push_back(log_errfile);
234
235 log("Warning: %s", message.c_str());
236 log_flush();
237
238 if (log_errfile != NULL && !log_quiet_warnings)
239 log_files.pop_back();
240
241 log_warnings.insert(message);
242 }
243
244 log_warnings_count++;
245 }
246 }
247
248 void logv_warning_noprefix(const char *format, va_list ap)
249 {
250 std::string message = vstringf(format, ap);
251 bool suppressed = false;
252
253 for (auto &re : log_nowarn_regexes)
254 if (std::regex_search(message, re))
255 suppressed = true;
256
257 if (suppressed)
258 {
259 log("%s", message.c_str());
260 }
261 else
262 {
263 for (auto &re : log_werror_regexes)
264 if (std::regex_search(message, re))
265 log_error("%s", message.c_str());
266
267 if (log_warnings.count(message))
268 {
269 log("%s", message.c_str());
270 log_flush();
271 }
272 else
273 {
274 if (log_errfile != NULL && !log_quiet_warnings)
275 log_files.push_back(log_errfile);
276
277 log("%s", message.c_str());
278 log_flush();
279
280 if (log_errfile != NULL && !log_quiet_warnings)
281 log_files.pop_back();
282
283 log_warnings.insert(message);
284 }
285
286 log_warnings_count++;
287 }
288 }
289
290 void logv_error(const char *format, va_list ap)
291 {
292 #ifdef EMSCRIPTEN
293 auto backup_log_files = log_files;
294 #endif
295
296 if (log_errfile != NULL)
297 log_files.push_back(log_errfile);
298
299 if (log_error_stderr)
300 for (auto &f : log_files)
301 if (f == stdout)
302 f = stderr;
303
304 log_last_error = vstringf(format, ap);
305 log("ERROR: %s", log_last_error.c_str());
306 log_flush();
307
308 if (log_error_atexit)
309 log_error_atexit();
310
311 #ifdef EMSCRIPTEN
312 log_files = backup_log_files;
313 throw 0;
314 #elif defined(_MSC_VER)
315 _exit(1);
316 #else
317 _Exit(1);
318 #endif
319 }
320
321 void log(const char *format, ...)
322 {
323 va_list ap;
324 va_start(ap, format);
325 logv(format, ap);
326 va_end(ap);
327 }
328
329 void log_header(RTLIL::Design *design, const char *format, ...)
330 {
331 va_list ap;
332 va_start(ap, format);
333 logv_header(design, format, ap);
334 va_end(ap);
335 }
336
337 void log_warning(const char *format, ...)
338 {
339 va_list ap;
340 va_start(ap, format);
341 logv_warning(format, ap);
342 va_end(ap);
343 }
344
345 void log_warning_noprefix(const char *format, ...)
346 {
347 va_list ap;
348 va_start(ap, format);
349 logv_warning_noprefix(format, ap);
350 va_end(ap);
351 }
352
353 void log_error(const char *format, ...)
354 {
355 va_list ap;
356 va_start(ap, format);
357 logv_error(format, ap);
358 }
359
360 void log_cmd_error(const char *format, ...)
361 {
362 va_list ap;
363 va_start(ap, format);
364
365 if (log_cmd_error_throw) {
366 log_last_error = vstringf(format, ap);
367 log("ERROR: %s", log_last_error.c_str());
368 log_flush();
369 throw log_cmd_error_exception();
370 }
371
372 logv_error(format, ap);
373 }
374
375 void log_spacer()
376 {
377 if (log_newline_count < 2) log("\n");
378 if (log_newline_count < 2) log("\n");
379 }
380
381 void log_push()
382 {
383 header_count.push_back(0);
384 }
385
386 void log_pop()
387 {
388 header_count.pop_back();
389 log_id_cache.clear();
390 string_buf.clear();
391 string_buf_index = -1;
392 log_flush();
393 }
394
395 #if defined(__linux__) && defined(YOSYS_ENABLE_PLUGINS)
396 void log_backtrace(const char *prefix, int levels)
397 {
398 if (levels <= 0) return;
399
400 Dl_info dli;
401 void *p;
402
403 if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) {
404 log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
405 } else {
406 log("%sframe #1: ---\n", prefix);
407 return;
408 }
409
410 if (levels <= 1) return;
411
412 #ifndef DEBUG
413 log("%sframe #2: [build Yosys with ENABLE_DEBUG for deeper backtraces]\n", prefix);
414 #else
415 if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) {
416 log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
417 } else {
418 log("%sframe #2: ---\n", prefix);
419 return;
420 }
421
422 if (levels <= 2) return;
423
424 if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) {
425 log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
426 } else {
427 log("%sframe #3: ---\n", prefix);
428 return;
429 }
430
431 if (levels <= 3) return;
432
433 if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) {
434 log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
435 } else {
436 log("%sframe #4: ---\n", prefix);
437 return;
438 }
439
440 if (levels <= 4) return;
441
442 if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) {
443 log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
444 } else {
445 log("%sframe #5: ---\n", prefix);
446 return;
447 }
448
449 if (levels <= 5) return;
450
451 if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) {
452 log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
453 } else {
454 log("%sframe #6: ---\n", prefix);
455 return;
456 }
457
458 if (levels <= 6) return;
459
460 if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) {
461 log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
462 } else {
463 log("%sframe #7: ---\n", prefix);
464 return;
465 }
466
467 if (levels <= 7) return;
468
469 if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) {
470 log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
471 } else {
472 log("%sframe #8: ---\n", prefix);
473 return;
474 }
475
476 if (levels <= 8) return;
477
478 if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) {
479 log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
480 } else {
481 log("%sframe #9: ---\n", prefix);
482 return;
483 }
484
485 if (levels <= 9) return;
486 #endif
487 }
488 #else
489 void log_backtrace(const char*, int) { }
490 #endif
491
492 void log_reset_stack()
493 {
494 while (header_count.size() > 1)
495 header_count.pop_back();
496 log_id_cache.clear();
497 string_buf.clear();
498 string_buf_index = -1;
499 log_flush();
500 }
501
502 void log_flush()
503 {
504 for (auto f : log_files)
505 fflush(f);
506
507 for (auto f : log_streams)
508 f->flush();
509 }
510
511 void log_dump_val_worker(RTLIL::IdString v) {
512 log("%s", log_id(v));
513 }
514
515 void log_dump_val_worker(RTLIL::SigSpec v) {
516 log("%s", log_signal(v));
517 }
518
519 const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
520 {
521 std::stringstream buf;
522 ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
523
524 if (string_buf.size() < 100) {
525 string_buf.push_back(buf.str());
526 return string_buf.back().c_str();
527 } else {
528 if (++string_buf_index == 100)
529 string_buf_index = 0;
530 string_buf[string_buf_index] = buf.str();
531 return string_buf[string_buf_index].c_str();
532 }
533 }
534
535 const char *log_const(const RTLIL::Const &value, bool autoint)
536 {
537 if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0)
538 return log_signal(value, autoint);
539
540 std::string str = "\"" + value.decode_string() + "\"";
541
542 if (string_buf.size() < 100) {
543 string_buf.push_back(str);
544 return string_buf.back().c_str();
545 } else {
546 if (++string_buf_index == 100)
547 string_buf_index = 0;
548 string_buf[string_buf_index] = str;
549 return string_buf[string_buf_index].c_str();
550 }
551 }
552
553 const char *log_id(RTLIL::IdString str)
554 {
555 log_id_cache.insert(str);
556 const char *p = str.c_str();
557 if (p[0] != '\\')
558 return p;
559 if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
560 return p;
561 if (p[1] >= '0' && p[1] <= '9')
562 return p;
563 return p+1;
564 }
565
566 void log_module(RTLIL::Module *module, std::string indent)
567 {
568 std::stringstream buf;
569 ILANG_BACKEND::dump_module(buf, indent, module, module->design, false);
570 log("%s", buf.str().c_str());
571 }
572
573 void log_cell(RTLIL::Cell *cell, std::string indent)
574 {
575 std::stringstream buf;
576 ILANG_BACKEND::dump_cell(buf, indent, cell);
577 log("%s", buf.str().c_str());
578 }
579
580 void log_wire(RTLIL::Wire *wire, std::string indent)
581 {
582 std::stringstream buf;
583 ILANG_BACKEND::dump_wire(buf, indent, wire);
584 log("%s", buf.str().c_str());
585 }
586
587 // ---------------------------------------------------
588 // This is the magic behind the code coverage counters
589 // ---------------------------------------------------
590 #if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
591
592 dict<std::string, std::pair<std::string, int>> extra_coverage_data;
593
594 void cover_extra(std::string parent, std::string id, bool increment) {
595 if (extra_coverage_data.count(id) == 0) {
596 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
597 if (p->id == parent)
598 extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
599 log_assert(extra_coverage_data.count(id));
600 }
601 if (increment)
602 extra_coverage_data[id].second++;
603 }
604
605 dict<std::string, std::pair<std::string, int>> get_coverage_data()
606 {
607 dict<std::string, std::pair<std::string, int>> coverage_data;
608
609 for (auto &it : pass_register) {
610 std::string key = stringf("passes.%s", it.first.c_str());
611 coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
612 coverage_data[key].second += it.second->call_counter;
613 }
614
615 for (auto &it : extra_coverage_data) {
616 if (coverage_data.count(it.first))
617 log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str());
618 coverage_data[it.first].first = it.second.first;
619 coverage_data[it.first].second += it.second.second;
620 }
621
622 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
623 if (coverage_data.count(p->id))
624 log_warning("found duplicate coverage id \"%s\".\n", p->id);
625 coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
626 coverage_data[p->id].second += p->counter;
627 }
628
629 for (auto &it : coverage_data)
630 if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
631 it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
632
633 return coverage_data;
634 }
635
636 #endif
637
638 YOSYS_NAMESPACE_END
639