root/trunk/libffado/src/debugmodule/debugmodule.cpp

Revision 1254, 23.8 kB (checked in by ppalmers, 16 years ago)

split config.h into config/version/debug_config to allow for faster compilation (splits dependencies)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
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.
14  *
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.
19  *
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/>.
22  *
23  */
24
25 #include "debugmodule.h"
26
27 #include <stdarg.h>
28 #include "libutil/ByteSwap.h"
29
30 #include <iostream>
31
32 #include <time.h>
33 #include <string.h>
34
35 #if DEBUG_BACKTRACE_SUPPORT
36     #include <execinfo.h>
37     #include <cxxabi.h>
38     #define GNU_SOURCE
39     #include <dlfcn.h>
40 #endif
41
42 #if DEBUG_USE_MESSAGE_BUFFER
43 #else
44     #ifdef DEBUG
45         #warning Printing debug info without ringbuffer, not RT-safe!
46     #else
47         #error Printing debug info without ringbuffer, not RT-safe (not allowed for non-debug builds)!
48     #endif
49 #endif
50
51 using namespace std;
52
53 struct ColorEntry  {
54     const char* preSequence;
55     const char* postSequence;
56 };
57
58 ColorEntry colorTable[] = {
59     { "",           ""        },
60     { "\033[31mFatal",   "\033[0m" },
61     { "\033[31mError",   "\033[0m" },
62     { "\033[31mWarning", "\033[0m" },
63     { "Debug",           ""        },
64 };
65
66
67 DebugModule::DebugModule( std::string name,  debug_level_t level )
68     : m_name( name )
69     , m_level( level )
70 {
71     if ( !DebugModuleManager::instance()->registerModule( *this ) ) {
72         cerr << "Could not register DebugModule (" << name
73              << ") at DebugModuleManager"
74              << endl;
75     }
76 }
77
78 DebugModule::~DebugModule()
79 {
80 //     if ( m_level >= eDL_VeryVerbose ) {
81 //         cout << "Unregistering "
82 //              << this->getName()
83 //              << " at DebugModuleManager"
84 //              << endl;
85 //     }
86     if ( !DebugModuleManager::instance()->unregisterModule( *this ) ) {
87         cerr << "Could not unregister DebugModule at DebugModuleManager"
88              << endl;
89     }
90
91 }
92
93 void
94 DebugModule::printShort( debug_level_t level,
95                          const char* format,
96                          ... ) const
97 {
98
99     // bypass for performance
100 #if DEBUG_BACKLOG_SUPPORT
101     if (level > BACKLOG_MIN_LEVEL
102         && level > m_level) {
103         return;
104     }
105 #else
106     if ( level >m_level ) {
107         return;
108     }
109 #endif
110
111     const char *warning = "WARNING: message truncated!\n";
112     const int warning_size = 32;
113     va_list arg;
114     char msg[MB_BUFFERSIZE];
115
116     // format the message such that it remains together
117     int chars_written=0;
118     int retval=0;
119
120     va_start( arg, format );
121     retval = vsnprintf(msg+chars_written, MB_BUFFERSIZE, format, arg);
122     va_end( arg );
123     if (retval >= 0) {  // ignore errors
124         chars_written += retval;
125     }
126
127     // output a warning if the message was truncated
128     if (chars_written == MB_BUFFERSIZE) {
129         snprintf(msg+MB_BUFFERSIZE-warning_size, warning_size, "%s", warning);
130     }
131
132 #if DEBUG_BACKLOG_SUPPORT
133     // print to backlog if necessary
134     if (level <= BACKLOG_MIN_LEVEL) {
135         DebugModuleManager::instance()->backlog_print( msg );
136     }
137 #endif
138
139     // print to stderr if necessary
140     if ( level <= m_level ) {
141         DebugModuleManager::instance()->print( msg );
142     }
143 }
144
145 void
146 DebugModule::print( debug_level_t level,
147                     const char*   file,
148                     const char*   function,
149                     unsigned int  line,
150                     const char*   format,
151                     ... ) const
152 {
153     // bypass for performance
154 #if DEBUG_BACKLOG_SUPPORT
155     if (level > BACKLOG_MIN_LEVEL
156         && level > m_level) {
157         return;
158     }
159 #else
160     if ( level >m_level ) {
161         return;
162     }
163 #endif
164
165     const char *warning = "WARNING: message truncated!\n";
166     const int warning_size = 32;
167
168     va_list arg;
169     char msg[MB_BUFFERSIZE];
170
171     // remove the path info from the filename
172     const char *f = file;
173     const char *fname = file;
174     while((f=strstr(f, "/"))) {
175         f++; // move away from delimiter
176         fname=f;
177     }
178
179     // add a timing timestamp
180     struct timespec ts;
181     clock_gettime(CLOCK_MONOTONIC, &ts);
182     uint64_t ts_usec=(uint64_t)(ts.tv_sec * 1000000LL + ts.tv_nsec / 1000LL);
183
184     // format the message such that it remains together
185     int chars_written=0;
186     int retval=0;
187     retval = snprintf(msg, MB_BUFFERSIZE, "%011llu: %s (%s)[%4d] %s: ",
188                       ts_usec, getPreSequence( level ),
189                       fname,  line,  function );
190     if (retval >= 0) chars_written += retval; // ignore errors
191
192     va_start( arg, format );
193     retval = vsnprintf( msg + chars_written,
194                         MB_BUFFERSIZE - chars_written,
195                         format, arg);
196     va_end( arg );
197     if (retval >= 0) chars_written += retval; // ignore errors
198
199     retval = snprintf( msg + chars_written,
200                        MB_BUFFERSIZE - chars_written,
201                        "%s", getPostSequence( level ) );
202     if (retval >= 0) chars_written += retval; // ignore errors
203
204     // output a warning if the message was truncated
205     if (chars_written == MB_BUFFERSIZE) {
206         snprintf(msg + MB_BUFFERSIZE - warning_size,
207                  warning_size,
208                  "%s", warning);
209     }
210
211 #if DEBUG_BACKLOG_SUPPORT
212     // print to backlog if necessary
213     if (level <= BACKLOG_MIN_LEVEL) {
214         DebugModuleManager::instance()->backlog_print( msg );
215     }
216 #endif
217
218     // print to stderr if necessary
219     if ( level <= m_level ) {
220         DebugModuleManager::instance()->print( msg );
221     }
222 }
223
224 const char*
225 DebugModule::getPreSequence( debug_level_t level ) const
226 {
227     if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
228         return colorTable[level].preSequence;
229     }
230     return colorTable[eDL_Normal].preSequence;
231 }
232
233 const char*
234 DebugModule::getPostSequence( debug_level_t level ) const
235 {
236     if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
237         return colorTable[level].postSequence;
238     }
239     return colorTable[eDL_Normal].postSequence;
240 }
241
242 //--------------------------------------
243
244 DebugModuleManager* DebugModuleManager::m_instance = 0;
245
246 DebugModuleManager::DebugModuleManager()
247     : mb_initialized(0)
248 #if DEBUG_USE_MESSAGE_BUFFER
249     , mb_inbuffer(0)
250     , mb_outbuffer(0)
251     , mb_overruns(0)
252 #endif
253 #if DEBUG_BACKTRACE_SUPPORT
254     , m_backtrace_buffer_nb_seen(0)
255 #endif
256 #if DEBUG_BACKLOG_SUPPORT
257     , bl_mb_inbuffer(0)
258 #endif
259 {
260
261 }
262
263 DebugModuleManager::~DebugModuleManager()
264 {
265     // cleanin up leftover modules
266     for ( DebugModuleVectorIterator it = m_debugModules.begin();
267           it != m_debugModules.end();
268           ++it )
269     {
270         fprintf(stderr,"Cleaning up leftover debug module: %s\n",(*it)->getName().c_str());
271         m_debugModules.erase( it );
272         delete *it;
273     }
274
275     if (!mb_initialized)
276         return;
277
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);
283
284     pthread_join(mb_writer_thread, NULL);
285     mb_flush();
286 #endif
287
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);
311                 }
312             } else {
313                 fprintf(stderr, " %p => %s\n",
314                         m_backtrace_buffer_seen[j], strings[j]);
315             }
316         }
317         free(strings);
318     }
319     pthread_mutex_unlock(&m_backtrace_lock);
320 #endif
321
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");
328
329     pthread_mutex_destroy(&mb_write_lock);
330     sem_destroy(&mb_writes);
331 #endif
332
333 #if DEBUG_BACKTRACE_SUPPORT
334     pthread_mutex_destroy(&m_backtrace_lock);
335 #endif
336
337 #if DEBUG_BACKLOG_SUPPORT
338     pthread_mutex_destroy(&bl_mb_write_lock);
339 #endif
340
341 }
342
343 bool
344 DebugModuleManager::init()
345 {
346     if (mb_initialized)
347         return true;
348
349         // if ( m_level >= eDL_VeryVerbose )
350         //         cout << "DebugModuleManager init..." << endl;
351
352 #if DEBUG_BACKTRACE_SUPPORT
353     pthread_mutex_init(&m_backtrace_lock, NULL);
354 #endif
355
356 #if DEBUG_BACKLOG_SUPPORT
357     pthread_mutex_init(&bl_mb_write_lock, NULL);
358 #endif
359
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);
364
365     mb_overruns = 0;
366
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.
371     */
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 RT thread  %d %s\n", res, strerror(res));
377         return -1;
378     }
379     if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
380         fprintf(stderr, "Cannot request joinable thread creation for RT thread  %d %s\n", res, strerror(res));
381         return -1;
382     }
383     if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
384         fprintf(stderr, "Cannot set scheduling scope for RT thread %d %s\n", res, strerror(res));
385         return -1;
386     }
387
388     if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO))) {
389
390     //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
391         fprintf(stderr, "Cannot set FIFO scheduling class for RT thread  %d %s\n", res, strerror(res));
392         return -1;
393     }
394
395     memset(&rt_param, 0, sizeof(rt_param));
396     rt_param.sched_priority = DEBUG_MESSAGE_BUFFER_REALTIME_PRIO;
397
398     if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
399         fprintf(stderr, "Cannot set scheduling priority for RT thread %d %s\n", res, strerror(res));
400         return -1;
401     }
402
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 thread %d %s\n", res, strerror(res));
406         mb_initialized = 0;
407     }
408     #else
409     mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
410     if ((res = pthread_create(&mb_writer_thread, NULL, &mb_thread_func, (void *)this))) {
411         fprintf(stderr, "Cannot create thread %d %s\n", res, strerror(res));
412         mb_initialized = 0;
413     }
414     #endif
415 #endif
416
417     return true;
418 }
419
420 DebugModuleManager*
421 DebugModuleManager::instance()
422 {
423     if ( !m_instance ) {
424         m_instance = new DebugModuleManager;
425         if ( !m_instance ) {
426             cerr << "DebugModuleManager::instance Failed to create "
427                  << "DebugModuleManager" << endl;
428         }
429         if ( !m_instance->init() ) {
430             cerr << "DebugModuleManager::instance Failed to init "
431                  << "DebugModuleManager" << endl;
432         }
433     }
434     return m_instance;
435 }
436
437 bool
438 DebugModuleManager::registerModule( DebugModule& debugModule )
439 {
440     bool already_present=false;
441
442     for ( DebugModuleVectorIterator it = m_debugModules.begin();
443           it != m_debugModules.end();
444           ++it )
445     {
446         if ( *it == &debugModule ) {
447             already_present=true;
448             return true;
449         }
450     }
451
452     if (already_present) {
453         cerr << "DebugModuleManager::registerModule: Module already registered: "
454             << "DebugModule (" << debugModule.getName() << ")" << endl;
455     } else {
456         m_debugModules.push_back( &debugModule );
457     }
458     return true;
459 }
460
461 bool
462 DebugModuleManager::unregisterModule( DebugModule& debugModule )
463 {
464
465     for ( DebugModuleVectorIterator it = m_debugModules.begin();
466           it != m_debugModules.end();
467           ++it )
468     {
469         if ( *it == &debugModule ) {
470             m_debugModules.erase( it );
471             return true;
472         }
473     }
474
475     cerr << "DebugModuleManager::unregisterModule: Could not unregister "
476          << "DebugModule (" << debugModule.getName() << ")" << endl;
477     return false;
478 }
479
480 bool
481 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
482 {
483     for ( DebugModuleVectorIterator it = m_debugModules.begin();
484           it != m_debugModules.end();
485           ++it )
486     {
487         if ( (*it)->getName() == name ) {
488             return (*it)->setLevel( level );
489         }
490     }
491
492     cerr << "setDebugLevel: Did not find DebugModule ("
493          << name << ")" << endl;
494     return false;
495 }
496
497 void
498 DebugModuleManager::flush()
499 {
500 #if DEBUG_USE_MESSAGE_BUFFER
501     mb_flush();
502 #else
503     fflush(stderr);
504 #endif
505 }
506
507 #if DEBUG_USE_MESSAGE_BUFFER
508 void
509 DebugModuleManager::mb_flush()
510 {
511     /* called WITHOUT the mb_write_lock */
512    
513     /* the flush lock is to allow a flush from multiple threads
514      * this allows a code section that outputs a lot of debug messages
515      * and that can be blocked to flush the buffer itself such that it
516      * does not overflow.
517      */
518     DebugModuleManager *m=DebugModuleManager::instance();
519     pthread_mutex_lock(&m->mb_flush_lock);
520     while (mb_outbuffer != mb_inbuffer) {
521         fputs(mb_buffers[mb_outbuffer], stderr);
522         mb_outbuffer = MB_NEXT(mb_outbuffer);
523     }
524     fflush(stderr);
525     pthread_mutex_unlock(&m->mb_flush_lock);
526 }
527
528 void *
529 DebugModuleManager::mb_thread_func(void *arg)
530 {
531
532     DebugModuleManager *m=static_cast<DebugModuleManager *>(arg);
533
534     while (m->mb_initialized) {
535         sem_wait(&m->mb_writes);
536         m->mb_flush();
537     }
538
539     return NULL;
540 }
541 #endif
542
543 #if DEBUG_BACKLOG_SUPPORT
544 void
545 DebugModuleManager::showBackLog()
546 {
547      DebugModuleManager *m=DebugModuleManager::instance();
548     // locking the flush lock ensures that the backlog is
549     // printed as one entity
550     pthread_mutex_lock(&m->mb_flush_lock);
551     fprintf(stderr, "=====================================================\n");
552     fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
553     fprintf(stderr, "=====================================================\n");
554
555     for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
556         unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
557         fputs("BL: ", stderr);
558         fputs(bl_mb_buffers[idx], stderr);
559     }
560     fprintf(stderr, "BL: \n");
561
562     fprintf(stderr, "=====================================================\n");
563     fprintf(stderr, "* END OF BACKLOG PRINT\n");
564     fprintf(stderr, "=====================================================\n");
565     pthread_mutex_unlock(&m->mb_flush_lock);
566 }
567
568 void
569 DebugModuleManager::showBackLog(int nblines)
570 {
571      DebugModuleManager *m=DebugModuleManager::instance();
572     // locking the flush lock ensures that the backlog is
573     // printed as one entity
574     pthread_mutex_lock(&m->mb_flush_lock);
575     fprintf(stderr, "=====================================================\n");
576     fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
577     fprintf(stderr, "=====================================================\n");
578
579     int lines_to_skip = BACKLOG_MB_BUFFERS - nblines;
580     if (lines_to_skip < 0) lines_to_skip = 0;
581     for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
582         if (lines_to_skip-- < 0) {
583             unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
584             fputs("BL: ", stderr);
585             fputs(bl_mb_buffers[idx], stderr);
586         }
587     }
588     fprintf(stderr, "BL: \n");
589
590     fprintf(stderr, "=====================================================\n");
591     fprintf(stderr, "* END OF BACKLOG PRINT\n");
592     fprintf(stderr, "=====================================================\n");
593     pthread_mutex_unlock(&m->mb_flush_lock);
594 }
595
596 void
597 DebugModuleManager::backlog_print(const char *msg)
598 {
599     unsigned int ntries;
600     struct timespec wait = {0, DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NSEC};
601     // the backlog
602     ntries=DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NTRIES;
603     while (ntries) { // try a few times
604         if (pthread_mutex_trylock(&bl_mb_write_lock) == 0) {
605             strncpy(bl_mb_buffers[bl_mb_inbuffer], msg, MB_BUFFERSIZE);
606             bl_mb_inbuffer = BACKLOG_MB_NEXT(bl_mb_inbuffer);
607             pthread_mutex_unlock(&bl_mb_write_lock);
608             break;
609         } else {
610             nanosleep(&wait, NULL);
611             ntries--;
612         }
613     }
614     // just bail out should it have failed
615 }
616 #endif
617
618 void
619 DebugModuleManager::print(const char *msg)
620 {
621 #if DEBUG_USE_MESSAGE_BUFFER
622     unsigned int ntries;
623     struct timespec wait = {0,50000};
624
625     if (!mb_initialized) {
626         /* Unable to print message with realtime safety.
627          * Complain and print it anyway. */
628         fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
629             msg);
630         return;
631     }
632
633     ntries=6;
634     while (ntries) { // try a few times
635         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
636             strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
637             mb_inbuffer = MB_NEXT(mb_inbuffer);
638             sem_post(&mb_writes);
639             pthread_mutex_unlock(&mb_write_lock);
640             break;
641         } else {
642             nanosleep(&wait, NULL);
643             ntries--;
644         }
645     }
646     if (ntries==0) {  /* lock collision */
647         //         atomic_add(&mb_overruns, 1);
648         // FIXME: atomicity
649         mb_overruns++; // skip the atomicness for now
650     }
651 #else
652     fprintf(stderr,msg);
653 #endif
654 }
655
656 #if DEBUG_BACKTRACE_SUPPORT
657 void
658 DebugModuleManager::printBacktrace(int len)
659 {
660     int nptrs;
661     int chars_written=0;
662
663     if(len > DEBUG_MAX_BACKTRACE_LENGTH) {
664         len = DEBUG_MAX_BACKTRACE_LENGTH;
665     }
666
667     pthread_mutex_lock(&m_backtrace_lock);
668     nptrs = backtrace(m_backtrace_buffer, len);
669     chars_written += snprintf(m_backtrace_strbuffer, MB_BUFFERSIZE-chars_written, "BACKTRACE (%d/%d): ", nptrs, len);
670
671     for (int j = 0; j < nptrs; j++) {
672         char name[64];
673         name[0]=0;
674         getFunctionName(m_backtrace_buffer[j], name, 64);
675         chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "%s ", name);
676     }
677     chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "\n");
678
679     // make sure the string is terminated properly
680     m_backtrace_strbuffer[MB_BUFFERSIZE-2] = '\n';
681     m_backtrace_strbuffer[MB_BUFFERSIZE-1] = 0;
682    
683     // save the pointers to the pointers-seen list such that we can
684     // dump their info later on
685     bool seen;
686     for (int i=0; i<nptrs; i++) {
687         seen = false;
688         int j;
689         for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) {
690             if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[i]) {
691                 seen = true;
692                 break;
693             }
694         }
695         if (!seen
696            && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) {
697             m_backtrace_buffer_seen[j] = m_backtrace_buffer[i];
698             m_backtrace_buffer_nb_seen++;
699         }
700     }
701
702     print(m_backtrace_strbuffer);
703
704     pthread_mutex_unlock(&m_backtrace_lock);
705 }
706
707 void *
708 DebugModuleManager::getBacktracePtr(int id)
709 {
710     int nptrs;
711     void *retval = NULL;
712
713     if(id >= DEBUG_MAX_BACKTRACE_LENGTH) {
714         return NULL;
715     }
716
717     pthread_mutex_lock(&m_backtrace_lock);
718     nptrs = backtrace(m_backtrace_buffer, id+1);
719     if(id >= nptrs) {
720         id = nptrs-1;
721     }
722     retval = m_backtrace_buffer[id];
723     // save the pointers to the pointers-seen list such that we can
724     // dump their info later on
725     bool seen = false;
726     int j;
727     for (j=0; j<m_backtrace_buffer_nb_seen && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) {
728         if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[id]) {
729             seen = true;
730             break;
731         }
732     }
733     if (!seen
734        && j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN) {
735         m_backtrace_buffer_seen[j] = m_backtrace_buffer[id];
736         m_backtrace_buffer_nb_seen++;
737     }
738     pthread_mutex_unlock(&m_backtrace_lock);
739
740     return retval;
741 }
742
743 void
744 DebugModuleManager::getFunctionName(void *ptr, char *buff, int len)
745 {
746     char* outbuf = NULL;
747     size_t length;
748     int status;
749     Dl_info info;
750     if (dladdr(ptr, &info) != 0) {
751         outbuf = abi::__cxa_demangle(info.dli_sname, outbuf, &length, &status);
752         if(outbuf && status == 0) {
753             if(len < (int)length) {
754                 strncpy(buff, outbuf, len);
755             } else {
756                 strncpy(buff, outbuf, length);
757             }
758         } else {
759             snprintf(buff, len, "%p (%s)", ptr, info.dli_sname);
760         }
761     } else {
762         snprintf(buff, len, "%p (I-ERR)", ptr);
763     }
764     if (outbuf) free(outbuf);
765 }
766
767 #endif
768
769 //----------------------------------------
770
771 unsigned char
772 toAscii( unsigned char c )
773 {
774     if ( ( c > 31 ) && ( c < 126) ) {
775         return c;
776     } else {
777         return '.';
778     }
779 }
780
781 /* converts a quadlet to a uchar * buffer
782  * not implemented optimally, but clear
783  */
784 void
785 quadlet2char( quadlet_t quadlet, unsigned char* buff )
786 {
787     *(buff)   = (quadlet>>24)&0xFF;
788     *(buff+1) = (quadlet>>16)&0xFF;
789     *(buff+2) = (quadlet>> 8)&0xFF;
790     *(buff+3) = (quadlet)    &0xFF;
791 }
792
793 void
794 hexDump( unsigned char *data_start, unsigned int length )
795 {
796     unsigned int i=0;
797     unsigned int byte_pos;
798     unsigned int bytes_left;
799
800     if ( length <= 0 ) {
801         return;
802     }
803     if ( length >= 7 ) {
804         for ( i = 0; i < (length-7); i += 8 ) {
805             printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
806                     "- [%c%c%c%c%c%c%c%c]\n",
807
808                     i,
809
810                     *(data_start+i+0),
811                     *(data_start+i+1),
812                     *(data_start+i+2),
813                     *(data_start+i+3),
814                     *(data_start+i+4),
815                     *(data_start+i+5),
816                     *(data_start+i+6),
817                     *(data_start+i+7),
818
819                     toAscii( *(data_start+i+0) ),
820                     toAscii( *(data_start+i+1) ),
821                     toAscii( *(data_start+i+2) ),
822                     toAscii( *(data_start+i+3) ),
823                     toAscii( *(data_start+i+4) ),
824                     toAscii( *(data_start+i+5) ),
825                     toAscii( *(data_start+i+6) ),
826                     toAscii( *(data_start+i+7) )
827                 );
828         }
829     }
830     byte_pos = i;
831     bytes_left = length - byte_pos;
832
833     printf( "%04X:" ,i );
834     for ( i = byte_pos; i < length; i += 1 ) {
835         printf( " %02X", *(data_start+i) );
836     }
837     for ( i=0; i < 8-bytes_left; i+=1 ) {
838         printf( "   " );
839     }
840
841     printf( " - [" );
842     for ( i = byte_pos; i < length; i += 1) {
843         printf( "%c", toAscii(*(data_start+i)));
844     }
845     for ( i = 0; i < 8-bytes_left; i += 1) {
846         printf( " " );
847     }
848
849     printf( "]" );
850     printf( "\n" );
851 }
852
853 void
854 hexDumpQuadlets( quadlet_t *data, unsigned int length )
855 {
856     unsigned int i=0;
857
858     if ( length <= 0 ) {
859         return;
860     }
861     for (i = 0; i< length; i += 1) {
862         printf( "%02d %04X: %08X (%08X)"
863                 "\n", i, i*4, data[i],CondSwapFromBus32(data[i]));
864     }
865 }
866
867
Note: See TracBrowser for help on using the browser.