1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <direct/build.h>
32 
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <signal.h>
38 
39 #include <direct/clock.h>
40 #include <direct/debug.h>
41 #include <direct/list.h>
42 #include <direct/log.h>
43 #include <direct/thread.h>
44 #include <direct/trace.h>
45 #include <direct/util.h>
46 
47 
48 #if DIRECT_BUILD_TEXT
49 
50 #if DIRECT_BUILD_DEBUGS  /* Build with debug support? */
51 
52 typedef struct {
53      DirectLink  link;
54      char       *name;
55      bool        enabled;
56 } DebugDomainEntry;
57 
58 /**************************************************************************************************/
59 
60 static pthread_mutex_t  domains_lock = PTHREAD_MUTEX_INITIALIZER;
61 static unsigned int     domains_age  = 1;
62 static DirectLink      *domains      = NULL;
63 
64 /**************************************************************************************************/
65 
66 __attribute__((no_instrument_function))
67 static inline DebugDomainEntry *
lookup_domain(const char * name,bool sub)68 lookup_domain( const char *name, bool sub )
69 {
70      DebugDomainEntry *entry;
71 
72      direct_list_foreach (entry, domains) {
73           if (! strcasecmp( entry->name, name ))
74                return entry;
75      }
76 
77      /*
78       * If the domain being registered contains a slash, but didn't exactly match an entry
79       * in directfbrc, check to see if the domain is descended from an entry in directfbrc
80       * (e.g. 'ui/field/messages' matches 'ui' or 'ui/field')
81       */
82      if (sub && strchr(name, '/')) {
83           int passed_name_len = strlen( name );
84 
85           direct_list_foreach (entry, domains) {
86                int entry_len = strlen( entry->name );
87                if ((passed_name_len > entry_len) &&
88                    (name[entry_len] == '/') &&
89                    (! strncasecmp( entry->name, name, entry_len))) {
90                     return entry;
91                }
92           }
93      }
94 
95      return NULL;
96 }
97 
98 __attribute__((no_instrument_function))
99 static inline bool
check_domain(DirectDebugDomain * domain)100 check_domain( DirectDebugDomain *domain )
101 {
102      if (domain->age != domains_age) {
103           DebugDomainEntry *entry = lookup_domain( domain->name, true );
104 
105           domain->age = domains_age;
106 
107           if (entry) {
108                domain->registered = true;
109                domain->enabled    = entry->enabled;
110           }
111      }
112 
113      return domain->registered ? domain->enabled : direct_config->debug;
114 }
115 
116 #endif /* DIRECT_BUILD_DEBUGS */
117 
118 /**************************************************************************************************/
119 
120 void
direct_debug_config_domain(const char * name,bool enable)121 direct_debug_config_domain( const char *name, bool enable )
122 {
123 #if DIRECT_BUILD_DEBUGS  /* Build with debug support? */
124      DebugDomainEntry *entry;
125 
126      pthread_mutex_lock( &domains_lock );
127 
128      entry = lookup_domain( name, false );
129      if (!entry) {
130           entry = calloc( 1, sizeof(DebugDomainEntry) );
131           if (!entry) {
132                D_WARN( "out of memory" );
133                pthread_mutex_unlock( &domains_lock );
134                return;
135           }
136 
137           entry->name = strdup( name );
138 
139           direct_list_prepend( &domains, &entry->link );
140      }
141 
142      entry->enabled = enable;
143 
144      if (! ++domains_age)
145           domains_age++;
146 
147      pthread_mutex_unlock( &domains_lock );
148 #endif /* DIRECT_BUILD_DEBUGS */
149 }
150 
151 bool
direct_debug_check_domain(DirectDebugDomain * domain)152 direct_debug_check_domain( DirectDebugDomain *domain )
153 {
154 #if DIRECT_BUILD_DEBUGS  /* Build with debug support? */
155      bool enabled;
156 
157      pthread_mutex_lock( &domains_lock );
158 
159      enabled = check_domain( domain );
160 
161      pthread_mutex_unlock( &domains_lock );
162 
163      return enabled;
164 #else
165      return false;
166 #endif /* DIRECT_BUILD_DEBUGS */
167 }
168 
169 /**************************************************************************************************/
170 
171 __attribute__((no_instrument_function))
172 static inline void
debug_domain_vprintf(const char * name,int name_len,const char * format,va_list ap)173 debug_domain_vprintf( const char        *name,
174                       int                name_len,
175                       const char        *format,
176                       va_list            ap )
177 {
178      char        buf[512];
179      long long   millis = direct_clock_get_millis();
180      const char *thread = direct_thread_self_name();
181      int         indent = direct_trace_debug_indent() * 4;
182 
183      /* Prepare user message. */
184      vsnprintf( buf, sizeof(buf), format, ap );
185 
186      /* Fill up domain name column after the colon, prepending remaining space (excl. ': ') to indent. */
187      indent += (name_len < 20 ? 20 : 36) - name_len - 2;
188 
189      /* Print full message. */
190      direct_log_printf( NULL, "(-) [%-15s %3lld.%03lld] (%5d) %s: %*s%s", thread ? thread : "  NO NAME",
191                         millis / 1000LL, millis % 1000LL, direct_gettid(), name, indent, "", buf );
192 }
193 
194 #if DIRECT_BUILD_DEBUGS  /* Build with debug support? */
195 
196 __attribute__((no_instrument_function))
197 void
direct_debug(const char * format,...)198 direct_debug( const char *format, ... )
199 {
200      va_list ap;
201 
202      va_start( ap, format );
203 
204      debug_domain_vprintf( "- - ", 4, format, ap );
205 
206      va_end( ap );
207 }
208 
209 __attribute__((no_instrument_function))
210 void
direct_debug_at(DirectDebugDomain * domain,const char * format,...)211 direct_debug_at( DirectDebugDomain *domain,
212                  const char        *format, ... )
213 {
214      bool enabled;
215 
216      pthread_mutex_lock( &domains_lock );
217 
218      enabled = check_domain( domain );
219 
220      pthread_mutex_unlock( &domains_lock );
221 
222      if (enabled) {
223           va_list ap;
224 
225           va_start( ap, format );
226 
227           debug_domain_vprintf( domain->name, domain->name_len, format, ap );
228 
229           va_end( ap );
230      }
231 }
232 
233 #endif /* DIRECT_BUILD_DEBUGS */
234 
235 __attribute__((no_instrument_function))
236 void
direct_debug_at_always(DirectDebugDomain * domain,const char * format,...)237 direct_debug_at_always( DirectDebugDomain *domain,
238                         const char        *format, ... )
239 {
240      va_list ap;
241 
242      va_start( ap, format );
243 
244      debug_domain_vprintf( domain->name, domain->name_len, format, ap );
245 
246      va_end( ap );
247 }
248 
249 #if DIRECT_BUILD_DEBUGS  /* Build with debug support? */
250 
251 __attribute__((no_instrument_function))
252 void
direct_debug_enter(DirectDebugDomain * domain,const char * func,const char * file,int line,const char * format,...)253 direct_debug_enter( DirectDebugDomain *domain,
254                     const char *func,
255                     const char *file,
256                     int         line,
257                     const char *format, ... )
258 {
259      bool enabled;
260 
261      pthread_mutex_lock( &domains_lock );
262 
263      enabled = check_domain( domain );
264 
265      pthread_mutex_unlock( &domains_lock );
266 
267      if (enabled) {
268           int         len;
269           char        dom[48];
270           char        fmt[128];
271           char        buf[512];
272           long long   millis = direct_clock_get_millis();
273           const char *name   = direct_thread_self_name();
274           va_list     ap;
275 
276           va_start( ap, format );
277 
278           vsnprintf( buf, sizeof(buf), format, ap );
279 
280           va_end( ap );
281 
282 
283           len = snprintf( dom, sizeof(dom), "%s:", domain->name );
284 
285           if (len < 18)
286                len = 18;
287           else
288                len = 28;
289 
290           len += direct_trace_debug_indent() * 4;
291 
292           snprintf( fmt, sizeof(fmt), "(>) [%%-15s %%3lld.%%03lld] (%%5d) %%-%ds Entering %%s%%s [%%s:%%d]\n", len );
293 
294           direct_log_printf( NULL, fmt, name ? name : "  NO NAME  ",
295                              millis / 1000LL, millis % 1000LL, direct_gettid(), dom,
296 			     func, buf, file, line );
297      }
298 }
299 
300 __attribute__((no_instrument_function))
301 void
direct_debug_exit(DirectDebugDomain * domain,const char * func,const char * file,int line,const char * format,...)302 direct_debug_exit( DirectDebugDomain *domain,
303                    const char *func,
304                    const char *file,
305                    int         line,
306                    const char *format, ... )
307 {
308      bool enabled;
309 
310      pthread_mutex_lock( &domains_lock );
311 
312      enabled = check_domain( domain );
313 
314      pthread_mutex_unlock( &domains_lock );
315 
316      if (enabled) {
317           int         len;
318           char        dom[48];
319           char        fmt[128];
320           char        buf[512];
321           long long   millis = direct_clock_get_millis();
322           const char *name   = direct_thread_self_name();
323           va_list     ap;
324 
325           va_start( ap, format );
326 
327           vsnprintf( buf, sizeof(buf), format, ap );
328 
329           va_end( ap );
330 
331 
332           len = snprintf( dom, sizeof(dom), "%s:", domain->name );
333 
334           if (len < 18)
335                len = 18;
336           else
337                len = 28;
338 
339           len += direct_trace_debug_indent() * 4;
340 
341           snprintf( fmt, sizeof(fmt), "(<) [%%-15s %%3lld.%%03lld] (%%5d) %%-%ds Returning from %%s%%s [%%s:%%d]\n", len );
342 
343           direct_log_printf( NULL, fmt, name ? name : "  NO NAME  ",
344                              millis / 1000LL, millis % 1000LL, direct_gettid(), dom,
345 			     func, buf, file, line );
346      }
347 }
348 
349 __attribute__((no_instrument_function))
350 static void
trap(const char * domain)351 trap( const char *domain )
352 {
353      D_DEBUG( "Direct/%s: Raising SIGTRAP...\n", domain );
354 
355      kill( direct_gettid(), SIGTRAP );
356 
357      D_DEBUG( "Direct/%s: ...returned after signal to ourself, maybe blocked, calling %s()!\n", domain,
358 #ifdef __NR_exit_group
359             "exit_group" );
360 
361      syscall( __NR_exit_group, DR_BUG );
362 #else
363             "_exit" );
364 
365             _exit( DR_BUG );
366 #endif
367 }
368 
369 __attribute__((no_instrument_function))
370 void
direct_break(const char * func,const char * file,int line,const char * format,...)371 direct_break( const char *func,
372               const char *file,
373               int         line,
374               const char *format, ... )
375 {
376      char        buf[512];
377      long long   millis = direct_clock_get_millis();
378      const char *name   = direct_thread_self_name();
379 
380      va_list ap;
381 
382      va_start( ap, format );
383 
384      vsnprintf( buf, sizeof(buf), format, ap );
385 
386      va_end( ap );
387 
388      direct_log_printf( NULL,
389                         "(!) [%-15s %3lld.%03lld] (%5d) *** Break [%s] *** [%s:%d in %s()]\n",
390                         name ? name : "  NO NAME  ", millis / 1000LL, millis % 1000LL,
391                         direct_gettid(), buf, file, line, func );
392 
393      direct_trace_print_stack( NULL );
394 
395      if (direct_config->fatal_break)
396           trap( "Break" );
397 }
398 
399 __attribute__((no_instrument_function))
400 void
direct_assertion(const char * exp,const char * func,const char * file,int line)401 direct_assertion( const char *exp,
402                   const char *func,
403                   const char *file,
404                   int         line )
405 {
406      long long   millis = direct_clock_get_millis();
407      const char *name   = direct_thread_self_name();
408 
409      direct_log_printf( NULL,
410                         "(!) [%-15s %3lld.%03lld] (%5d) *** Assertion [%s] failed *** [%s:%d in %s()]\n",
411                         name ? name : "  NO NAME  ", millis / 1000LL, millis % 1000LL,
412                         direct_gettid(), exp, file, line, func );
413 
414      direct_trace_print_stack( NULL );
415 
416      if (direct_config->fatal >= DCFL_ASSERT)
417           trap( "Assertion" );
418 }
419 
420 __attribute__((no_instrument_function))
421 void
direct_assumption(const char * exp,const char * func,const char * file,int line)422 direct_assumption( const char *exp,
423                    const char *func,
424                    const char *file,
425                    int         line )
426 {
427      long long   millis = direct_clock_get_millis();
428      const char *name   = direct_thread_self_name();
429 
430      direct_log_printf( NULL,
431                         "(!) [%-15s %3lld.%03lld] (%5d) *** Assumption [%s] failed *** [%s:%d in %s()]\n",
432                         name ? name : "  NO NAME  ", millis / 1000LL, millis % 1000LL,
433                         direct_gettid(), exp, file, line, func );
434 
435      direct_trace_print_stack( NULL );
436 
437      if (direct_config->fatal >= DCFL_ASSUME)
438           trap( "Assumption" );
439 }
440 
441 #endif /* DIRECT_BUILD_DEBUGS */
442 
443 #else
444 
445 void
direct_debug_config_domain(const char * name,bool enable)446 direct_debug_config_domain( const char *name, bool enable )
447 {
448 }
449 
450 #endif /* DIRECT_BUILD_TEXT */
451 
452