blob: c7074ca660b9b004739d3dbe2fbacb02e413b53f [file] [log] [blame]
Ernesto Posse8a4f2962015-05-12 13:28:46 -04001// basedebug.cpp - Base Debug (BD) run-time debugging.
2
3/*******************************************************************************
4* Copyright (c) 2014-2015 Zeligsoft (2009) Limited and others.
5* All rights reserved. This program and the accompanying materials
6* are made available under the terms of the Eclipse Public License v1.0
7* which accompanies this distribution, and is available at
8* http://www.eclipse.org/legal/epl-v10.html
9*******************************************************************************/
10
11// See basedebug.hh for interface details.
12
13#ifndef _GNU_SOURCE
14#define _GNU_SOURCE
15#endif
16
17#include <stdarg.h>
18#include <stdio.h>
19#include <pthread.h>
20#include <string.h>
21#include <sys/time.h>
22#include <semaphore.h>
23#include "basedebug.hh"
24#include "basedebugtype.hh"
25#include "basefatal.hh"
26
27namespace base
28{
29 // Colour codes:
Barry Maher5da2c532015-05-15 12:59:11 -040030 //-static const char * ANSI_RESET = "\u001B[0m";
Ernesto Posse8a4f2962015-05-12 13:28:46 -040031 //static const char * ANSI_DIM_BLACK = "\u001B[2;30m";
32 //static const char * ANSI_DIM_RED = "\u001B[2;31m";
33 //static const char * ANSI_DIM_GREEN = "\u001B[2;32m";
34 //static const char * ANSI_DIM_YELLOW = "\u001B[2;33m";
Barry Maher5da2c532015-05-15 12:59:11 -040035 //-static const char * ANSI_DIM_BLUE = "\u001B[2;34m";
Ernesto Posse8a4f2962015-05-12 13:28:46 -040036 //static const char * ANSI_DIM_PURPLE = "\u001B[2;35m";
37 //static const char * ANSI_DIM_CYAN = "\u001B[2;36m";
38 //static const char * ANSI_BRIGHT_BLACK = "\u001B[1;30m";
Barry Maher5da2c532015-05-15 12:59:11 -040039 //-static const char * ANSI_BRIGHT_RED = "\u001B[1;31m";
Ernesto Posse8a4f2962015-05-12 13:28:46 -040040 //static const char * ANSI_BRIGHT_GREEN = "\u001B[1;32m";
41 //static const char * ANSI_BRIGHT_YELLOW = "\u001B[1;33m";
Barry Maher5da2c532015-05-15 12:59:11 -040042 //-static const char * ANSI_BRIGHT_BLUE = "\u001B[1;34m";
Ernesto Posse8a4f2962015-05-12 13:28:46 -040043 //static const char * ANSI_BRIGHT_PURPLE = "\u001B[1;35m";
44 //static const char * ANSI_BRIGHT_CYAN = "\u001B[1;36m";
45 //static const char * ANSI_WHITE = "\u001B[37m";
46
47 // To output BD type as string.
48 const char *debugMessageTypePrefix[BD_MAXPLUS1] = BD_PREFIX_STRING;
49
50 // ---- RUN-TIME ENABLE OF BD MESSAGES HERE ----
51 // Un-comment the lines that correspond to the types you want enabled.
52 long int debugEnableMessageType = 0
53// | (1 << BD_INJECT)
54// | (1 << BD_MSG)
55// | (1 << BD_SIGNAL)
56// | (1 << BD_SIGNALREF)
57// | (1 << BD_SIGNALINIT)
58// | (1 << BD_TIMER)
59// | (1 << BD_CONTROLLER)
60// | (1 << BD_NOTIFY)
61// | (1 << BD_SERIALIZE)
62// | (1 << BD_LOCK)
63 ;
64
65 // ---- RUN-TIME ENABLE OF BD MESSAGE COMPONENTS HERE ----
66 // Set to true to enable that part of the BD message output.
67 bool debugEnable = false; // Overall enable - if this is false, no debug output is produced regardless of all other settings.
68 bool debugEnableColor = true; // Enable color escape-sequences for output text.
69 bool debugEnableTypeName = true;
70 bool debugEnableTime = true;
71 bool debugEnableThreadId = false;
72 bool debugEnableFilename = false;
73 bool debugEnableLineNumber = false;
74 bool debugEnableMethod = false;
75 bool debugEnableUserMessage = true;
76
77 // Use a semaphore to serialize debug log messages.
78 class bdsem {
79 public:
80 bdsem( int value ) // Must explicitly set initial value.
81 {
82 if (sem_init(&sem, 0/*threads only*/, value) < 0)
83 {
84 FATAL_ERRNO("sem_init");
85 }
86 }
87 ~bdsem()
88 {
89 if (sem_destroy(&sem) < 0)
90 {
91 FATAL_ERRNO("sem_destroy");
92 }
93 }
94
95 // Wait forever for one to be available.
96 void Wait(void)
97 {
98 if (sem_wait(&sem) < 0)
99 {
100 FATAL_ERRNO("sem_wait");
101 }
102 }
103
104 // Give one back.
105 void Post(void)
106 {
107 if (sem_post(&sem) < 0)
108 {
109 FATAL_ERRNO("sem_wait");
110 }
111 }
112
113 private:
114 bdsem();
115
116 sem_t sem;
117 };
118
119 // Convenience class for serializing debug log output.
120 class bdguard {
121 public:
122 bdguard( bdsem * * m );
123 ~bdguard() { sem->Post(); }
124
125 private:
126 bdsem * sem;
127 };
128 bdguard::bdguard( bdsem * * m )
129 {
130 if (!(*m))
131 {
132 (*m) = new bdsem(1);
133 }
134 (*m)->Wait();
135 sem = (*m);
136 }
137
138 bdsem * bdprintflock;
139
140 // BD debug printf - called from BDEBUG macros.
141 void debugPrintf( int bdtype, const char * file, int line, const char * method, const char * fmt, ...)
142 {
143 static bool outputprefix = true;
144 static pthread_t lastthread = 0;
145
146 outputprefix |= (lastthread != pthread_self());
147 lastthread = pthread_self();
148
149 if (debugEnable && (bdtype < BD_MAXPLUS1) && (debugEnableMessageType & (1 << bdtype)))
150 {
151 va_list ap;
152 va_start(ap, fmt);
153 bdguard guard(&bdprintflock);
154 debugColourBrightBlue();
155 if (debugEnableTime && outputprefix)
156 {
157 struct timeval now;
158 gettimeofday(&now, NULL);
159 struct tm from_localtime;
160 const time_t seconds = now.tv_sec;
161 localtime_r( &seconds, &from_localtime );
162 char tmbuf[64];
163 size_t length = strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d:%H:%M:%S", &from_localtime);
164 snprintf(&tmbuf[length], sizeof(tmbuf)-length, ".%03ld", now.tv_usec/1000);
165 if (length <= 0)
166 {
167 strcpy(tmbuf, "?");
168 }
169 printf("%s:", tmbuf);
170 }
171 if (debugEnableTypeName && outputprefix)
172 {
173 printf("%s:", debugMessageTypePrefix[bdtype]);
174 }
175 if (debugEnableThreadId && outputprefix)
176 {
Barry Maher5da2c532015-05-15 12:59:11 -0400177#if 0
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400178 // Not universally available.
179 char name[80]; // TODO: remove magic #.
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400180 if (pthread_getname_np(pthread_self(), name, sizeof(name)) != 0)
181 strcpy(name, "?");
182 printf("%s:", name);
183#else
184 // Use this if pthread_getname_np/pthread_setname_np taken out.
185 printf("%ld:", pthread_self());
186#endif
187 }
188 if (debugEnableFilename && outputprefix)
189 {
190 printf("%s:", file);
191 }
192 if (debugEnableLineNumber && outputprefix)
193 {
194 printf("line %d:", line);
195 }
196 if (debugEnableMethod && outputprefix)
197 {
198 printf("%s:", method);
199 }
200 if (debugEnableUserMessage)
201 {
202 vprintf(fmt, ap);
203 }
204 size_t len;
205 if ((len = strlen(fmt)) > 0)
206 {
207 outputprefix = (fmt[len-1] == '\n');
208 }
209 va_end(ap);
210 debugColourReset();
211 fflush(stdout);
212 }
213 }
214
215 // See UMLRTMain.hh
216 long int debugGetEnabledTypes()
217 {
218 return debugEnableMessageType;
219 }
220
221 // See UMLRTMain.hh
222 void debugEnableSet( bool enabled )
223 {
224 debugEnable = enabled;
225 }
226
227 // See UMLRTMain.hh
228 void debugEnableColorSet( bool enabled )
229 {
230 debugEnableColor = enabled;
231 }
232
233 // See UMLRTMain.hh
234 bool debugEnableTypeMaskNameSet( const char * name, bool enable )
235 {
236 long int index = -1;
237 bool ok = true;
238
239 // Special name 'all'
240 if (!strcasecmp(name, "ALL"))
241 {
242 for (int i = 1; (i < BD_MAXPLUS1) && ok; ++i)
243 {
244 ok = debugEnableTypeMaskNameSet(debugMessageTypePrefix[i], enable);
245 }
246 }
247 else
248 {
249 for (int i = 0; (i < BD_MAXPLUS1) && (index == -1); ++i)
250 {
251 if (!strcasecmp(name, debugMessageTypePrefix[i]))
252 {
253 index = i;
254 }
255 }
256 if (index == -1)
257 {
258 printf("ERROR: debug-type '%s' not found.\n", name);
259 ok = false;
260 }
261 else if (enable)
262 {
263 debugEnableMessageType |= (1 << index);
264 }
265 else
266 {
267 debugEnableMessageType &= ~(1 << index);
268 }
269 }
270 return ok;
271 }
272
273
274 // See UMLRTMain.hh
275 bool debugEnableTypeMaskSpecSet( char * typeMaskSpec, bool enable )
276 {
277 bool ok = true;
278 bool oneset = false;
279 char * next;
280 char * str = typeMaskSpec;
281 while (ok)
282 {
283 // str non-NULL the first time, get the first token.
284 char * token = strtok_r(str, " ", &next);
285 // str set NULL, to use 'next' for subsequent calls.
286 str = NULL;
287 if (token == NULL)
288 {
289 break;
290 }
291 oneset = true;
292 // Got a debug-type name - enable or disable it.
293 ok = debugEnableTypeMaskNameSet(token, enable);
294 }
295 if (ok && oneset)
296 {
297 debugEnableSet(true);
298 }
299 return ok;
300 }
301
302 // See UMLRTMain.hh
303 void debugEnableTypeNameDisplaySet( bool enabled )
304 {
305 debugEnableTypeName = enabled;
306 if (enabled)
307 {
308 debugEnableSet(true);
309 }
310 }
311
312 // See UMLRTMain.hh
313 void debugEnableTimeDisplaySet( bool enabled )
314 {
315 debugEnableTime = enabled;
316 if (enabled)
317 {
318 debugEnableSet(true);
319 }
320 }
321
322 // See UMLRTMain.hh
323 void debugEnableThreadDisplaySet( bool enabled )
324 {
325 debugEnableThreadId = enabled;
326 if (enabled)
327 {
328 debugEnableSet(true);
329 }
330 }
331
332 // See UMLRTMain.hh
333 void debugEnableFilenameDisplaySet( bool enabled )
334 {
335 debugEnableFilename = enabled;
336 if (enabled)
337 {
338 debugEnableSet(true);
339 }
340 }
341
342 // See UMLRTMain.hh
343 void debugEnableLineNumberDisplaySet( bool enabled )
344 {
345 debugEnableLineNumber = enabled;
346 if (enabled)
347 {
348 debugEnableSet(true);
349 }
350 }
351
352 // See UMLRTMain.hh
353 void debugEnableMethodDisplaySet( bool enabled )
354 {
355 debugEnableMethod = enabled;
356 if (enabled)
357 {
358 debugEnableSet(true);
359 }
360 }
361
362 // See UMLRTMain.hh
363 void debugEnableUserMsgDisplaySet( bool enabled )
364 {
365 debugEnableUserMessage = enabled;
366 if (enabled)
367 {
368 debugEnableSet(true);
369 }
370 }
371
372 // See UMLRTMain.hh
373 bool debugTypeEnabled( long int type )
374 {
375 return ((debugEnableMessageType & (1 << type)) != 0);
376 }
377
378 // See UMLRTMain.hh
379 void debugLogData( long int type, uint8_t * data, size_t size)
380 {
381 if (base::debugTypeEnabled(type) && (size != 0))
382 {
383 int extra = size & 0x7;
384
385 for (size_t i = 0; i < ((size / 8) + (extra != 0 ? 1 : 0)); ++i)
386 {
387 char buf[(8*6) + 2];
388 buf[0] = '\0';
389 char * p = buf;
390 int count = 0;
391 for (size_t j = 0; (j < 8) && (((i*8) + j) < size); ++j, ++count)
392 {
393 p += snprintf(p, sizeof(buf)-(p-buf), "0x%02X ", data[(i*8) + j]);
394 }
395 for (size_t j = count; j < 8; ++j)
396 {
397 p += snprintf(p, sizeof(buf)-(p-buf), " ");
398 }
399 *(p++) = ' ';
400 for (size_t j = 0; (j < 8) && ((j + (i*8)) < size); ++j)
401 {
402 char c = data[(i*8) + j];
403 if ((c >= 0x20) && (c <= 0x7F))
404 {
405 *(p++) = c;
406 }
407 else
408 {
409 *(p++) = '.';
410 }
411 }
412 *p = '\0';
413 BDEBUG(type, "%s\n", buf);
414 }
415 }
416 }
417
418 // See UMLRTMain.hh
419 void debugOptionSummary()
420 {
421 debugColourBrightBlue();
422
423 printf("Overall debug log enable (option 'debug/D') : %s\n", debugEnable ? "enabled" : "disabled");
424 printf("Debug message types (option 'debugtype/T')\n");
425 for (int i = 1; i < BD_MAXPLUS1; ++i)
426 {
427 printf(" %13s : %s\n", debugMessageTypePrefix[i], ((debugEnableMessageType & (1 << i)) != 0) ? "enabled" : "disabled");
428 }
429 printf("Debug log message components displayed:\n");
430 printf(" time-stamp (option 'debugtime/S') : %s\n", debugEnableTime ? "displayed" : "suppressed" );
431 printf(" type name (option 'debugname/N') : %s\n", debugEnableTypeName ? "displayed" : "suppressed" );
432 printf(" thread-id (option 'debugthread/n') : %s\n", debugEnableThreadId ? "displayed" : "suppressed" );
433 printf(" file-name (option 'debugfile/F') : %s\n", debugEnableFilename ? "displayed" : "suppressed" );
434 printf(" line-number (option 'debugline/L') : %s\n", debugEnableLineNumber ? "displayed" : "suppressed" );
435 printf(" method name (option 'debugmethod/M') : %s\n", debugEnableMethod ? "displayed" : "suppressed" );
436 printf(" user message (option 'debugmsg/m') : %s\n", debugEnableUserMessage ? "displayed" : "suppressed" );
437
438 debugColourReset();
439 }
440
441 // See UMLRTMain.hh
442 void debugTypeSummary()
443 {
444 for (int i = 1; i < BD_MAXPLUS1; ++i)
445 {
446 printf("%s ", debugMessageTypePrefix[i]);
447 }
448 }
449
450 // See basedebug.hh
451 void debugColourReset()
452 {
453 if (debugEnableColor)
454 {
Barry Maher5da2c532015-05-15 12:59:11 -0400455 //printf("%s", ANSI_RESET);
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400456 }
457 }
458 void debugColourBrightBlue()
459 {
460 if (debugEnableColor)
461 {
Barry Maher5da2c532015-05-15 12:59:11 -0400462 //printf("%s", ANSI_BRIGHT_BLUE);
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400463 }
464 }
465 void debugColourBrightRed()
466 {
467 if (debugEnableColor)
468 {
Barry Maher5da2c532015-05-15 12:59:11 -0400469 //printf("%s", ANSI_BRIGHT_RED);
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400470 }
471 }
472 void debugColourDimBlue()
473 {
474 if (debugEnableColor)
475 {
Barry Maher5da2c532015-05-15 12:59:11 -0400476 //printf("%s", ANSI_DIM_BLUE);
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400477 }
478 }
479
480 // See basedebug.hh for documentation.
481 void swerr( const char * file, int line, const char * method, const char * fmt, ...)
482 {
483 if (debugEnable && (debugEnableMessageType & (1 << BD_SWERR)))
484 {
485 va_list ap;
486 va_start(ap, fmt);
487 bdguard guard(&bdprintflock);
488 debugColourBrightRed();
489 printf("SWERR:%s:%d:%s:%ld:", file, line, method, pthread_self());
490 vprintf(fmt, ap);
491 printf("\n");
492 va_end(ap);
493 debugColourReset();
494 }
495 }
496 // See basedebug.hh for documentation.
497 void swerrErrno( const char * file, int line, const char * method, int errno_, const char * api)
498 {
499 if (debugEnable && (debugEnableMessageType & (1 << BD_SWERR)))
500 {
501 bdguard guard(&bdprintflock);
502 debugColourBrightRed();
503 printf("SWERR:%s:%d:%s:%ld:%s:errno(%d):%s\n", file, line, method, pthread_self(), api, errno_, strerror(errno_));
504 debugColourReset();
505 }
506 }
507}