SConstruct: further refinement of debug control at build time. A new DEBUG_MESSAGES...
[ffado.git] / libffado / src / debugmodule / debugmodule.cpp
blobd20654273e7da05d484f604e803e6472647cd096
1 /*
2 * Copyright (C) 2005-2008 by Daniel Wagner
3 * Copyright (C) 2005-2008 by Pieter Palmers
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) version 3 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "debugmodule.h"
27 #include <stdarg.h>
28 #include "libutil/ByteSwap.h"
29 #include "libutil/Time.h"
31 #include <iostream>
33 #include <time.h>
34 #include <string.h>
35 #include <errno.h>
37 #if DEBUG_BACKTRACE_SUPPORT
38 #include <execinfo.h>
39 #include <cxxabi.h>
40 #define GNU_SOURCE
41 #include <dlfcn.h>
42 #endif
44 #if DEBUG_USE_MESSAGE_BUFFER
45 #else
46 #ifdef DEBUG_MESSAGES
47 #warning Printing debug info without ringbuffer, not RT-safe!
48 #else
49 #error Printing debug info without ringbuffer, not RT-safe (not allowed for non-debug builds)!
50 #endif
51 #endif
53 using namespace std;
55 struct ColorEntry {
56 const char* preSequence;
57 const char* postSequence;
60 ColorEntry colorTable[] = {
61 { "", "" },
62 { "\033[31mFatal", "\033[0m" },
63 { "\033[31mError", "\033[0m" },
64 { "\033[31mWarning", "\033[0m" },
65 { "Debug", "" },
69 DebugModule::DebugModule( std::string name, debug_level_t level )
70 : m_name( name )
71 , m_level( level )
73 if ( !DebugModuleManager::instance()->registerModule( *this ) ) {
74 cerr << "Could not register DebugModule (" << name
75 << ") at DebugModuleManager"
76 << endl;
80 DebugModule::~DebugModule()
82 // if ( m_level >= eDL_VeryVerbose ) {
83 // cout << "Unregistering "
84 // << this->getName()
85 // << " at DebugModuleManager"
86 // << endl;
87 // }
89 if (m_manager && !m_manager->unregisterModule( *this ) ) {
90 cerr << "Could not unregister DebugModule at DebugModuleManager"
91 << endl;
96 void
97 DebugModule::printShort( debug_level_t level,
98 const char* format,
99 ... ) const
102 // bypass for performance
103 #if DEBUG_BACKLOG_SUPPORT
104 if (level > BACKLOG_MIN_LEVEL
105 && level > m_level) {
106 return;
108 #else
109 if ( level >m_level ) {
110 return;
112 #endif
114 const char *warning = "WARNING: message truncated!\n";
115 const int warning_size = 32;
116 va_list arg;
117 char msg[MB_BUFFERSIZE];
119 // format the message such that it remains together
120 int chars_written=0;
121 int retval=0;
123 va_start( arg, format );
124 retval = vsnprintf(msg+chars_written, MB_BUFFERSIZE, format, arg);
125 va_end( arg );
126 if (retval >= 0) { // ignore errors
127 chars_written += retval;
130 // output a warning if the message was truncated
131 if (chars_written == MB_BUFFERSIZE) {
132 snprintf(msg+MB_BUFFERSIZE-warning_size, warning_size, "%s", warning);
135 #if DEBUG_BACKLOG_SUPPORT
136 // print to backlog if necessary
137 if (level <= BACKLOG_MIN_LEVEL) {
138 DebugModuleManager::instance()->backlog_print( msg );
140 #endif
142 // print to stderr if necessary
143 if ( level <= m_level ) {
144 DebugModuleManager::instance()->print( msg );
148 void
149 DebugModule::print( debug_level_t level,
150 const char* file,
151 const char* function,
152 unsigned int line,
153 const char* format,
154 ... ) const
156 // bypass for performance
157 #if DEBUG_BACKLOG_SUPPORT
158 if (level > BACKLOG_MIN_LEVEL
159 && level > m_level) {
160 return;
162 #else
163 if ( level >m_level ) {
164 return;
166 #endif
168 const char *warning = "WARNING: message truncated!\n";
169 const int warning_size = 32;
171 va_list arg;
172 char msg[MB_BUFFERSIZE];
174 // remove the path info from the filename
175 const char *f = file;
176 const char *fname = file;
177 while((f=strstr(f, "/"))) {
178 f++; // move away from delimiter
179 fname=f;
182 // add a timing timestamp
183 struct timespec ts;
184 Util::SystemTimeSource::clockGettime(&ts);
185 uint64_t ts_usec=(uint64_t)(ts.tv_sec * 1000000LL + ts.tv_nsec / 1000LL);
187 // format the message such that it remains together
188 int chars_written=0;
189 int retval=0;
190 retval = snprintf(msg, MB_BUFFERSIZE, "%011"PRIu64": %s (%s)[%4u] %s: ",
191 ts_usec, getPreSequence( level ),
192 fname, line, function );
193 if (retval >= 0) chars_written += retval; // ignore errors
195 va_start( arg, format );
196 retval = vsnprintf( msg + chars_written,
197 MB_BUFFERSIZE - chars_written,
198 format, arg);
199 va_end( arg );
200 if (retval >= 0) chars_written += retval; // ignore errors
202 retval = snprintf( msg + chars_written,
203 MB_BUFFERSIZE - chars_written,
204 "%s", getPostSequence( level ) );
205 if (retval >= 0) chars_written += retval; // ignore errors
207 // output a warning if the message was truncated
208 if (chars_written == MB_BUFFERSIZE) {
209 snprintf(msg + MB_BUFFERSIZE - warning_size,
210 warning_size,
211 "%s", warning);
214 #if DEBUG_BACKLOG_SUPPORT
215 // print to backlog if necessary
216 if (level <= BACKLOG_MIN_LEVEL) {
217 DebugModuleManager::instance()->backlog_print( msg );
219 #endif
221 // print to stderr if necessary
222 if ( level <= m_level ) {
223 DebugModuleManager::instance()->print( msg );
227 const char*
228 DebugModule::getPreSequence( debug_level_t level ) const
230 if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
231 return colorTable[level].preSequence;
233 return colorTable[eDL_Normal].preSequence;
236 const char*
237 DebugModule::getPostSequence( debug_level_t level ) const
239 if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
240 return colorTable[level].postSequence;
242 return colorTable[eDL_Normal].postSequence;
245 //--------------------------------------
247 DebugModuleManager* DebugModuleManager::m_instance = 0;
249 DebugModuleManager::DebugModuleManager()
250 : mb_initialized(0)
251 #if DEBUG_USE_MESSAGE_BUFFER
252 , mb_inbuffer(0)
253 , mb_outbuffer(0)
254 , mb_overruns(0)
255 #endif
256 #if DEBUG_BACKTRACE_SUPPORT
257 , m_backtrace_buffer_nb_seen(0)
258 #endif
259 #if DEBUG_BACKLOG_SUPPORT
260 , bl_mb_inbuffer(0)
261 #endif
266 DebugModuleManager::~DebugModuleManager()
268 // cleaning up leftover modules
269 while (!m_debugModules.empty())
271 DebugModule *mod = m_debugModules.back();
272 unregisterModule(*mod);
275 if (!mb_initialized)
276 return;
278 #if DEBUG_USE_MESSAGE_BUFFER
279 pthread_mutex_lock(&mb_write_lock);
280 mb_initialized = 0;
281 sem_post(&mb_writes);
282 pthread_mutex_unlock(&mb_write_lock);
284 pthread_join(mb_writer_thread, NULL);
285 mb_flush();
286 #endif
288 #if DEBUG_BACKTRACE_SUPPORT
289 pthread_mutex_lock(&m_backtrace_lock);
290 // print a list of the symbols seen in a backtrace
291 fprintf(stderr, "Backtrace saw %d symbols:\n", m_backtrace_buffer_nb_seen);
292 char **strings = backtrace_symbols(m_backtrace_buffer_seen, m_backtrace_buffer_nb_seen);
293 if (strings == NULL) {
294 perror("backtrace_symbols");
295 } else {
296 char* outbuf = NULL;
297 size_t length;
298 int status;
299 Dl_info info;
300 for (int j = 0; j < m_backtrace_buffer_nb_seen; j++) {
301 if (dladdr(m_backtrace_buffer_seen[j], &info) != 0) {
302 outbuf = __cxxabiv1::__cxa_demangle(info.dli_sname, outbuf, &length, &status);
303 if(outbuf && status == 0) {
304 fprintf(stderr, " %p => %s\n",
305 m_backtrace_buffer_seen[j], outbuf);
306 free(outbuf);
307 outbuf = NULL;
308 } else {
309 fprintf(stderr, " %p => %s (demangle status: %d)\n",
310 m_backtrace_buffer_seen[j], strings[j], status);
312 } else {
313 fprintf(stderr, " %p => %s\n",
314 m_backtrace_buffer_seen[j], strings[j]);
317 free(strings);
319 pthread_mutex_unlock(&m_backtrace_lock);
320 #endif
322 #if DEBUG_USE_MESSAGE_BUFFER
323 if (mb_overruns)
324 fprintf(stderr, "WARNING: %d message buffer overruns!\n",
325 mb_overruns);
326 else
327 fprintf(stderr, "no message buffer overruns\n");
329 pthread_mutex_destroy(&mb_write_lock);
330 sem_destroy(&mb_writes);
331 #endif
333 #if DEBUG_BACKTRACE_SUPPORT
334 pthread_mutex_destroy(&m_backtrace_lock);
335 #endif
337 #if DEBUG_BACKLOG_SUPPORT
338 pthread_mutex_destroy(&bl_mb_write_lock);
339 #endif
343 bool
344 DebugModuleManager::init()
346 if (mb_initialized)
347 return true;
349 // if ( m_level >= eDL_VeryVerbose )
350 // cout << "DebugModuleManager init..." << endl;
352 #if DEBUG_BACKTRACE_SUPPORT
353 pthread_mutex_init(&m_backtrace_lock, NULL);
354 #endif
356 #if DEBUG_BACKLOG_SUPPORT
357 pthread_mutex_init(&bl_mb_write_lock, NULL);
358 #endif
360 #if DEBUG_USE_MESSAGE_BUFFER
361 pthread_mutex_init(&mb_flush_lock, NULL);
362 pthread_mutex_init(&mb_write_lock, NULL);
363 sem_init(&mb_writes, 0, 0);
365 mb_overruns = 0;
367 int res;
368 #if DEBUG_MESSAGE_BUFFER_REALTIME
369 /* Get the client thread to run as an RT-FIFO
370 scheduled thread of appropriate priority.
372 pthread_attr_t attributes;
373 struct sched_param rt_param;
374 pthread_attr_init(&attributes);
375 if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
376 fprintf(stderr, "Cannot request explicit scheduling for messagebuffer thread: %s (%d)\n", strerror(res), res);
377 return -1;
379 if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
380 fprintf(stderr, "Cannot request joinable thread creation for messagebuffer thread: %s (%d)\n", strerror(res), res);
381 return -1;
383 if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
384 fprintf(stderr, "Cannot set scheduling scope for messagebuffer thread: %s (%d)\n", strerror(res), res);
385 return -1;
388 if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO))) {
390 //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
391 fprintf(stderr, "Cannot set FIFO scheduling class for messagebuffer thread: %s (%d)\n", strerror(res), res);
392 return -1;
395 memset(&rt_param, 0, sizeof(rt_param));
396 rt_param.sched_priority = DEBUG_MESSAGE_BUFFER_REALTIME_PRIO;
398 if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
399 fprintf(stderr, "Cannot set scheduling priority for messagebuffer thread: %s (%d)\n", strerror(res), res);
400 return -1;
403 mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
404 if ((res = pthread_create(&mb_writer_thread, &attributes, mb_thread_func, (void *)this))) {
405 fprintf(stderr, "Cannot create RT messagebuffer thread: %s (%d)\n", strerror(res), res);
406 mb_initialized = 0;
409 if (res==EPERM && mb_initialized==0) {
410 fprintf(stderr, "Retrying messagebuffer thread without RT scheduling\n");
411 memset(&rt_param, 0, sizeof(rt_param));
412 if ((res=pthread_attr_setschedpolicy(&attributes, SCHED_OTHER)) ||
413 (res=pthread_attr_setschedparam(&attributes, &rt_param))) {
414 fprintf(stderr, "Cannot set standard scheduling for messagebuffer thread: %s (%d)\n", strerror(res), res);
415 } else {
416 mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
417 if ((res = pthread_create(&mb_writer_thread, &attributes, mb_thread_func, (void *)this))) {
418 fprintf(stderr, "Cannot create messagebuffer thread: %s (%d)\n", strerror(res), res);
419 mb_initialized = 0;
420 } else
421 fprintf(stderr, "Messagebuffer not realtime; consider enabling RT scheduling for user\n");
424 #else
425 mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
426 if ((res = pthread_create(&mb_writer_thread, NULL, &mb_thread_func, (void *)this))) {
427 fprintf(stderr, "Cannot create thread %d %s\n", res, strerror(res));
428 mb_initialized = 0;
430 #endif
431 #endif
433 return true;
436 DebugModuleManager*
437 DebugModuleManager::instance()
439 if ( !m_instance ) {
440 m_instance = new DebugModuleManager;
441 if ( !m_instance ) {
442 cerr << "DebugModuleManager::instance Failed to create "
443 << "DebugModuleManager" << endl;
445 if ( !m_instance->init() ) {
446 cerr << "DebugModuleManager::instance Failed to init "
447 << "DebugModuleManager" << endl;
450 return m_instance;
453 bool
454 DebugModuleManager::registerModule( DebugModule& debugModule )
456 bool already_present=false;
458 for ( DebugModuleVectorIterator it = m_debugModules.begin();
459 it != m_debugModules.end();
460 ++it )
462 if ( *it == &debugModule ) {
463 already_present=true;
464 return true;
468 if (already_present) {
469 cerr << "DebugModuleManager::registerModule: Module already registered: "
470 << "DebugModule (" << debugModule.getName() << ")" << endl;
471 } else {
472 m_debugModules.push_back( &debugModule );
473 if (debugModule.m_manager == NULL)
474 debugModule.m_manager = this;
476 return true;
479 bool
480 DebugModuleManager::unregisterModule( DebugModule& debugModule )
483 for ( DebugModuleVectorIterator it = m_debugModules.begin();
484 it != m_debugModules.end();
485 ++it )
487 if ( *it == &debugModule ) {
488 m_debugModules.erase( it );
489 if (debugModule.m_manager == this)
490 debugModule.m_manager = NULL;
491 return true;
495 cerr << "DebugModuleManager::unregisterModule: Could not unregister "
496 << "DebugModule (" << debugModule.getName() << ")" << endl;
497 return false;
500 bool
501 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
503 for ( DebugModuleVectorIterator it = m_debugModules.begin();
504 it != m_debugModules.end();
505 ++it )
507 if ( (*it)->getName() == name ) {
508 return (*it)->setLevel( level );
512 cerr << "setDebugLevel: Did not find DebugModule ("
513 << name << ")" << endl;
514 return false;
517 void
518 DebugModuleManager::flush()
520 #if DEBUG_USE_MESSAGE_BUFFER
521 mb_flush();
522 #else
523 fflush(stderr);
524 #endif
527 #if DEBUG_USE_MESSAGE_BUFFER
528 void
529 DebugModuleManager::mb_flush()
531 /* called WITHOUT the mb_write_lock */
533 /* the flush lock is to allow a flush from multiple threads
534 * this allows a code section that outputs a lot of debug messages
535 * and that can be blocked to flush the buffer itself such that it
536 * does not overflow.
538 DebugModuleManager *m=DebugModuleManager::instance();
539 pthread_mutex_lock(&m->mb_flush_lock);
540 while (mb_outbuffer != mb_inbuffer) {
541 fputs(mb_buffers[mb_outbuffer], stderr);
542 mb_outbuffer = MB_NEXT(mb_outbuffer);
544 fflush(stderr);
545 pthread_mutex_unlock(&m->mb_flush_lock);
548 void *
549 DebugModuleManager::mb_thread_func(void *arg)
552 DebugModuleManager *m=static_cast<DebugModuleManager *>(arg);
554 while (m->mb_initialized) {
555 sem_wait(&m->mb_writes);
556 m->mb_flush();
559 return NULL;
561 #endif
563 #if DEBUG_BACKLOG_SUPPORT
564 void
565 DebugModuleManager::showBackLog()
567 DebugModuleManager *m=DebugModuleManager::instance();
568 // locking the flush lock ensures that the backlog is
569 // printed as one entity
570 pthread_mutex_lock(&m->mb_flush_lock);
571 fprintf(stderr, "=====================================================\n");
572 fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
573 fprintf(stderr, "=====================================================\n");
575 for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
576 unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
577 fputs("BL: ", stderr);
578 fputs(bl_mb_buffers[idx], stderr);
580 fprintf(stderr, "BL: \n");
582 fprintf(stderr, "=====================================================\n");
583 fprintf(stderr, "* END OF BACKLOG PRINT\n");
584 fprintf(stderr, "=====================================================\n");
585 pthread_mutex_unlock(&m->mb_flush_lock);
588 void
589 DebugModuleManager::showBackLog(int nblines)
591 DebugModuleManager *m=DebugModuleManager::instance();
592 // locking the flush lock ensures that the backlog is
593 // printed as one entity
594 pthread_mutex_lock(&m->mb_flush_lock);
595 fprintf(stderr, "=====================================================\n");
596 fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
597 fprintf(stderr, "=====================================================\n");
599 int lines_to_skip = BACKLOG_MB_BUFFERS - nblines;
600 if (lines_to_skip < 0) lines_to_skip = 0;
601 for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
602 if (lines_to_skip-- < 0) {
603 unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
604 fputs("BL: ", stderr);
605 fputs(bl_mb_buffers[idx], stderr);
608 fprintf(stderr, "BL: \n");
610 fprintf(stderr, "=====================================================\n");
611 fprintf(stderr, "* END OF BACKLOG PRINT\n");
612 fprintf(stderr, "=====================================================\n");
613 pthread_mutex_unlock(&m->mb_flush_lock);
616 void
617 DebugModuleManager::backlog_print(const char *msg)
619 unsigned int ntries;
620 struct timespec wait = {0, DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NSEC};
621 // the backlog
622 ntries=DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NTRIES;
623 while (ntries) { // try a few times
624 if (pthread_mutex_trylock(&bl_mb_write_lock) == 0) {
625 strncpy(bl_mb_buffers[bl_mb_inbuffer], msg, MB_BUFFERSIZE);
626 bl_mb_inbuffer = BACKLOG_MB_NEXT(bl_mb_inbuffer);
627 pthread_mutex_unlock(&bl_mb_write_lock);
628 break;
629 } else {
630 nanosleep(&wait, NULL);
631 ntries--;
634 // just bail out should it have failed
636 #endif
638 void
639 DebugModuleManager::print(const char *msg)
641 #if DEBUG_USE_MESSAGE_BUFFER
642 unsigned int ntries;
643 struct timespec wait = {0,50000};
645 if (!mb_initialized) {
646 /* Unable to print message with realtime safety.
647 * Complain and print it anyway. */
648 fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
649 msg);
650 return;
653 ntries=6;
654 while (ntries) { // try a few times
655 if (pthread_mutex_trylock(&mb_write_lock) == 0) {
656 strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
657 mb_inbuffer = MB_NEXT(mb_inbuffer);
658 sem_post(&mb_writes);
659 pthread_mutex_unlock(&mb_write_lock);
660 break;
661 } else {
662 nanosleep(&wait, NULL);
663 ntries--;
666 if (ntries==0) { /* lock collision */
667 // atomic_add(&mb_overruns, 1);
668 // FIXME: atomicity
669 mb_overruns++; // skip the atomicness for now
671 #else
672 fprintf(stderr,msg);
673 #endif
676 #if DEBUG_BACKTRACE_SUPPORT
677 void
678 DebugModuleManager::printBacktrace(int len)
680 int nptrs;
681 int chars_written=0;
683 if(len > DEBUG_MAX_BACKTRACE_LENGTH) {
684 len = DEBUG_MAX_BACKTRACE_LENGTH;
687 pthread_mutex_lock(&m_backtrace_lock);
688 nptrs = backtrace(m_backtrace_buffer, len);
689 chars_written += snprintf(m_backtrace_strbuffer, MB_BUFFERSIZE-chars_written, "BACKTRACE (%d/%d): ", nptrs, len);
691 for (int j = 0; j < nptrs; j++) {
692 char name[64];
693 name[0]=0;
694 getFunctionName(m_backtrace_buffer[j], name, 64);
695 chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "%s\n", name);
697 chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "\n");
699 // make sure the string is terminated properly
700 m_backtrace_strbuffer[MB_BUFFERSIZE-2] = '\n';
701 m_backtrace_strbuffer[MB_BUFFERSIZE-1] = 0;
703 // save the pointers to the pointers-seen list such that we can
704 // dump their info later on
705 bool seen;
706 for (int i=0; i<nptrs; i++) {
707 seen = false;
708 int j;
709 for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) {
710 if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[i]) {
711 seen = true;
712 break;
715 if (!seen
716 && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) {
717 m_backtrace_buffer_seen[j] = m_backtrace_buffer[i];
718 m_backtrace_buffer_nb_seen++;
722 print(m_backtrace_strbuffer);
724 pthread_mutex_unlock(&m_backtrace_lock);
727 void *
728 DebugModuleManager::getBacktracePtr(int id)
730 int nptrs;
731 void *retval = NULL;
733 if(id >= DEBUG_MAX_BACKTRACE_LENGTH) {
734 return NULL;
737 pthread_mutex_lock(&m_backtrace_lock);
738 nptrs = backtrace(m_backtrace_buffer, id+1);
739 if(id >= nptrs) {
740 id = nptrs-1;
742 retval = m_backtrace_buffer[id];
743 // save the pointers to the pointers-seen list such that we can
744 // dump their info later on
745 bool seen = false;
746 int j;
747 for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) {
748 if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[id]) {
749 seen = true;
750 break;
753 if (!seen
754 && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) {
755 m_backtrace_buffer_seen[j] = m_backtrace_buffer[id];
756 m_backtrace_buffer_nb_seen++;
758 pthread_mutex_unlock(&m_backtrace_lock);
760 return retval;
763 void
764 DebugModuleManager::getFunctionName(void *ptr, char *buff, int len)
766 char* outbuf = NULL;
767 size_t length;
768 int status;
769 Dl_info info;
770 if (dladdr(ptr, &info) != 0) {
771 outbuf = abi::__cxa_demangle(info.dli_sname, outbuf, &length, &status);
772 if(outbuf && status == 0) {
773 if(len < (int)length) {
774 strncpy(buff, outbuf, len);
775 } else {
776 strncpy(buff, outbuf, length);
778 } else {
779 snprintf(buff, len, "%p (%s)", ptr, info.dli_sname);
781 } else {
782 snprintf(buff, len, "%p (I-ERR)", ptr);
784 if (outbuf) free(outbuf);
787 #endif
789 //----------------------------------------
791 unsigned char
792 toAscii( unsigned char c )
794 if ( ( c > 31 ) && ( c < 126) ) {
795 return c;
796 } else {
797 return '.';
801 /* converts a quadlet to a uchar * buffer
802 * not implemented optimally, but clear
804 void
805 quadlet2char( quadlet_t quadlet, unsigned char* buff )
807 *(buff) = (quadlet>>24)&0xFF;
808 *(buff+1) = (quadlet>>16)&0xFF;
809 *(buff+2) = (quadlet>> 8)&0xFF;
810 *(buff+3) = (quadlet) &0xFF;
813 void
814 hexDump( unsigned char *data_start, unsigned int length )
816 unsigned int i=0;
817 unsigned int byte_pos;
818 unsigned int bytes_left;
820 if ( length <= 0 ) {
821 return;
823 if ( length >= 7 ) {
824 for ( i = 0; i < (length-7); i += 8 ) {
825 printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
826 "- [%c%c%c%c%c%c%c%c]\n",
830 *(data_start+i+0),
831 *(data_start+i+1),
832 *(data_start+i+2),
833 *(data_start+i+3),
834 *(data_start+i+4),
835 *(data_start+i+5),
836 *(data_start+i+6),
837 *(data_start+i+7),
839 toAscii( *(data_start+i+0) ),
840 toAscii( *(data_start+i+1) ),
841 toAscii( *(data_start+i+2) ),
842 toAscii( *(data_start+i+3) ),
843 toAscii( *(data_start+i+4) ),
844 toAscii( *(data_start+i+5) ),
845 toAscii( *(data_start+i+6) ),
846 toAscii( *(data_start+i+7) )
850 byte_pos = i;
851 bytes_left = length - byte_pos;
853 printf( "%04X:" ,i );
854 for ( i = byte_pos; i < length; i += 1 ) {
855 printf( " %02X", *(data_start+i) );
857 for ( i=0; i < 8-bytes_left; i+=1 ) {
858 printf( " " );
861 printf( " - [" );
862 for ( i = byte_pos; i < length; i += 1) {
863 printf( "%c", toAscii(*(data_start+i)));
865 for ( i = 0; i < 8-bytes_left; i += 1) {
866 printf( " " );
869 printf( "]" );
870 printf( "\n" );
873 void
874 hexDumpQuadlets( quadlet_t *data, unsigned int length )
876 unsigned int i=0;
878 if ( length <= 0 ) {
879 return;
881 for (i = 0; i< length; i += 1) {
882 fprintf(stderr, "%02d %04X: %08X (%08X)"
883 "\n", i, i*4, data[i],CondSwapFromBus32(data[i]));