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

Revision 1999, 23.9 kB (checked in by adi, 12 years ago)

Fix segfault upon termination.

Kudos to David Henningsson for the patch.

Closes: #329

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