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